JAXBによって生成された@XmlRootElementはありません


209

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を指定しています。これにはすべてのタイプが含まれます。

回答:


261

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

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

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

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

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


15
特別なケースの解決策:クラス生成に使用されるxsdを変更できる場合: この回答で提供されるリンクを読んだ後の私の解決策は、クラスの生成に使用されるxsdファイルを変更することでした:ルート要素の定義を個別に定義された型への参照を使用する代わりに、インライン定義。これらにより、JAXBはこの要素を@XmlRootElementとして設定できます。これは、以前にルート要素に使用されていたelementTypeでは不可能でした。
Arthur

2
ただし、<scowl>ルート要素をインライン型に変更すると、すべてのクラスがルート型の内部クラスになります。また、ルート要素自体の後にルート要素タイプが定義されている場合でも(どうやらスキーマによって許可されている)、JAXBは@XmlRootElementで注釈を付けません。
Pawel Veselov 2013

10
ie new ObjectFactory().createPositionReport(positionReport)が戻るJAXBElement<PositionReport>
vikingsteve '27 / 09/27

17
生成されたObjectFactoryメソッドが引数をラップするメソッドを作成しない場合はどうなりJXBElementますか?私の場合、ファクトリメソッドは0-arityであり、newオブジェクトを返すだけです。(なぜ一部のクラスはJAXBElementラッパーヘルパーを与えられ、他のクラスは与えられないのですか?)その場合、私たちは自分でラッパーを作成する必要があると思いますか?
カールG

1
@CarlG私も同じ状況です。クラスにXmlRootElementもJAXBElementも表示されません。このケースの解決策を見つけましたか?
Mickael Marrache、2015

68

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

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

私はマークされた答えを好みますが、これも私にとってうまくいきます。
ペドロデュッソ2014

1
jc上記のスニペットには何がありますか?
アルン、2016

3
@ArunRajそれはJAXBContextクラスです
Gurnard

51

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

1
それは私には当てはまりません。私のタイプは匿名であり(ルート要素内に埋め込まれています)、XmlRootElementアノテーションは生成されません。何か案が?
Mickael Marrache 2016

38

@XmlRootElementは非整列化には必要ありません-Unmarshaller#unmarshallの2パラメータ形式を使用する場合。

だから、代わりに:

UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString));

1つを行う必要があります。

JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class);
UserType user = userElement.getValue();

後者のコードは、UserTypeクラスレベルで@XmlRootElementアノテーションを必要としません。


2
XmlRootElementを持たないオブジェクトをマーシャリングする同じようにエレガントな方法を知っていますか-skaffmanやGurnard等が述べたようにJAXBElementでラップせずに
Chris

4
+1は完璧に機能します!より明確にするための1つの編集...ソリューションでは、「someSource」は非常にあいまいな用語です。詳しく説明するには:JAXBElement <TargetClazz> root = unmarshaller.unmarshal(new StreamSource(new File( "some.xml"))、TargetClazz.class);
超新星

4
'someSource'の詳細:String pathname = "file.xml"; InputStream stream = new FileInputStream(pathname); JAXBContext jaxbContext = JAXBContext.newInstance(UserType.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader someSource = factory.createXMLEventReader(stream); JAXBElement<UserType> userElement = jaxbUnmarshaller.unmarshal(someSource, UserType.class); UserType user = userElement.getValue();
Steve Pitchers

21

Joeの答え(Joe Jun 26 '09 at 17:26)は私のためにそれをします。簡単な答えは、JAXBElementをマーシャリングする場合、@ XmlRootElementアノテーションがなくても問題はないということです。混乱したのは、生成されたObjectFactoryに2つのcreateMyRootElementメソッドがあることです。1つ目はパラメーターを取得せずにラップされていないオブジェクトを取得し、2つ目はラップされていないオブジェクトを取得してJAXBElementにラップして返し、JAXBElementが正常に機能することをマーシャリングします。これが私が使用した基本的なコードです(私はこれが初めてなので、コードがこの応答で正しくフォーマットされていないことをお詫びします)。リンクテキストから大きく引用されています

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

1
私のObjectFactoryクラスは、JAXBElementインスタンスではなく、通常のインスタンスを返すメソッドのみを定義する場合があります...
Mickael

20

この問題は、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>

3
確かに、binding.xjbファイルで<xjc:simple>を使用するとうまくいきました。マーシャリングコードまたはWSDLを変更したくない場合の素晴らしいソリューション。xjc:simpleは、コレクションのゲッターに対して異なるメソッド名(複数)を生成することに注意してください(たとえば、getOrderではなくgetOrders)
dvtoever

10

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

あなたのポイントに...ネストされた要素のためにObjectFactoryからのJAXBElement <?> create ...()メソッドをどのように使用しますか?ie:<SOAP-ENV:Header> <wsse:Security> <wsse:UsernameToken> </ wsse:UsernameToken> </ wsse:Security> </ SOAP-ENV:Header>取得:「タイプ "UsernameTokenType"をマーシャリングできません」 @XmlRootElementアノテーションがないため要素として」
アンジェリーナ

6

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


これは私にとってはうまくいきました、ありがとう。また、これを実行する過程で、間違ったJAXBオブジェクト(ルートは思っていたのではなく)をマーシャリングしていることもわかりました。JAXBElementを作成するのを忘れて、バインディングから取得したObjectFactoryクラスから返されたオブジェクトだけをマーシャリングしようとしていました。これは基本的に問題を完全に処理しました(他の誰かが同じ問題に直面した場合に備えて)。
Joe Bane、

1
404:「申し訳ありませんが、java.netサイトは閉鎖されました。以前java.netでホストされていたほとんどのオープンソースプロジェクトは、移転されました。」
トリスタン


6

2日間スラグリングした後、私は問題の解決策を見つけました。@XmlRootElementを持たないクラスの回避策としてObjectFactoryクラスを使用できます。ObjectFactoryには、JAXBElementをラップするためのオーバーロードメソッドがあります。

メソッド:1は、オブジェクトの単純な作成を行います。

Method:2は、オブジェクトを@JAXBElementでラップします。

常にMethod:2を使用して、javax.xml.bind.MarshalExceptionを回避します-リンクされた例外で@XmlRootElementアノテーションが欠落しています。

以下のサンプルコードを見つけてください

方法1:オブジェクトの簡単な作成を行います

public GetCountry createGetCountry() {
        return new GetCountry();
    }

Method:2は、オブジェクトを@JAXBElementでラップします。

 @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("test_guid");

JAXBElement<GetCountryResponse> jaxbResponse = (JAXBElement<GetCountryResponse>)springWSTemplate .marshalSendAndReceive(new ObjectFactory().createGetCountry(request));

GetCountryResponse response = jaxbResponse.getValue();

かなり長い間それを理解するのに苦労していたように、春のウェブサービステンプレートでコードリファレンスを提供してくれてありがとう!
RRR_J

5

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

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

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

私はIntellJツールに戻り、「Desgin Type」ドロップダウンにデフォルトのオプションが表示されていることを確認しました(もちろん、これは理解できませんでした。正直に言ってもわかりません)。

設計タイプ:

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

これを

「ローカル要素/タイプ」

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



4

JAXBElementラッパー@XmlRootElementは、JAXBによって生成されない場合に機能します。これらのラッパーは、ObjectFactoryによって生成されるクラスで使用できますmaven-jaxb2-plugin。たとえば:

     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

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

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

これは、JDK 1.7u71で動作しました。トップレベルの要素には、xjcによって@XmlRootElementが割り当てられます。最初は、トップレベルの複合型のみがありました。JAXBElementでラップする必要があることは、明らかに醜いです。
Serge Merzliakov、2015年

1

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

折り返しタグは次のようになります<jaxb:bindings> ... <jaxws:bindings> ... </jaxws:bindings> ... </jaxb:bindings>
aliopi '31 / 10/31

0

トピックはかなり古いですが、企業のビジネスコンテキストではまだ関連しています。後で簡単に更新できるように、xsdsに触れないようにしました。これが私の解決策です。

1.ほとんどxjc:simpleは十分です

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    jxb:extensionBindingPrefixes="xjc">

    <jxb:globalBindings>
        <xjc:simple/> <!-- adds @XmlRootElement annotations -->
    </jxb:globalBindings>

</jxb:bindings>

ほとんどの場合、xsd定義をインポートするためのXmlRootElementsを作成します。

2. jaxb2-maven-plugin実行を分割する

xsdごとの実行定義ではなく、複数のxsd定義からクラスを生成しようとすると、大きな違いが生じることに遭遇しました。

したがって、複数<source>のを含む定義がある場合は、それらを分割してみてください。

          <execution>
            <id>xjc-schema-1</id>
            <goals>
              <goal>xjc</goal>
            </goals>
            <configuration>
              <xjbSources>
                <xjbSource>src/main/resources/xsd/binding.xjb</xjbSource>
              </xjbSources>
              <sources>
                <source>src/main/resources/xsd/definition1/</source>
              </sources>
              <clearOutputDir>false</clearOutputDir>
            </configuration>
          </execution>

          <execution>
            <id>xjc-schema-2</id>
            <goals>
              <goal>xjc</goal>
            </goals>
            <configuration>
              <xjbSources>
                <xjbSource>src/main/resources/xsd/binding.xjb</xjbSource>
              </xjbSources>
              <sources>
                <source>src/main/resources/xsd/definition2/</source>
              </sources>
              <clearOutputDir>false</clearOutputDir>
            </configuration>
          </execution>

ジェネレーターは、1つのクラスで十分である可能性があるという事実をキャッチしないため、実行ごとにカスタムクラスを作成します。そして、それがまさに私が必要とするものです;)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.