Нет @XmlRootElement генерируется JAXB



Я пытаюсь создать классы Java из FpML (Finanial Products Markup Language) версии 4.5. Создается тонна кода, но я не могу его использовать. Пытаясь сериализовать простой документ, я получаю следующее:



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, который затем включает все типы.

745   14  

14 ответов:

чтобы связать воедино то, что другие уже заявили или намекнули, правила, по которым JAXB XJC решает, следует ли ставить @XmlRootElement аннотации на сгенерированном классе нетривиальны (эту статью).

@XmlRootElement существует, потому что среда выполнения JAXB требует определенной информации для маршалинга/unmarshal данного объекта, в частности имя элемента 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);
<xsd:element name="myRootElement" type="MyRootElementType" />

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

вы бы:

<xsd:element name="myRootElement">
    <xsd:complexType>
    ...
    <xsd:complexType>
</xsd:element>

@XmlRootElement не требуется для unmarshalling-если используется форма 2 параметра Unmarshaller#unmarshall.

Итак, если вместо этого делать:

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

надо сделать:

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

последний код не требует аннотации @XmlRootElement на уровне класса UserType.

ответ Джо (Джо июня 26 '09 В 17:26) делает это для меня. Самый простой ответ заключается в том, что отсутствие @XmlRootElement аннотация-это не проблема, если вы маршал JAXBElement. То, что меня смутило, - это сгенерированный ObjectFactory имеет 2 метода createMyRootElement-первый не принимает параметров и дает развернутый объект, второй берет развернутый объект и возвращает его, завернутый в JAXBElement, и маршалинг этого JAXBElement отлично работает. Вот основной код, который я использовал (я новичок это, так что извиняюсь, если код не отформатирован правильно в этом ответе), в основном cribbed from текст ссылки:

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

вы можете исправить эту проблему с помощью привязки от как создать классы @XmlRootElement для базовых типов в XSD?.

вот пример с 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>

здесь контент

<?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

С помощью Maven, вы можете добавить @XmlRootElement аннотации

С "jaxb2-basics-annotate" плагин.

см. дополнительную информацию: см.

настройка Maven для создания классов из XML-схемы с помощью JAXB

и генерация кода JAXB XJC

в случае, если мой опыт этой проблемы дает кому-то Эврика! момент.. Я добавлю следующее:

Я также получал эту проблему при использовании xsd-файла, который я создал с помощью опции меню IntelliJ "Generate xsd from Instance document".

когда я принял все значения по умолчанию этого инструмента, он сгенерировал xsd-файл, который при использовании с jaxb генерировал java-файлы без @XmlRootElement. Во время выполнения, когда я пытался маршалировать, я получил то же исключение, что и обсуждалось в этот вопрос.

Я вернулся к инструменту IntellJ и увидел опцию по умолчанию в выпадающем списке "Тип Desgin" (что, конечно, я не понял.. и до сих пор нет, если честно) было:

Тип Desgin:

"локальные элементы / глобальные сложные типы"

Я изменил это, чтобы

"локальные элементы/типа"

, теперь он сгенерировал a (существенно) другой xsd, который произвел @XmlRootElement при использовании с jaxb. Не могу сказать, что я понимаю, в чем дело, но это сработало для меня.

вы пытались изменить свой xsd вот так?

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

фантики 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;
      }
 }

для его решения вы должны настроить привязку xml перед компиляцией с wsimport, установив 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>

после того, как сругглинг в течение двух дней я нашел решение этой проблемы.Вы можете использовать ObjectFactory класс для обхода для классов, которые не имеют @XmlRootElement. ObjectFactory имеет перегруженные методы, чтобы обернуть его вокруг JAXBElement. Способ:1 совсем простое создание объекта и Способ:2 обернет объект с @JAXBElement. Всегда использовать Способ:2 чтобы избежать класса javax.XML.связывать.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();

Comments

    Ничего не найдено.