JAXB XMLAdapter:有没有一种方法可以将此方法转换为JAXB XmlAdapter [英] JAXB XMLAdapter: Is there a way to convert this method into JAXB XmlAdapter

查看:74
本文介绍了JAXB XMLAdapter:有没有一种方法可以将此方法转换为JAXB XmlAdapter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个JSON文件,我正在尝试使用 JAXB 注释方法将其转换为 XML .现在一切正常,我能够将 JSON 转换为 XML .现在,我尝试对代码进行一些重构,以使我的课程看上去很干净.因此,我试图删除我的 class 中存在的方法,并将其命名为 JAXB XMLAdapter ,以便其他类可以重用它.

I have a JSON file that I am trying to convert into XML using the JAXB annotation approach. Everything is working fine now and I able to convert the JSON to XML. Now I am trying to refactor the code a little bit so that my class would look clean. Hence, I am trying to remove the method which is present in my class and make it JAXB XMLAdapter so that it can be reused by other classes.

基本上,我想将 XMLSupport 方法从 CarInfo 类移动到 XMLAdapter .将它们移到 XMLAdapter 时,我不确定如何填充 CarInfo 对象.

Basically I would like to move the XMLSupport method from CarInfo class to XMLAdapter. I am not sure how to populate the CarInfo objects when I move them to the XMLAdapter.

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

Following is my JSON file (it has been modified for simplicity purpose):

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

以下是我希望 JAXB 提供的 XML :(观察 JSON中不存在的 carInfo 标签./code>,但我需要使用 XML 来匹配标准的 XSD )

Following is the XML that I expect JAXB to provide: (Observe the carInfo tag which is not present in JSON but I need in XML to match the standard XSD)

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

以下是我拥有的类:(与JSON元素匹配的Tha Car 类)

Following are the classes that I have: (Tha Car class that matches the JSON elements)

@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 类,该类通过添加 carInfo 标签来构建 XML :

Following is MYCar class that builds the XML by adding the carInfo tag:

@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 标记的帮助者:

Following is my CarInfo class which acts as a helper to build the additional tag around MyCar class:

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

以下是我的 Main 类,该类实际上是通过使用 JAXBCOntext

Following is my Main class which actually builds the XML by using the 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 ?

Now coming back to my main question: As we can see from MyCar class I have the XMLSupport method which is actually populating the CarInfo objects and then using that method I am creating the XML. Is there a way I can move this to XMLAdapter?

我尝试创建 XMLAdapter ,但是不确定如何从适配器中填充 CarInfo 对象:

I tried creating the XMLAdapter but I am not sure how can I populate the CarInfo objects from the adapter:

public class MyCar extends Car{
    
    @XmlElement(name="carInfo")
    @XmlJavaTypeAdapter(ExtensionAdapter.class)
    @XmlElement(name = "carInfo")
    private CarInfo carInfo;
}

以下是我尝试过的我的 Adapter 类:公共类ExtensionAdapter扩展了XmlAdapter< CarInfo,CarInfo>.{

Following is my Adapter class I've tried: public class ExtensionAdapter extends 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.

You don't need any adapters, you just need a well-defined POJO.

诀窍是使用getter和setter,而不是字段访问,因此我们可以进行委托,然后使用 @JsonIgnore @XmlTransient 控制用于JSON和XML的getter/setter方法.

The trick is using getters and setters, not field access, so we can do delegation, and then use @JsonIgnore and @XmlTransient to control which getter/setter methods are used for JSON vs 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正是您想要的,输出的最后两行表明解析同样有效.

As you can see, the generated JSON and XML is exactly what you wanted, and the last two lines of output shows that parsing works as well.

这篇关于JAXB XMLAdapter:有没有一种方法可以将此方法转换为JAXB XmlAdapter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆