Unable to marshal type as XML element because @XmlRootElement annotation is missing

42,536

Solution 1

public String toXML(T object) throws JAXBException {
  StringWriter stringWriter = new StringWriter();

  JAXBContext jaxbContext = JAXBContext.newInstance(T.class);
  Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

  // format the XML output
  jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

  QName qName = new QName("com.yourModel.t", "object");
  JAXBElement<T> root = new JAXBElement<Bbb>(qName, T.class, object);

  jaxbMarshaller.marshal(root, stringWriter);

  String result = stringWriter.toString();
  LOGGER.info(result);
  return result;
}

Here is the article I use when I have to marshal/unmarshal without @XmlRootElement: http://www.source4code.info/2013/07/jaxb-marshal-unmarshal-with-missing.html

All the best hope it helps :)

Solution 2

Note that the error message talks about FreightOfferDetail, not FreightOffer.

Based on that, I would expect that somewhere (outside the provided code), you're asking a Detail to be marshalled.

If you want to be able to do that (with JAXB?) you need to annotate that class as well with the XmlRootElement annotation.

Solution 3

You can use the ObjectFactory class to workaround for the classes which doesn't have the @XmlRootElement. ObjectFactory has overloaded methods.

Method:1 It does simple creation of the object and

Method:2 It will wrap the object with @JAXBElement.

Always to use Method:2 to avoid javax.xml.bind.MarshalException - with linked exception missing an @XmlRootElement annotation

Method:1

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

Method:2

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

for more information follow this stackoverflow-question

Hope this will be helpful...

Share:
42,536
catch23
Author by

catch23

Updated on July 05, 2022

Comments

  • catch23
    catch23 almost 2 years

    I want to marshal object to XML.

    However, it fails with exception:

    javax.xml.bind.MarshalException
     - with linked exception:
    [com.sun.istack.SAXException2: unable to marshal type "FreightOfferDetail" as an element because it is missing an @XmlRootElement annotation]
        at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:331)
        at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:257)
        at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:96)
        at com.wktransportservices.fx.test.util.jaxb.xmltransformer.ObjectTransformer.toXML(ObjectTransformer.java:27)
        at com.wktransportservices.fx.test.sampler.webservice.connect.FreightOfferToConnectFreight.runTest(FreightOfferToConnectFreight.java:59)
        at org.apache.jmeter.protocol.java.sampler.JavaSampler.sample(JavaSampler.java:191)
        at org.apache.jmeter.threads.JMeterThread.process_sampler(JMeterThread.java:429)
        at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:257)
        at java.lang.Thread.run(Thread.java:662)
    Caused by: com.sun.istack.SAXException2: unable to marshal type "FreightOfferDetail" as an element because it is missing an @XmlRootElement annotation
        at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:244)
        at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:303)
        at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:490)
        at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:328)
    

    In fact, this annotation is present (for parent and delivered class):

    @XmlRootElement(name = "Freight_Offer")
    @XmlAccessorType(XmlAccessType.FIELD)
    @JsonIgnoreProperties(ignoreUnknown = true)
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    public class FreightOffer {
        @JsonIgnore
        @XmlTransient
        private String freightId;
        private String id;
    
        private String externalSystemId;
    
        private AddressLocation pickUp;
    
        private AddressLocation delivery;
    
        private FreightDescription freightDescription;
    
        private ListContacts contacts;
    
        private Customer customer;
    
        private ListSla slas;
    
        private String pushId;
    
        private CompanyProfile company;
    
        private Route route;
    
        private String href;
    
        private Lifecycle lifecycle;
    
        private Visibility visibility;
    
        private Boolean unfoldedVXMatching;
        // getters / setters
    

    Child class:

    @XmlAccessorType(XmlAccessType.PROPERTY)
    public class FreightOfferDetail extends FreightOffer {
    
        private List<Contact> contact;
    
        @XmlElement(name = "contacts")
        @JsonProperty("contacts")
        public List<Contact> getContact() {
            return contact;
        }
    
        public void setContact(List<Contact> contact) {
            this.contact = contact;
        }
    

    It fails exactly at this method toXML():

    public class ObjectTransformer<T> implements Transformer<T> {
    
        protected final JAXBContext context;
        protected final Marshaller marshaller;
    
        protected final int okStatusCode = 200;
        protected final String okSubErrorCode = "OK";
    
        public ObjectTransformer(JAXBContext context) throws JAXBException {
            this.context = context;
            marshaller = context.createMarshaller();
            marshaller.setProperty("jaxb.encoding", "UTF-8");
            marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
        }
    
        public String toXML(T object) throws JAXBException {
            StringWriter writer = new StringWriter();
            marshaller.marshal(object, writer);
            String xmlOffer = writer.toString();
            return xmlOffer;
        }
    

    It should work, but it shouldn't.

    I couldn't find what is missed or wrong here.

    UPDATE:

    Here is snippet from test:

    public SampleResult runTest(JavaSamplerContext context) {
        AbstractSamplerResults results = new XMLSamplerResults(new SampleResult());
        results.startAndPauseSampler();
    
        if (failureCause != null) {
            results.setExceptionFailure("FAILED TO INSTANTIATE connectTransformer", failureCause);
        } else {
            FreightOfferDTO offer = null;
            FreightOffer freightOffer = null;
            try {
                results.resumeSampler();            
    
                RouteInfo routeDTO = SamplerUtils.getRandomRouteFromRepo(context.getIntParameter(ROUTES_TOUSE_KEY));
    
                offer = FreightProvider.createRandomFreight(routeDTO, createUserWithLoginOnly(context));
    
                freightOffer = connectTransformer.fromDTO(offer);
                String xmlOfferString = connectTransformer.toXML(freightOffer); // <- it fails here.
    

    I take the date from CSV file and converting to DTO object. This method returns to me FreightOfferDetail.

    Here is snippet from this method:

    public FreightOfferDetail freightFromDTO(FreightOfferDTO freightDTO, boolean fullFormat){
        FreightOfferDetail freight = new FreightOfferDetail();
    
        freight.setFreightId(freightDTO.getIds().getAtosId());
        freight.setId(freightDTO.getIds().getFxId());
        // ...
    

    How to marshal object to XML file, at this case?

  • catch23
    catch23 about 8 years
    I tried your suggestion. Result is the same - javax.xml.bind.MarshalException - with linked exception: [com.sun.istack.SAXException2 ...
  • Alain Van Hout
    Alain Van Hout about 8 years
    Could have you include the entire stack trace? The exception type doesn't say a lot without the accompanying exception message. And the actual marshalling call would help to narrow it down (i.e. what type of object is actually being marshalled?).
  • catch23
    catch23 about 8 years
    View the question. It contains exactly this exception.
  • Alain Van Hout
    Alain Van Hout about 8 years
    Okay, I'm just asking because in the original question you seemed to not have noticed that the exception did not refer to the class that you pointed out as indeed having that annotation.
  • Alain Van Hout
    Alain Van Hout about 8 years
    that snippet doesn't include an actual toXml() call, and the Detail class contains List<Contact> field. Is that field annotated with the needed XML annotations? And based on the initial feedback, could you update the class definition annotations?
  • catch23
    catch23 about 8 years
    Contact has only XmlAccessorType. About which class definition have you exactly talked?
  • Alain Van Hout
    Alain Van Hout about 8 years
    I'm talking about FreightOfferDetail (rather than FreightOffer) since that's what's mentioned in the original stacktrace message. To reiterate: the exception indicates that you are converting a Detail directly and that it therefore needs that one annotation.
  • catch23
    catch23 almost 6 years
    On that project we had to use ant as a build tool. And my main goal is marshal object to XML instead of wrapping fault message. I have exception stack trace from a console.