No @XmlRootElement généré par JAXB

j'essaie de générer des classes Java à partir de la version 4.5 du FpML (Financial Products Markup Language). Une tonne de code est générée, mais je ne peux pas l'utiliser. En essayant de sérialiser un document simple je reçois ceci:

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]

en fait Non les classses ont l'annotation @xmlrootelement, alors que puis-je faire de mal?. Je pointe xjc (JAXB 2.1) sur fpml-main-4-5.xsd, qui inclut alors tous les types.

187
demandé sur Peter Rosemann 2009-05-04 15:32:19

14 réponses

pour lier ensemble ce que d'autres ont déjà déclaré ou laissé entendre, les règles par lesquelles JAXB XJC décide si oui ou non mettre l'annotation @XmlRootElement sur une classe générée sont non triviales ( voir cet article ).

@XmlRootElement existe parce que L'exécution JAXB nécessite certaines informations afin de marshal/unmarshal un objet donné, en particulier le nom de L'élément XML et l'Espace-nom. Vous ne pouvez pas juste passer n'importe quel vieil objet au Marshaller. @XmlRootElement fournit cette information.

l'annotation est juste une commodité, cependant - JAXB ne l'exige pas. L'alternative est d'utiliser des objets JAXBElement wrapper, qui fournissent les mêmes informations que @XmlRootElement , mais sous la forme d'un objet, plutôt qu'une annotation.

cependant, JAXBElement les objets sont difficiles à construire, puisque vous avez besoin de connaître le nom de L'élément XML et l'espace de nom, qui logique d'affaires habituellement Non.

heureusement, quand XJC génère un modèle de classe, il génère aussi une classe appelée ObjectFactory . C'est en partie là pour la rétrocompatibilité avec JAXB v1, mais C'est aussi là comme un endroit pour XJC de mettre les méthodes d'usine générées qui créent JAXBElement enveloppant vos propres objets. Il gère le nom XML et l'espace de noms pour vous, de sorte que vous n'avez pas besoin de vous inquiéter à ce sujet. Vous avez juste besoin de regarder à travers les méthodes ObjectFactory (et pour les grands schémas, là peut-être des centaines d'entre eux) pour trouver celui dont vous avez besoin.

232
répondu skaffman 2017-09-05 04:16:28

cela est mentionné au bas de l'article de blog déjà lié ci-dessus, mais cela fonctionne comme un plaisir pour moi:

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);
59
répondu Gurnard 2011-05-03 13:18:29

comme indiqué dans l'une des réponses ci-dessus, vous n'obtiendrez pas de XMLRootElement sur votre élément root si dans le XSD son type est défini comme un type nommé, puisque ce type nommé pourrait être utilisé ailleurs dans votre XSD. Essayez un type anonyme, i.e. au lieu de:

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

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

vous auriez:

<xsd:element name="myRootElement">
    <xsd:complexType>
    ...
    <xsd:complexType>
</xsd:element>
42
répondu Matthew Wise 2013-02-27 16:27:01

@xmlrootelement n'est pas nécessaire pour unmarshalling - si on utilise la forme à 2 paramètres de Unmarshaller#unmarshall.

ainsi, si au lieu de faire:

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

on devrait faire:

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

ce dernier code ne requerra pas d'annotation @XmlRootElement au niveau de la classe UserType.

32
répondu Sayantam 2015-08-20 20:55:52

la réponse de Joe (Joe Jun 26 '09 à 17:26) le fait pour moi. La réponse simple est que l'absence d'une annotation @XmlRootElement ne pose pas de problème si vous mariez un JAXBElement. La chose qui m'a embrouillé est L'ObjectFactory généré a 2 méthodes createMyRootElement-la première ne prend pas de paramètres et donne l'objet non enveloppé, la seconde prend l'objet non enveloppé et le renvoie enveloppé dans un JAXBElement, et la formation que JAXBElement fonctionne bien. Voici le code de base que j'ai utilisé (je suis nouveau à cela, donc des excuses si le code n'est pas formaté correctement dans cette réponse), en grande partie cribbed de lien texte :

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
répondu Yaqoob 2010-12-30 15:58:30

vous pouvez corriger ce problème en utilisant la liaison de comment générer des Classes @XmlRootElement pour les Types de Base dans XSD? .

voici un exemple avec 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>

voici le binding.xjb contenu du fichier

<?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>
16
répondu Olivier.Roger 2017-05-23 12:10:34

comme vous le savez, la réponse est d'utiliser ObjectFactory(). Voici un exemple du code qui a fonctionné pour moi:)

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
répondu Shehaaz 2016-08-02 14:26:07

ça ne marche pas pour nous non plus. Mais nous avons trouvé un article largement cité qui ajoute un peu de contexte... Je vais le relier ici pour le bien de la personne suivante: http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html

6
répondu mcherm 2009-06-18 15:38:42

avec une construction Maven, vous pouvez ajouter le @XmlRootElement annotation

avec le " jaxb2-basics-annotate " plug-in.

Voir plus d'informations : voir

configurer Maven pour générer des classes à partir du schéma XML en utilisant JAXB

et JAXB XJC code generation

4
répondu metatechbe 2017-04-13 12:40:36

au cas où mon expérience de ce problème donne à quelqu'un un Eureka! moment.. Je vais ajouter ce qui suit:

j'ai également eu ce problème, en utilisant un fichier xsd que j'avais généré en utilisant L'option de menu" Generate xsd from Instance document " D'IntelliJ.

lorsque j'ai accepté toutes les valeurs par défaut de cet outil, il a généré un fichier xsd qui, utilisé avec jaxb, a généré des fichiers java sans @XmlRootElement . A runtime quand j'ai essayé de marshal j'ai eu le même exception que celle dont il est question dans cette question.

je suis retourné à L'outil IntellJ, et j'ai vu l'option par défaut dans le" desgin Type " tomber vers le bas (qui, bien sûr, je n'ai pas compris.. et n'ont toujours pas si je suis honnête) a été:

Desgin Type:

"éléments locaux/types complexes globaux "

j'ai changé ceci en

"éléments/types locaux"

, maintenant il a généré un (substantiellement) différent xsd, qui a produit le @XmlRootElement lorsqu'il est utilisé avec jaxb. Je ne peux pas dire que je comprends les entrées et les sorties, mais ça a marché pour moi.

4
répondu johnm 2014-11-26 15:44:10

avez-vous essayé de changer votre xsd comme ça?

<!-- create-logical-system -->
<xs:element name="methodCall">
  <xs:complexType>
    ...
  </xs:complexType>
</xs:element>
3
répondu Tony 2011-05-02 22:45:58

jaxbelement wrappers fonctionne pour les cas où aucun @XmlRootElement n'est généré par JAXB. Ces emballages sont disponibles dans la classe ObjectFactory générée par maven-jaxb2-plugin . Par exemple:

     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;
      }
 }
2
répondu zer0Id0l 2017-08-09 15:31:08

pour le résoudre, vous devez configurer une liaison xml avant de compiler avec wsimport, en définissant generateElementProperty comme 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
répondu leandruol 2011-11-15 15:14:45

après avoir passé deux jours à dégonfler, j'ai trouvé la solution au problème.Vous pouvez utiliser la classe ObjectFactory pour contourner les classes qui n'ont pas le @xmlrootelement . ObjectFactory a des méthodes surchargées pour l'enrouler autour du JAXBElement. Méthode:1 fait la création simple de l'objet et Méthode: 2 envelopper l'objet avec @JAXBElement . Toujours pour utiliser Méthode:2 pour éviter javax.XML.lier.MarshalException - liés exception manque un @XmlRootElement annotation

Méthode: 1

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

Méthode:2

 @XmlElementDecl(namespace = "my/name/space", name = "getCountry")
 public JAXBElement<GetCountry> createGetCountry(GetCountry value) {
        return new JAXBElement<GetCountry>(_GetCountry_QNAME, GetCountry.class, null, value);
    }

exemple de code de travail:

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();
1
répondu prasadg 2018-03-03 12:46:54