JAXBによって生成された@XmlRootElementはありません
質問
FpML(Finanial Products Markup Language)バージョン4.5からJavaクラスを生成しようとしています。大量のコードが生成されますが、使用できません。簡単なドキュメントをシリアル化しようとすると、次のようになります。
javax.xml.bind.MarshalException
- with linked exception: [com.sun.istack.SAXException2: unable
to marshal type
"org.fpml._2008.fpml_4_5.PositionReport"
as an element because it is missing an
@XmlRootElement annotation]
実際には、クラスには@XmlRootElementアノテーションがないので、何が間違っているのでしょうか。 xjc(JAXB 2.1)をfpml-main-4-5.xsdに向けています。これにはすべてのタイプが含まれます。
解決
他の人がすでに述べたり示唆したことを結びつけるために、JAXB XJCが生成されたクラスに @XmlRootElement
アノテーションを付けるかどうかを決定するルールは重要ではありません(こちらの記事をご覧ください)。
@XmlRootElement
は、JAXBランタイムが特定のオブジェクト、特にXML要素名と名前空間をマーシャリング/アンマーシャリングするために特定の情報を必要とするために存在します。古いオブジェクトをマーシャラーに渡すことはできません。 @XmlRootElement
はこの情報を提供します。
注釈は便利なだけですが、JAXBでは必要ありません。代替方法は、 JAXBElement
ラッパーオブジェクトを使用することです。これは、 @XmlRootElement
と同じ情報を提供しますが、注釈ではなくオブジェクトの形式です。
ただし、 JAXBElement
オブジェクトは、ビジネスロジックでは通常認識されないXML要素名と名前空間を知る必要があるため、構築するのが困難です。
ありがたいことに、XJCがクラスモデルを生成すると、 ObjectFactory
というクラスも生成されます。これはJAXB v1との後方互換性のために部分的にありますが、XJCが独自のオブジェクトの周りに JAXBElement
ラッパーを作成する生成されたファクトリメソッドを置く場所としてもあります。 XML名と名前空間を処理するため、心配する必要はありません。必要なものを見つけるには、 ObjectFactory
メソッド(および大規模なスキーマの場合は、数百個存在する可能性があります)を調べるだけで済みます。
他のヒント
これは、すでに上記でリンクされているブログ投稿の下部に記載されていますが、これは私にとってはうれしい機能です:
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(new JAXBElement<MyClass>(new QName("uri","local"), MyClass.class, myClassInstance), System.out);
上記の回答の1つで示唆されているように、XSDでタイプが名前付きタイプとして定義されている場合、その名前付きタイプはXSDの他の場所で使用できるため、ルート要素でXMLRootElementを取得しません。匿名型、つまり:の代わりにmkingしてみてください:
<xsd:element name="myRootElement" type="MyRootElementType" />
<xsd:complexType name="MyRootElementType">
...
</xsd:complexType>
次のようになります:
<xsd:element name="myRootElement">
<xsd:complexType>
...
<xsd:complexType>
</xsd:element>
@XmlRootElementはアンマーシャリングに必要ありません-Unmarshaller#unmarshallの2パラメーター形式を使用する場合。
したがって、次のようにすると:
UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString));
やるべきこと:
JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class);
UserType user = userElement.getValue();
後者のコードは、UserTypeクラスレベルで@XmlRootElementアノテーションを必要としません。
Joeの答え(Joe Jun 26 '09 at 17:26)が私のためにしています。簡単な答えは、JAXBElementをマーシャリングする場合、@ XmlRootElementアノテーションがなくても問題ないということです。混乱したのは、生成されたObjectFactoryに2つのcreateMyRootElementメソッドがあることです。最初のメソッドはパラメーターを使用せず、ラップされていないオブジェクトを提供します。ここに私が使用した基本的なコードがあります(私はこれが初めてなので、この返信でコードが正しくフォーマットされていない場合はおaびします)、主にリンクテキスト:
ObjectFactory objFactory = new ObjectFactory();
MyRootElement root = objFactory.createMyRootElement();
...
// Set root properties
...
if (!writeDocument(objFactory.createMyRootElement(root), output)) {
System.err.println("Failed to marshal XML document");
}
...
private boolean writeDocument(JAXBElement document, OutputStream output) {
Class<?> clazz = document.getValue().getClass();
try {
JAXBContext context =
JAXBContext.newInstance(clazz.getPackage().getName());
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(document, output);
return true;
} catch (JAXBException e) {
e.printStackTrace(System.err);
return false;
}
}
のバインディングを使用してこの問題を修正できますXSDで基本型の@XmlRootElementクラスを生成する方法は?。
Mavenの例
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>src/main/resources/xsd</schemaDirectory>
<packageName>com.mycompany.schemas</packageName>
<bindingFiles>bindings.xjb</bindingFiles>
<extension>true</extension>
</configuration>
</plugin>
これは binding.xjb
ファイルのコンテンツです
<?xml version="1.0"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="path/to/myschema.xsd" node="/xs:schema">
<jxb:globalBindings>
<xjc:simple/>
</jxb:globalBindings>
</jxb:bindings>
</jxb:bindings>
ご存じのとおり、答えはObjectFactory()を使用することです。ここに私のために働いたコードのサンプルがあります:)
ObjectFactory myRootFactory = new ObjectFactory();
MyRootType myRootType = myRootFactory.createMyRootType();
try {
File file = new File("./file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(MyRoot.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
//output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
JABXElement<MyRootType> myRootElement = myRootFactory.createMyRoot(myRootType);
jaxbMarshaller.marshal(myRootElement, file);
jaxbMarshaller.marshal(myRootElement, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
それは私たちにとっても機能していません。しかし、いくつかの背景を追加する広く引用された記事を見つけました...次の人のためにここにリンクします: http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html
この問題の私の経験が誰かにユーレカを与える場合!瞬間..次を追加します。
IntelliJの「インスタンスドキュメントからxsdを生成」を使用して生成したxsdファイルを使用しているときにも、この問題が発生していました。メニューオプション。
このツールのデフォルトをすべて受け入れたとき、xcodeが生成され、jaxbで使用すると、 @XmlRootElement
のないJavaファイルが生成されました。実行時にマーシャリングしようとしたときに、この質問で説明したのと同じ例外が発生しました。
IntellJツールに戻り、「設計タイプ」にデフォルトオプションが表示されました。ドロップダウン(もちろん、私は理解していませんでした。..正直な場合でも、まだわかりません):
設計タイプ:
&quot;ローカル要素/グローバル複合型&quot;
これを
に変更しました&quot;ローカル要素/タイプ&quot;
、今では(実質的に)異なるxsdを生成し、jaxbとともに使用すると @XmlRootElement
を生成しました。私はそれの内外を理解しているとは言えませんが、それは私のために働いた。
Mavenビルドでは、 @XmlRootElement
注釈を追加できます
&quot; jaxb2-basics-annotate
&quot;プラグイン。
詳細を参照してください:参照
XMLスキーマからクラスを生成するようにMavenを構成するJAXB
and JAXB XJCコード生成
xsdをこのように変更しようとしましたか?
<!-- create-logical-system -->
<xs:element name="methodCall">
<xs:complexType>
...
</xs:complexType>
</xs:element>
JAXBElementラッパーは、JAXBによって @XmlRootElement
が生成されない場合に機能します。これらのラッパーは、 maven-jaxb2-plugin
によって生成された ObjectFactory
クラスで使用できます。例:
public class HelloWorldEndpoint {
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "person")
@ResponsePayload
public JAXBElement<Greeting> sayHello(@RequestPayload JAXBElement<Person> request) {
Person person = request.getValue();
String greeting = "Hello " + person.getFirstName() + " " + person.getLastName() + "!";
Greeting greet = new Greeting();
greet.setGreeting(greeting);
ObjectFactory factory = new ObjectFactory();
JAXBElement<Greeting> response = factory.createGreeting(greet);
return response;
}
}
2日間の密輸の後、問題の解決策が見つかりました。 ObjectFactory クラスを使用して、 @XmlRootElement を持たないクラスを回避できます。 ObjectFactoryには、JAXBElementをラップするメソッドがオーバーロードされています。 Method:1 はオブジェクトの簡単な作成を行い、 Method:2 はオブジェクトを @JAXBElement でラップします。常に Method:2 を使用してjavax.xml.bind.MarshalExceptionを回避する-リンク例外で@XmlRootElementアノテーションが欠落している
方法:1
public GetCountry createGetCountry() {
return new GetCountry();
}
方法:2
@XmlElementDecl(namespace = "my/name/space", name = "getCountry")
public JAXBElement<GetCountry> createGetCountry(GetCountry value) {
return new JAXBElement<GetCountry>(_GetCountry_QNAME, GetCountry.class, null, value);
}
実際のコードサンプル:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
WebServiceTemplate springWSTemplate = context.getBean(WebServiceTemplate.class);
GetCountry request = new GetCountry();
request.setGuid("1f3e1771-3049-49f5-95e6-dc3732c3227b");
JAXBElement<GetCountryResponse> jaxbResponse = (JAXBElement<GetCountryResponse>)springWSTemplate .marshalSendAndReceive(new ObjectFactory().createGetCountry(request));
GetCountryResponse response = jaxbResponse.getValue();
それを解決するには、wsimportでコンパイルする前にxmlバインディングを構成し、generateElementPropertyをfalseに設定する必要があります。
<jaxws:bindings wsdlLocation="LOCATION_OF_WSDL"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='NAMESPACE_OF_WSDL']">
<jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xjc:generateElementProperty>false</xjc:generateElementProperty>
</jxb:globalBindings>
</jaxws:bindings>
</jaxws:bindings>