232

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にポイントします。これには、すべてのタイプが含まれます。

4

17 に答える 17

278

他の人がすでに述べていることや示唆していることを結び付けるために、JAXB XJCが@XmlRootElement生成されたクラスにアノテーションを付けるかどうかを決定するルールは簡単ではありません(この記事を参照)。

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

注釈は単なる便宜ですが、JAXBはそれを必要としません。の代わりに、JAXBElementラッパーオブジェクトを使用することもできます。ラッパーオブジェクトは、と同じ情報を提供します@XmlRootElementが、注釈ではなくオブジェクトの形式で提供します。

ただし、JAXBElementXML要素の名前と名前空間を知る必要があるため、オブジェクトの作成は厄介です。これは、ビジネスロジックでは通常はわかりません。

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

于 2010-01-31T19:15:06.603 に答える
71

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

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);
于 2011-05-03T13:18:29.243 に答える
59

上記の回答の1つで示唆されているように、XSDでその型が名前付き型として定義されている場合、その名前付き型はXSDの他の場所で使用できるため、ルート要素でXMLRootElementを取得することはできません。匿名タイプ、つまり次の代わりに作成してみてください。

<xsd:element name="myRootElement" type="MyRootElementType" />

<xsd:complexType name="MyRootElementType">
...
</xsd:complexType>

あなたが持っているだろう:

<xsd:element name="myRootElement">
    <xsd:complexType>
    ...
    <xsd:complexType>
</xsd:element>
于 2013-02-27T16:27:01.513 に答える
40

@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アノテーションは必要ありません。

于 2011-08-09T15:22:59.147 に答える
24

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>
于 2012-05-16T07:13:06.703 に答える
21

ジョーの答え(ジョー2009年6月26日17:26)は私のためにそれをします。簡単な答えは、JAXBElementをマーシャリングする場合、@XmlRootElementアノテーションがなくても問題はないということです。私を混乱させたのは、生成されたObjectFactoryに2つのcreateMyRootElementメソッドがあることです。最初のメソッドはパラメーターを受け取らず、ラップされていないオブジェクトを提供し、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;
  }
}
于 2010-12-30T15:58:30.220 に答える
11

ご存知のように、答えは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();
    }
于 2016-02-18T18:15:49.133 に答える
8

2日間苦労した後、問題の解決策を見つけました。ObjectFactoryクラスを使用して、 @XmlRootElementを持たないクラスを回避できます。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();
于 2018-03-03T12:01:54.457 に答える
7

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

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

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

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

デザインタイプ:

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

これをに変更しました

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

、今では(実質的に)異なるxsdが生成さ@XmlRootElementれ、jaxbで使用すると生成されます。インとアウトを理解しているとは言えませんが、うまくいきました。

于 2014-11-26T15:44:10.913 に答える
6

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

于 2009-06-18T15:38:42.397 に答える
6

Mavenビルドを使用すると、@XmlRootElement注釈を追加できます

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

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

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

およびJAXBXJCコード生成

于 2012-06-07T10:13:28.160 に答える
6

@XmlRootElementJAXBElementラッパーは、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;
      }
 }
于 2017-08-09T15:31:08.710 に答える
4

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

<!-- create-logical-system -->
<xs:element name="methodCall">
  <xs:complexType>
    ...
  </xs:complexType>
</xs:element>
于 2011-05-02T22:40:21.170 に答える
4

このトピックはかなり古いものですが、それでもエンタープライズビジネスのコンテキストに関連しています。将来簡単に更新できるように、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が作成されます。

jaxb2-maven-plugin2.実行を分割します

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つのクラスで十分である可能性があるという事実をキャッチしないため、実行ごとにカスタムクラスを作成します。そしてそれはまさに私が必要としているものです;)。

于 2020-03-30T07:25:18.420 に答える
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>
于 2011-11-15T15:14:45.370 に答える
1

そのため、私はmavenを使用maven-jaxb2-pluginして、大きくて複雑なWSDLファイルからクラスを生成し、この問題に遭遇しました。問題は、WSDLの要素がcomplexType定義を参照しているtypeため、要素クラスが生成されておらず、complexTypeクラスを使用しようとすると、欠落した@XmlRootElementエラーが発生することです。

私の意見では、WSDLを変更することは実際には実行可能な解決策ではありません。実用的な唯一のことは、生成中に欠落している注釈を追加する方法を設計するように思われました。また、リクエストが間違った要素名を送信しており、応答に一致する要素名を持つクラスがなかったため、マーシャリング時にシリアル化で問題が発生しました。

私がやったjaxb2-basics-annotateことは、jaxbバインディングファイルを使用して、不足しているアノテーションを必要なクラスに追加できる2番目のMavenプラグインを使用することでした。これにより、不要なコードを追加せずにこの問題を解決する必要がなくなり、将来更新されたWSDLファイルを使用する必要がある場合に簡単に再生成できるようになります。

pom.xml(実行の構成にプラグインセクションがあることに注意してください-WSDLファイルの場所は/src/main/resources/wsdl/EstimatingService.wsdlです)

<project>
    ...
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <jaxb2.version>0.14.0</jaxb2.version>
        <jaxb2.annotate.version>1.1.0</jaxb2.annotate.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <version>${jaxb2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jvnet.jaxb2_commons</groupId>
            <artifactId>jaxb2-basics-annotate</artifactId>
            <version>${jaxb2.annotate.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>${jaxb2.version}</version>
                <executions>
                    <execution>
                        <id>estimating</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <schemaLanguage>WSDL</schemaLanguage>
                            <generateDirectory>target/generated-sources/acme/src/gen/estimating-service</generateDirectory>
                            <generatePackage>com.acme.shipping.estimating.service</generatePackage>
                            <schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
                            <schemaIncludes>
                                <include>EstimatingService.wsdl</include>
                            </schemaIncludes>
                            <bindingDirectory>${project.basedir}/src/main/resources/bindings</bindingDirectory>
                            <bindingIncludes>estimateServiceBinding.xjb</bindingIncludes>
                            <extension>true</extension>
                            <args>
                                <arg>-Xannotate</arg>
                                <arg>-XremoveAnnotation</arg>
                            </args>
                            <plugins>
                                <plugin>
                                    <groupId>org.jvnet.jaxb2_commons</groupId>
                                    <artifactId>jaxb2-basics-annotate</artifactId>
                                </plugin>
                            </plugins>
                        </configuration>
                    </execution>
                    ...
                    // More executions here if you have multiple WSDL files (Dont forget to give it a different package name and id)
                </executions>
            </plugin>
        </plugins>
    </build>
    ...
</project>  

EstimateServiceBinding.xjb(この例で使用されるjaxbバインディングファイル-/src/main/resources/bindings/estimateServiceBinding.xjb

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:annox="http://annox.dev.java.net" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    <jaxb:globalBindings generateElementProperty="false">
        <xjc:simple />
    </jaxb:globalBindings>
    <!-- Target the schema section in the WSDL file using the given target namespace which contains the complexType definitions we want to annotate -->
    <jaxb:bindings schemaLocation="../wsdl/EstimatingService.wsdl" node="//xs:schema[@targetNamespace='http://acme.com/schema/datatypes/v2']">
        <jaxb:bindings node="xs:complexType[@name='GetQuickEstimateRequestContainer']">
            <!-- Add the @XmlRootElement annotation to the generated class and then tell it use the correct element name required when marshalling. e.g GetQuickEstimateRequestContainer element is renamed to the element name that referenced it in the WSDL (GetQuickEstimateRequest) -->
            <annox:annotateClass>@javax.xml.bind.annotation.XmlRootElement(name="GetQuickEstimateRequest")</annox:annotateClass>
        </jaxb:bindings>
        <jaxb:bindings node="xs:complexType[@name='GetQuickEstimateResponseContainer']">
            <annox:annotateClass>@javax.xml.bind.annotation.XmlRootElement(name="GetQuickEstimateResponse")</annox:annotateClass>
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>

@XmlRootElementアノテーションと正しい要素名を持つ生成されたクラス(GetQuickEstimateRequestContainer.java)

@XmlRootElement(name = "GetQuickEstimateRequest")
public class GetQuickEstimateRequestContainer {
    ...
    // class member fields & setters and getters
    ...
}
于 2021-08-26T23:46:47.500 に答える
0

同じ問題でしばらく苦労していたので、うまくいく最終結果を投稿したいと思います。したがって、基本的な問題は次のとおりです。

  • XmlRootElementアノテーションのないJAXBクラスインスタンスからxml文字列を生成する必要があります
  • クラスには、マーシャリングプロセスにバインドする追加のクラスが必要です

次のクラスは、この問題に対して正常に機能します。

public class Object2XmlConverter {

    public static <T> String convertToString(final T jaxbInstance, final Class<?>... additionalClasses)
            throws JAXBException {
        final Class<T> clazz = (Class<T>) jaxbInstance.getClass();

        final JAXBContext jaxbContext;
        if (additionalClasses.length > 0) {
            // this path is only necessary if you need additional classes to be bound
            jaxbContext = JAXBContext.newInstance(addClassesToBeBound(clazz, additionalClasses));
        } else {
            jaxbContext = JAXBContext.newInstance(clazz);
        }

        final QName qname = new QName("", jaxbInstance.getClass().getSimpleName());
        final JAXBElement<T> jaxbElement = new JAXBElement<T>(qname, clazz, null, jaxbInstance);

        final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        final StringWriter stringWriter = new StringWriter();
        jaxbMarshaller.marshal(jaxbElement, stringWriter);
        return stringWriter.toString();
    }

    private static <T> Class<?>[] addClassesToBeBound(final Class<T> clazz, final Class<?>[] additionalClasses) {
        final Class<?>[] classArray = new Class<?>[additionalClasses.length + 1];
        for (int i = 0; i < additionalClasses.length; i++) {
            classArray[i] = additionalClasses[i];
        }
        classArray[classArray.length - 1] = clazz;
        return classArray;
    }

    public static void main(final String[] args) throws Exception {
        final Ns1TargetHeaderTyp dataTyp = ...;
        System.out.println(convertToString(dataTyp));
    }
}
于 2020-11-30T18:51:46.993 に答える