JAXB XMLAdapter:有没有办法将此方法转换为JAXB XMLAdapter



我有一个JSON文件,我正试图使用JAXB注释方法将其转换为XML。现在一切都很好,我可以将JSON转换为XML。现在我正在尝试对代码进行一点重构,这样我的类看起来就会很干净。因此,我试图删除class中存在的方法,并将其设为JAXB XMLAdapter,以便其他类可以重用它。

基本上,我想将XMLSupport方法从CarInfo类移动到XMLAdapter。当我将CarInfo对象移动到XMLAdapter时,我不知道如何填充它们。

以下是我的JSON文件(为了简单起见,对其进行了修改(:

{
"brand": "Ferari",
"build": "Italy",
"engine": "Mercedes",
"year": "2021"

}

以下是我希望JAXB提供的XML:(观察JSON中不存在的carInfo标签,但我需要在XML中匹配标准XSD(

<?xml version="1.0"?>
<Car>
<brand>Ferari</brand>
<build>Italy</build>
<carinfo>
<engine>Mercedes</engine>
<year>2021</year>
</carinfo>
</Car>

以下是我拥有的类:(匹配JSON元素的ThaCar类(

@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
}

以下是通过添加carInfo标签构建XMLMYCar类:

@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类,它充当了围绕MyCar类构建additional标签的助手:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = {"engine","year"})
public class Carinfo{
private String engine;
private String year;
//Getter, Setters and other consturctiores ommited
}

下面是我的Main类,它使用JAXBCOntext实际构建了XML

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课程:公共类ExtensionAdapter扩展XmlAdapter<CarInfo、CarInfo>{

@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", "build", "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, build=Italy, carinfo=Info[engine=Mercedes, year=2021]]
Car[brand=Ferari, build=Italy, carinfo=Info[engine=Mercedes, year=2021]]

正如您所看到的,生成的JSON和XML正是您想要的,最后两行输出显示解析也能正常工作。

最新更新