web-dev-qa-db-ja.com

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]

実際、noクラスには@XmlRootElementアノテーションがあります。私はxjc(JAXB 2.1)をfpml-main-4-5.xsdに向けていますが、これにはすべてのタイプが含まれています。

195
robinr

他の人がすでに述べたり示唆したことを結び付けるために、生成されたクラスに@XmlRootElement注釈を付けるかどうかをJAXB XJCが決定する規則は重要ではありません( この記事を参照 )。

@XmlRootElementが存在するのは、JAXBランタイムが特定のオブジェクト、具体的にはXML要素名と名前空間をマーシャリング/アンマーシャリングするために特定の情報を必要とするためです。古いオブジェクトをマーシャラーに渡すことはできません。 @XmlRootElementはこの情報を提供します。

ただし、注釈は便利ですが、JAXBでは必要ありません。代替手段はJAXBElementラッパーオブジェクトを使用することです。ラッパーオブジェクトは、@XmlRootElementと同じ情報を提供しますが、注釈ではなくオブジェクトの形式で提供します。

ただし、JAXBElementオブジェクトは、ビジネス要素では通常は認識されないXML要素の名前と名前空間を知る必要があるため、構築するのが面倒です。

ありがたいことに、XJCがクラスモデルを生成すると、ObjectFactoryというクラスも生成されます。これはJAXB v1との後方互換性のために一部ありますが、XJCが生成されたファクトリメソッドを配置して、独自のオブジェクトのJAXBElementラッパーを作成する場所としてもあります。 XML名と名前空間を処理するため、心配する必要はありません。必要なものを見つけるには、ObjectFactoryメソッド(および大規模なスキーマの場合、何百ものメソッドが存在する可能性があります)を調べるだけです。

251
skaffman

これは、すでに上記でリンクされているブログ投稿の下部に記載されていますが、これは私の治療のように機能します:

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);
65
Gurnard

上記の回答の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>
47
Matthew Wise

@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アノテーションを必要としません。

34
Sayantam

Joeの答え(Joe Jun 26 '09 at 17:26)は私のためにそれをします。簡単な答えは、JAXBElementをマーシャリングする場合、@ XmlRootElementアノテーションがなくても問題ないということです。混乱したのは、生成されたObjectFactoryに2つのcreateMyRootElementメソッドがあることです。最初のメソッドはパラメーターを受け取らず、ラップされていないオブジェクトを提供します。ここに私が使用した基本的なコードがあります(これは初めてなので、この返信でコードが正しくフォーマットされていない場合はおologiesびします)、 link text

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

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>
17
Olivier.Roger

ご存じのとおり、答えは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();
    }
7
Shehaaz

私たちにとっても機能していません。しかし、いくつかの背景を追加する広く引用された記事を見つけました...次の人のためにここにリンクします: http://weblogs.Java.net/blog/kohsuke/archive /2006/03/why_does_jaxb_p.html

6
mcherm

この問題の私の経験が誰かにユーレカを与える場合に備えて!瞬間..次を追加します。

また、IntelliJの[インスタンスドキュメントからxsdを生成]メニューオプションを使用して生成したxsdファイルを使用すると、この問題が発生していました。

このツールのすべてのデフォルトを受け入れたとき、jaxbとともに使用すると、@XmlRootElementなしでJavaファイルが生成されるxsdファイルが生成されました。実行時にマーシャリングしようとしたときに、この質問で説明したのと同じ例外が発生しました。

IntellJツールに戻って、「設計タイプ」ドロップダウンのデフォルトオプションを見ました(もちろんそれは理解できませんでしたが、正直なところまだわかりません)。

設計タイプ:

"ローカル要素/グローバル複合型"

これを

"ローカル要素/タイプ"

、jaxbで使用すると@XmlRootElementを生成する(実質的に)異なるxsdを生成するようになりました。私はそれの内外を理解しているとは言えませんが、それは私のために働いた。

5
johnm

Mavenビルドでは、@XmlRootElementアノテーションを追加できます

jaxb2-basics-annotate」プラグインを使用します。

詳細情報を参照してください。

JAXBを使用してXMLスキーマからクラスを生成するようにMavenを設定

および JAXB XJCコード生成

4
metatechbe

JAXBElementラッパーは、@XmlRootElementがJAXBによって生成されない場合に機能します。これらのラッパーは、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;
      }
 }
3
zer0Id0l

このようにxsdを変更しようとしましたか?

<!-- create-logical-system -->
<xs:element name="methodCall">
  <xs:complexType>
    ...
  </xs:complexType>
</xs:element>
3
Tony

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();
2
prasadg

それを解決するには、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>
1
leandruol