3

Foo子クラスが不変であり、デフォルトの引数なしコンストラクターを定義しない親子関係があります。親クラス:Barは、インターフェースを通じて子を参照します: IFoo。コンストラクターの問題を解決するアダプターを定義しましたが、現在、JAXB がクラス Foo がこのコンテキストに認識されていないと不平を言っているという別の問題に直面しています。

これをブートストラップして解決しようとするJAXBContextFoo.class、代わりにデフォルト コンストラクターが不足しているというエラーが表示されます。

Unofficial JAXB Guide の 3.2.1 で説明されているインターフェイス マッピング アプローチに従おうとしていることに注意してください。

この問題を解決するには、別のインターフェイス マッピング アプローチを採用する必要がありますか? 各インターフェイスの実装を使用してマークするXmlRootElementことは、アダプタ コードが実行されていないことを意味するのではないかと思います (Blaise Doughanがここで説明しているように)。これは、これら 2 つのアプローチが本質的に互換性がなく、説明されている他のインターフェイス マッピング手法のいずれかを使用する必要があるかどうか疑問に思います。

public interface IFoo {
  String getName();
  int getAge();
}

@XmlJavaTypeAdapter(FooAdapter.class)
@XmlRootElement
public class Foo implements IFoo {
  private final String name;
  private final int age;

  public Foo(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public String getName() { return name; }
  public int getAge() { return age; }
}

public class FooAdapter extends XmlAdapter<AdaptedFoo, Foo> {
  @Override
  public Foo unmarshal(AdaptedFoo af) throws Exception {
    return new Foo(af.getName(), af.getAge());
  }

  @Override
  public AdaptedFoo marshal(Foo foo) throws Exception {
    AdaptedFoo ret = new AdaptedFoo();
    ret.setName(foo.getName());
    ret.setAge(foo.getAge());
    return ret;
  }
}

public class AdaptedFoo {
  private String name;
  private int age;

  public AdaptedFoo() {}

  @XmlAttribute
  public String getName() { return name; }
  public void setName(String name) { this.name = name; }

  @XmlAttribute
  public int getAge() { return age; }
  public void setAge(int age) { this.age = age; }
}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {
  @XmlAnyElement
  private IFoo foo;
  private int baz;

  public Bar() {}

  public IFoo getFoo() { return foo; }
  public void setFoo(IFoo foo) { this.foo = foo; }

  public int getBaz() { return baz; }
  public void setBaz(int baz) { this.baz = baz; }
}

public class Marshal {
  public static void main(String[] args) {
    Foo foo = new Foo("Adam", 34);
    Bar bar = new Bar();
    bar.setFoo(foo);
    bar.setBaz(10);

    try {
      JAXBContext jaxbContext = JAXBContext.newInstance(Bar.class, AdaptedFoo.class);
      Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

      // output pretty printed
      jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

      jaxbMarshaller.marshal(bar, System.out);
    } catch (JAXBException e) {
      e.printStackTrace();
    }
  }
}

スタックトレース

$ java Marshal
javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.internal.SAXException2: class Foo nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class Foo nor any of its super class is known to this context.]
        at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:311)
        at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236)
        at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
        at Marshal.main(Marshal.java:20)
Caused by: com.sun.istack.internal.SAXException2: class Foo nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class Foo nor any of its super class is known to this context.
        at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:235)
        at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:250)
        at com.sun.xml.internal.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodePr
operty.java:102)
        at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:341)
        at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:582)
        at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:323)
        at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:483)
        at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308)
        ... 3 more
Caused by: javax.xml.bind.JAXBException: class Foo nor any of its super class is known to this context.
        at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:573)
        at com.sun.xml.internal.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodePr
operty.java:94)
        ... 8 more
4

1 に答える 1

4

@XmlElementプロパティにアノテーションを使用しfooて実装タイプを指定すると、ユースケースが機能するはずです。

  @XmlElement(type=Foo.class)
  private IFoo foo;

バー

以下はあなたのBarクラスの更新されたバージョンです

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {
  @XmlElement(type=Foo.class)
  private IFoo foo;
  private int baz;

  public Bar() {}

  public IFoo getFoo() { return foo; }
  public void setFoo(IFoo foo) { this.foo = foo; }

  public int getBaz() { return baz; }
  public void setBaz(int baz) { this.baz = baz; }
}

詳細については

于 2012-08-15T18:18:01.370 に答える