Нет @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, который затем включает все типы.
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
в случае, если мой опыт этой проблемы дает кому-то Эврика! момент.. Я добавлю следующее:
Я также получал эту проблему при использовании 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