【问题标题】:Marshalling/Unmarshalling Java superclass and subclasses using JAXB使用 JAXB 编组/解组 Java 超类和子类
【发布时间】:2016-01-26 23:18:57
【问题描述】:

我一直在试验 JAXB 教程,并设法让代码工作,从 Java 对象生成 XML 文件,然后能够使用 XML 生成 Java 对象。目前它读取同一个类的多个实例以创建一个类似于下面的 XML 文件

<Car>
    <regplate>TR54</regplate>
    <colour>red</colour>
    <energyrating>5</energyrating>
</Car>
<Car>
    <regplate>BN04 THY</regplate>
    <colour>yellow</colour>
    <energyrating>3</energyrating>
</Car>
<Car>
    <regplate>BN05 THY</regplate>
    <colour>yellow</colour>
    <energyrating>5</energyrating>
</Car>

我希望能够使用 JAXB 技术来处理子类。例如:假设我有一个 Car、Van 和 Bicycle 对象,它们是 Vehicle 的子类。我是否可以操纵我的 JAXB 类来编写一个 XML 文件来产生类似的东西?我在下面提供了我正在使用的代码。

<Vehicle>
    <Car>
        <regplate>TR54</regplate>
        <colour>red</colour>
        <energyrating>5</energyrating>
    </Car>
    <Van>
        <regplate>MN05 RFD</regplate>
        <colour>red</colour>
        <energyrating>5</energyrating>
    </Van>
    <Car>
        <regplate>ZX54 UJK</regplate>
        <colour>red</colour>
        <energyrating>1</energyrating>
    </Car>
</Vehicle>

主类

package basictransport2;

public class Main
{
    public static void main(String[] args)
    {
        JAXB parser = new JAXB();
        parser.marshall();
        //parser.unmarshallList();
    }
}

车辆类别

package basictransport2;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

//@XmlRootElement(name = "Vehicle")
public class Vehicle
{
    private int ownerId;

    public Vehicle(int ownerId)
    {
        this.setOwnerId(ownerId);
    }

    //@XmlElement (name = "Owner ID")
    public int getOwnerId()
    {
        return ownerId;
    }

    public void setOwnerId(int ownerId)
    {
        this.ownerId = ownerId;
    }


    public int getEnergyRating()
    {
        return (Integer) null;
    }


    public String getColour()
    {
        return null;
    }

    public String getRegPlate()
    {
        return null;
    }
}

汽车类

package basictransport2;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

//@XmlRootElement(name = "Car")
public class Car extends Vehicle
{
    private String regPlate;
    private int energyRating;
    private String colour;

    public Car(String regPlate, int energyRating, String colour, int ownerId)
    {
        super(ownerId);
        this.regPlate = regPlate;
        this.energyRating = energyRating;
        this.colour = colour;
    } 

    public Car(int ownerId)
    {
        super(ownerId);
    }

    //@XmlElement (name = "Registration")
    public String getRegPlate()
    {
        return regPlate;
    }

    public void setRegPlate(String regPlate)
    {
        if(this.regPlate == null)
        {
            this.regPlate = regPlate;
        }
    }

    //@XmlElement (name = "Energy Rating")
    public int getEnergyRating()
    {
        return energyRating;
    }

    public void setEnergyRating(int energyRating)
    {
        this.energyRating = energyRating;
    }

    //@XmlElement (name = "Colour")
    public String getColour()
    {
        return colour;
    }

    public void setColour(String colour)
    {
        this.colour = colour;
    }
}

JAXB 类

package basictransport2;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class JAXB
{   
    public void marshall()
    {
        try
        {
            List<Vehicle> vehicleList = new ArrayList<Vehicle>();

            vehicleList.add(new Car("SG09 TYH", 4, "Yellow", 1));
            vehicleList.add(new Car("XX09 VVV", 3, "Red", 2));
            vehicleList.add(new Car("BL09 TYZ", 4, "Blue", 3));

            Garage listOfVehicles = new Garage();
            listOfVehicles.setListOfVehicles(vehicleList);

            JAXBContext context = JAXBContext.newInstance(Garage.class);
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(listOfVehicles, System.out);
            marshaller.marshal(listOfVehicles, new File("src\\data\\listcar.xml"));
        }

        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }

    public void unmarshall()
    {
        try
        {
            JAXBContext context = JAXBContext.newInstance(Garage.class);
            Unmarshaller unmarhsaller = context.createUnmarshaller();
            Garage listOfVehicles = (Garage)unmarhsaller.unmarshal(new File("src\\data\\listcar.xml"));
            System.out.println("List Car information");

            for(Vehicle vehicle : listOfVehicles.getListOfVehicles())
            {
                System.out.println("Reg Plate: " + vehicle.getRegPlate());
                System.out.println("Energy Rating: " + vehicle.getEnergyRating());
                System.out.println("Colour: " + vehicle.getColour());
                System.out.println("================");
            }    
        }

        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
    }
}

列表类

package basictransport2;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="Vehicle")
public class Garage
{
    @XmlElements
    ({
        @XmlElement(name = "Car", type = Car.class, required = false)
    })    

    private List<Vehicle> vehicleCollection = new ArrayList<Vehicle>();

    public List<Vehicle> getListOfVehicles()
    {
        return vehicleCollection;
    }

    public void setListOfVehicles(List<Vehicle> listOfVehicles)
    {
        this.vehicleCollection = listOfVehicles;
    }
}

【问题讨论】:

  • 您需要创建一个 Vehicle 类,您的子车辆将从该类继承。查看@XmlSeeAlso 标记以进行绑定。

标签: java xml jaxb unmarshalling


【解决方案1】:

感谢大家的意见。我使用了您所有答案的反馈,但最终是它们的组合起作用,这就是为什么我为将来可能遇到此问题的任何人创建了一个单独的答案。

为了让它工作,我必须确保在被编组/解组的超类和子类中的所有 getter 方法都用 @XmlElement 注释。这将确定相应变量的 XML 标记。

@XmlElement (name = "OwnerID")
    public int getOwnerId()
    {
        return ownerId;
    }

必须用@XmlSeeAlso 注释超类才能将子类绑定到它。即在我的代码中,RoadVehicle 是超类,CarVan 类都扩展了它。

@XmlSeeAlso({Car.class, Van.class})
public class Vehicle
{

现在注释了超类和子类,唯一需要注释的其他类是列表类(我的代码中的车库)。此处的更改将确定填充 XML 标记的内容。

根 XML 标记是通过将 @XmlRootElement 注释应用到类的顶部来设置的。即“车辆”将是我的示例中的根 XML 标记。

@XmlRootElement(name = "Vehicle")
public class Garage
{

最后,@XmlElements 列表必须使用 @XmlElements 注释为每个需要 XML 标记的子类声明,name 提供 XML 标记的名称。这个列表必须在集合的 getter 方法之上声明。

@XmlElements
    ({
        @XmlElement(name = "Car", type = Car.class, required = false),
        @XmlElement(name = "Van", type = Van.class, required = false)
    })    
    public List<Vehicle> getListOfVehicles()
    {
        return vehicleCollection;
    }

【讨论】:

    【解决方案2】:

    你在正确的轨道上。希望下面的东西会有所帮助

    @XmlRootElement(name = "car")
    public class Car extends BasicType{
    
    }
    
    @XmlRootElement(name = "van")
    public class Van extends BasicType{
    
    }
    
    @XmlRootElement(name = "vehicle")
        public class Vehicle {
             List<BasicType> basicType;
    
    
        }
    

    【讨论】:

    • 感谢您的意见。我试过了,得到了 1 个 IllegalAnnotationExceptions 计数。 (我现在已经注释掉了)
    【解决方案3】:

    最简单的解决方案是为汽车和货车设置不同的子类,即使它们不向基类添加任何内容。然后,根元素类包含一个基类列表,元素 QNames 标识实际类。

    @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "车辆") 公共类车辆{ @XmlElements({ @XmlElement(name = "Car", type = Car.class, required = false), @XmlElement(name = "Van", type = Van.class, required = false) }) 受保护列表 carOrVan; 公共列表 getCarOrVan() { if (carOrVan == null) { carOrVan = new ArrayList(); } 返回 this.carOrVan; } }

    这是基类和子类:

    公共类基本{ 私人字符串注册; 私有字符串颜色; 私人弦能量评级; public String getRegplate(){ return regplate; } public void setRegplate(String v){ regplate = v; } public String getColor(){ 返回颜色; } 公共无效 setColor( 字符串 v ){ 颜色 = v; } public String getEnergyrating(){ return energyrating; } public void setEnergyrating(String v){energyrating = v; } } 公共类汽车扩展基本{} 公共类范扩展基本{}

    如果汽车和货车发展成不同的子类,这将顺利进行。

    【讨论】:

    • 谢谢。我已尝试实施您的建议(请参阅编辑),但收到“2 个 IllegalAnnotationExceptions 计数”
    • 没有标记的行是绝望的。 - 我的答案中的代码已经过测试并且可以工作。 - 然而,最好的方法是编写一个 XML Schema 并使用 xjc 来编译 Java 类。
    • 是的,没有迹象表明异常发生在哪里
    • AFAIK,那些错误信息通常表明非法注释异常发生在哪里。
    • 我必须删除我的异常调用的 .getMessage
    猜你喜欢
    • 1970-01-01
    • 2010-12-28
    • 2010-10-11
    • 1970-01-01
    • 2011-07-03
    • 2014-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多