问题描述
我有一个 JSON 文件,我正在尝试使用 XML
注释方法将其转换为 JAXB
。现在一切正常,我可以将 JSON
转换为 XML
。现在我正在尝试稍微重构代码,以便我的类看起来干净。因此,我试图删除我的 class
中存在的方法并将其设为 JAXB XMLAdapter
,以便其他类可以重用它。
基本上我想将 XMLSupport
方法从 CarInfo
类移动到 XMLAdapter
。当我将它们移动到 CarInfo
时,我不确定如何填充 XMLAdapter
对象。
以下是我的 JSON
文件(为了简单起见已对其进行了修改):
{
"brand": "Ferari","build": "Italy","engine": "Mercedes","year": "2021"
}
以下是我希望 XML
提供的 JAXB
:(注意 carInfo
中不存在的 JSON
标记,但我需要在 XML
匹配标准 XSD
)
<?xml version="1.0"?>
<Car>
<brand>Ferari</brand>
<build>Italy</build>
<carinfo>
<engine>Mercedes</engine>
<year>2021</year>
</carinfo>
</Car>
以下是我拥有的类:(与 JSON 元素匹配的 Car
类)
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlTransient
@XmlSeeAlso({MyCar.class});
public class Car{
private String brand;
private String build;
@XmlTransient
private String engine;
@XmlTransient
private String year;
//Getter,Setters and other consturctiores ommited
}
以下是通过添加 MYCar
标记构建 XML
的 carInfo
类:
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlRootElement(name = "Car")
@XmlType(name = "Car",propOrder = {"brand","build","carInfo"})
public class MyCar extends Car{
@XmlElement(name="carInfo")
private CarInfo carInfo;
public MyCar xmlSupport() {
if(carInfo == null){
carInfo = new Carinfo();
}
carInfo.setEngine(getEngine);
carInfo.setYear(getYear());
return this;
}
}
以下是我的 CarInfo
类,它充当围绕 additional
类构建 MyCar
标签的助手:
@XmlAccessorType(XmlAccesstype.FIELD)
@XmlType(propOrder = {"engine","year"})
public class Carinfo{
private String engine;
private String year;
//Getter,Setters and other consturctiores ommited
}
以下是我的 Main
类,它通过使用 XML
JAXBCOntext
public class Main{
public static void main(String[] args){
JAXBContext context = JAXBContext.newInstance(MyCar.class);
Marshaller mar = context.createMarshaller();
mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,Boolean.TRUE);
mar.marshal((MyCar).xmlSupport(),System.out);
System.out.println("-----------------");
}
}
现在回到我的主要问题:
正如我们从 MyCar
类中看到的,我有 XMLSupport
方法,它实际上填充了 CarInfo
对象,然后使用该方法创建了 XML
。有什么办法可以将其移至 XMLAdapter
?
我尝试创建 XMLAdapter
,但不确定如何从适配器填充 CarInfo
对象:
public class MyCar extends Car{
@XmlElement(name="carInfo")
@XmlJavaTypeAdapter(ExtensionAdapter.class)
@XmlElement(name = "carInfo")
private CarInfo carInfo;
}
以下是我尝试过的 Adapter
课程:
public class ExtensionAdapter extends XmlAdapter
@Override
public CarInfo unmarshal(CarInfo valueType) throws Exception {
System.out.println("UN-MARSHALLING");
return null;
}
@Override
public CarInfo marshal(CarInfo boundType) throws Exception {
System.out.println("MARSHALLING");
System.out.println(boundType);
//I get boundType as NULL so I am not sure how to convert the xmlSupport Method to Adapter so I can use this adapter with multiple class
return null;
}
}
解决方法
你不需要任何适配器,你只需要一个定义良好的 POJO。
诀窍是使用 getter 和 setter,而不是字段访问,所以我们可以进行委托,然后使用 @JsonIgnore
和 @XmlTransient
来控制哪些 getter/setter 方法是用于 JSON 与 XML。
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@XmlRootElement(name = "Car")
@XmlType(propOrder = { "brand","build","carinfo" })
@JsonPropertyOrder({ "brand","engine","year" })
public final class Car {
@XmlType(propOrder = { "engine","year" })
public static final class Info {
private String engine;
private String year;
public String getEngine() {
return this.engine;
}
public void setEngine(String engine) {
this.engine = engine;
}
public String getYear() {
return this.year;
}
public void setYear(String year) {
this.year = year;
}
@Override
public String toString() {
return "Info[engine=" + this.engine + ",year=" + this.year + "]";
}
}
private String brand;
private String build;
private Info carinfo;
public Car() {
// Nothing to do
}
public Car(String brand,String build,String engine,String year) {
this.brand = brand;
this.build = build;
this.carinfo = new Info();
this.carinfo.setEngine(engine);
this.carinfo.setYear(year);
}
public String getBrand() {
return this.brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getBuild() {
return this.build;
}
public void setBuild(String build) {
this.build = build;
}
@JsonIgnore // For XML,not JSON
public Info getCarinfo() {
if (this.carinfo == null)
this.carinfo = new Info();
return this.carinfo;
}
public void setCarinfo(Info info) {
this.carinfo = info;
}
@XmlTransient // For JSON,not XML
public String getEngine() {
return getCarinfo().getEngine();
}
public void setEngine(String engine) {
getCarinfo().setEngine(engine);
}
@XmlTransient // For JSON,not XML
public String getYear() {
return getCarinfo().getYear();
}
public void setYear(String year) {
getCarinfo().setYear(year);
}
@Override
public String toString() {
return "Car[brand=" + this.brand + ",build=" + this.build + ",carinfo=" + this.carinfo + "]";
}
}
测试
Car car = new Car("Ferari","Italy","Mercedes","2021");
// Generate JSON
ObjectMapper jsonMapper = new ObjectMapper();
jsonMapper.enable(SerializationFeature.INDENT_OUTPUT);
String json = jsonMapper.writeValueAsString(car);
// Generate XML
JAXBContext jaxbContext = JAXBContext.newInstance(Car.class);
Marshaller xmlMarshaller = jaxbContext.createMarshaller();
xmlMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,Boolean.TRUE);
String xml;
try (StringWriter writer = new StringWriter()) {
xmlMarshaller.marshal(car,writer);
xml = writer.toString();
}
// Print generated results
System.out.println(car);
System.out.println(json);
System.out.println(xml);
// Parse JSON
Car carFromJson = jsonMapper.readValue(json,Car.class);
System.out.println(carFromJson);
// Parse XML
Unmarshaller xmlUnmarshaller = jaxbContext.createUnmarshaller();
Car carFromXml = xmlUnmarshaller.unmarshal(new StreamSource(new StringReader(xml)),Car.class).getValue();
System.out.println(carFromXml);
输出
Car[brand=Ferari,build=Italy,carinfo=Info[engine=Mercedes,year=2021]]
{
"brand" : "Ferari","build" : "Italy","engine" : "Mercedes","year" : "2021"
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Car>
<brand>Ferari</brand>
<build>Italy</build>
<carinfo>
<engine>Mercedes</engine>
<year>2021</year>
</carinfo>
</Car>
Car[brand=Ferari,year=2021]]
Car[brand=Ferari,year=2021]]
如您所见,生成的 JSON 和 XML 正是您想要的,最后两行输出表明解析也能正常工作。