首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JAXB XMLAdapter:有没有办法将这种方法转换成JAXB XmlAdapter

JAXB XMLAdapter:有没有办法将这种方法转换成JAXB XmlAdapter
EN

Stack Overflow用户
提问于 2021-04-28 21:09:31
回答 1查看 58关注 0票数 0

我有一个JSON文件,我正在尝试使用JAXB注解方法将其转换为XML。现在一切正常,我能够将JSON转换为XML。现在,我正在尝试稍微重构一下代码,这样我的类看起来就更干净了。因此,我正在尝试删除我的class中存在的方法,并将其设置为JAXB XMLAdapter,以便其他类可以重用它。

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

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

代码语言:javascript
复制
{
   "brand": "Ferari",
   "build": "Italy",
    "engine": "Mercedes",
    "year": "2021"
   
}

下面是我期望JAXB提供的XML:(观察carInfo标记,它在JSON中不存在,但我需要在XML中匹配标准XSD)

代码语言:javascript
复制
<?xml version="1.0"?>
<Car>
    <brand>Ferari</brand>
    <build>Italy</build>
    <carinfo>
        <engine>Mercedes</engine>
        <year>2021</year>
    </carinfo>
</Car>

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

代码语言:javascript
复制
@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类:

代码语言:javascript
复制
@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标记的帮助器:

代码语言:javascript
复制
@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

代码语言:javascript
复制
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对象:

代码语言:javascript
复制
public class MyCar extends Car{
    
    @XmlElement(name="carInfo")
    @XmlJavaTypeAdapter(ExtensionAdapter.class)
    @XmlElement(name = "carInfo")
    private CarInfo carInfo;
}

下面是我尝试过的Adapter类:公共类ExtensionAdapter扩展了XmlAdapter {

代码语言:javascript
复制
    @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;
    }
}
EN

回答 1

Stack Overflow用户

发布于 2021-04-28 22:05:48

你不需要任何适配器,你只需要一个定义良好的POJO。

诀窍是使用getter和setter,而不是字段访问,所以我们可以进行委托,然后使用@JsonIgnore@XmlTransient来控制哪些getter/setter方法用于JSON vs XML。

代码语言:javascript
复制
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 + "]";
    }
}

测试

代码语言:javascript
复制
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);

输出

代码语言:javascript
复制
Car[brand=Ferari, build=Italy, carinfo=Info[engine=Mercedes, year=2021]]
代码语言:javascript
复制
{
  "brand" : "Ferari",
  "build" : "Italy",
  "engine" : "Mercedes",
  "year" : "2021"
}
代码语言:javascript
复制
<?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>
代码语言:javascript
复制
Car[brand=Ferari, build=Italy, carinfo=Info[engine=Mercedes, year=2021]]
代码语言:javascript
复制
Car[brand=Ferari, build=Italy, carinfo=Info[engine=Mercedes, year=2021]]

如您所见,生成的JSON和XML正是您想要的,输出的最后两行显示解析也是有效的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67300882

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档