9

考虑以下抽象类 -

public abstract class Car
{
    public abstract void drive(double miles);
}

这是扩展上述类的示例类(用于说明目的)。

public class Ferrari extends Car
{
    private String lastUsed; // Ferrari specific field not in Car
    private boolean f1Car;   // Ferrari specific field not in Car

    @XmlElement
    public void setF1Car(boolean f1Car)
    {
        this.f1Car = f1Car;
    }

    public boolean isF1Car() { return f1Car; }

    @XmlElement
    public void setLastUsed(String lastUsed)
    {
        this.lastUsed = lastUsed;
    }

    public String getLastUsed() { return lastUsed; }

    public void drive(double miles)
    {
        // implementation
    }
}

我有一个包含 Car 对象的报告类 -

@XmlRootElement
public class CarTestReport
{
    private String date;
    private double miles;
    private Car car;

    @XmlElement
    public void setDate(String date) { this.date = date;}

    public String getDate() {return date;}

    @XmlElement
    public void setMiles(double miles) { this.miles = miles; }

    public double getMiles() {return miles;}

    @XmlElement
    public void setCar(Car car) { this.car = car; }

    public Car getCar() { return car; }
}

这是使用 JAXB 来编组 CarTestReport 对象的一段代码 -

public static void main(String[] args) throws Exception
{
    Ferrari ferrari = new Ferrari();
    ferrari.setLastUsed("July 5 2012");
    ferrari.setF1Car(false);

    CarTestReport  report = new CarTestReport();
    report.setDate("July 6 2012");
    report.setMiles(200);
    report.setCar(ferrari);

    File file = new File("carTestReport.xml");
    JAXBContext jaxbContext = JAXBContext.newInstance(CarTestReport.class);
    Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

    jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    jaxbMarshaller.marshal(report, file);
}

问题是,由于抽象类型 Car,JAXB 在编组 CarTestReport 对象时忽略它并且不编组 Ferrari 对象。我得到的输出是这个 -

<carTestReport>
  <car/>
  <date>July 6 2012</date>
  <miles>200.0</miles>
</carTestReport> 

如您所见,“汽车”节点下没有输入任何内容,即使已填充 Ferrari 对象。如何解决这个问题呢?

4

2 回答 2

20

JAXB 系统不会通过类路径查找任何可能的带有 JAXB 注释的类。你必须帮助它找到它们。在您的示例代码中,它根本不知道Ferrari该类的存在。(它只看到Car,因为那是 getter 中的返回类型CarTestReport。)

告诉 JAXB 的一种快速而肮脏的方法是在类的顶部Ferrari添加。然后你会得到这样的输出:@XmlSeeAlso({Ferrari.class})Car

<carTestReport>
  <car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ferrari">
    <f1Car>false</f1Car>
    <lastUsed>July 5 2012</lastUsed>
  </car>
  <date>July 6 2012</date>
  <miles>200.0</miles>
</carTestReport>

告诉 JAXB 的另一种方法Ferrari是将该类传递给JAXBContext.newInstance方法,即:

JAXBContext jaxbContext = JAXBContext.newInstance(CarTestReport.class,
        Ferrari.class);

或者,如果您所有的 JAXB 类都在同一个包中,例如com.mycompany.carstuff,那么您可以这样做:

JAXBContext jaxbContext = JAXBContext.newInstance("com.mycompany.carstuff");

在最后一种情况下,它将搜索该包中的所有类。

如果您希望它发出一个名为ferrari(而不是<car xsi:type="ferrari">上面的类似)的元素,一种可能性是添加@XmlType到您的Car类的顶部,如下所示:

import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;

@XmlSeeAlso({Ferrari.class})
@XmlType
public abstract class Car {
  public abstract void drive(double miles);
}

...并穿上@XmlRootElementFerrari例如:

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Ferrari extends Car {
  // ...
}

据我了解,这种注释组合告诉 JAXBCar该类映射到 XML 模式类型(因此您不会获得任何名为“car”的元素),并且Ferrari该类是该类型的元素(因此您可以拥有名为“法拉利”的元素)。并且其中的“根”@XmlRootElement具有误导性……它可以是对象结构中任何位置的元素。

于 2012-07-06T19:41:25.080 回答
2

您需要用car 属性注释您的 Ferrari 类@XmlRootElement并替换为@XmlElement@XmlElementRef

于 2016-07-18T13:13:12.223 回答