Marshalling/Unmarshalling Java 使用 JAXB 的超类和子类

Marshalling/Unmarshalling Java superclass and subclasses using JAXB

我一直在试验 JAXB 教程,并设法让代码工作,从 Java 对象生成 XML 文件,然后能够使用 XML 来生成一个 Java 对象。目前它读取同一个 class 的多个实例来创建一个类似于下面的 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 技术来处理子classes。例如:假设我有一个 Car、Van 和 Bicycle 对象,它们是 Vehicle 的子class。我是否可以操纵我的 JAXB class 来编写一个 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>

主要Class

package basictransport2;

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

车辆Class

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

汽车Class

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 Class

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());
        }
    }
}

列表class

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

你走在正确的轨道上。可能下面的内容会有所帮助

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


    }

最简单的解决方案是为汽车和货车设置不同的子classes,即使它们不会向基础 classes 添加任何东西。然后,根元素 class 包含基 class 的列表,元素 QNames 标识实际 class.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Vehicle")
public class Vehicle {
    @XmlElements({
        @XmlElement(name = "Car", type = Car.class, required = false),
        @XmlElement(name = "Van", type = Van.class, required = false)
    })
    protected List carOrVan;
    public List getCarOrVan() {
        if (carOrVan == null) {
            carOrVan = new ArrayList();
        }
        return this.carOrVan;
    }
}

这是基础 class 和子class:

public class Basic {
    private String regplate;
    private String color;
    private String energyrating;

    public String getRegplate(){ return regplate; }
    public void setRegplate( String v ){ regplate = v; }
    public String getColor(){ return color; }
    public void setColor( String v ){ color = v; }
    public String getEnergyrating(){ return energyrating; }
    public void setEnergyrating( String v ){ energyrating = v; }
}

public class Car extends Basic {}

public class Van extends Basic {}

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

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

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

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

superclass 必须用 @XmlSeeAlso 注释才能将 subclasses 绑定到它。即在我的代码中 RoadVehicle 是超级 class 并且 CarVan class 扩展了它。

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

有了 super 和 subclasses 现在注释了唯一需要注释的其他 class 是列表 class(我的代码中的车库)。此处的更改将决定 XML 标签填充的内容。

根 XML 标签是通过将 @XmlRootElement 注释应用到 class 的顶部来设置的。即 "Vehicle" 在我的示例中将是根 XML 标记。

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

最后,必须声明一个 @XmlElements 列表,其中每个子 class 都需要一个 XML 标记并带有 name 提供的 @XmlElements 注释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;
    }