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 オブジェクトが設定されていても、'car' ノードの下には何も入力されていません。この問題を解決するには?

4

2 に答える 2

20

JAXB システムは、可能な JAXB アノテーション付きクラスのクラスパスを調べません。それらを見つけるのを手伝わなければなりません。Ferrariサンプル コードでは、単にクラスの存在を認識していません。(それCarは の getter の戻り値の型であるため、表示されるだけCarTestReportです。)

JAXB に伝える手っ取り早い方法の 1 つは、クラスの先頭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(上記のようなものではなく)という名前の要素を発行したい場合、1つの可能性は、次のようにクラスの先頭<car xsi:type="ferrari">に追加することです。@XmlTypeCar

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 {
  // ...
}

私が理解していることから、この注釈の組み合わせは、Carクラスが XML スキーマにマップされていること (つまり、「car」という名前の要素を取得しないこと)、およびFerrariクラスがその型の要素であること(したがって、 「フェラーリ」と名付けられた要素)。そして、「ルート」@XmlRootElementは誤解を招きます...オブジェクトの構造のどこにでもある要素になる可能性があります。

于 2012-07-06T19:41:25.080 に答える
2

Ferrari クラスに注釈を付け、 car 属性を次のよう@XmlRootElementに置き換える必要があります。@XmlElement@XmlElementRef

于 2016-07-18T13:13:12.223 に答える