4

I am trying to convert a Java object inside of a Java library to an XML file. However, I got this problem:

A a = new A();

// initializing for a

JAXBContext jc = JAXBContext.newInstance("libraryA.A");

Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(a, System.out);

Then I got this exception:

javax.xml.bind.JAXBException: "libraryA.a" doesnt contain ObjectFactory.class or jaxb.index
    at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:186)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:128)
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:290)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:244)

If I change: JAXBContext jc = JAXBContext.newInstance("libraryA.a");

to:

JAXBContext jc = JAXBContext.newInstance(libraryA.A.class);

then I have another exception:

com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions

library.A is an interface, and JAXB can't handle interfaces.
    this problem is related to the following location:
        at library.A

library.A does not have a no-arg default constructor.
    this problem is related 

to the following location:
    at library.A
halfer
  • 19,824
  • 17
  • 99
  • 186
olidev
  • 20,058
  • 51
  • 133
  • 197

2 Answers2

14

Background Info (From Related Question)

From the comment you made on my answer to your previous question the domain model is already being used with JAXB. The easiest way to have your client and server communicate via XML is to leverage the already annotated model on both ends.

I just have checked the source code of my client. In the process, we need to convert back a xml file which is generated from java objects to xml file using: javax.xml.bind.JAXBContext & javax.xml.bind.Marshaller. so my question is it possible to read back the xml file to the same java objects? then we can use the java objects for a further step. Thanks in advance!


UPDATE

It appears as though your issue is due to having a domain model that is defined through interfaces with backing implementation classes. Below I'll demonstrate how you can handle this using a JAXB implementation (Metro, MOXy, JaxMe, etc).

Demo Code

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(CustomerImpl.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("input.xml");
        Customer customer = (Customer) unmarshaller.unmarshal(xml);

        Address address = customer.getAddress();
        System.out.println(address.getStreet());

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}

Interface Model

The following interfaces represent our domain model. These interfaces when not be leveraged to bootstrap the JAXBContext.

Customer

public interface Customer {

    public Address getAddress();

    public void setAddress(Address address);

}

Address

public interface Address {

    public String getStreet();

    public void setStreet(String street);

}

Implementation Classes

The implementation classes are what will be mapped to XML using JAXB.

CustomerImpl

Note in the CustomerImpl class we use the @XmlElement annotation on the address property to specify the type is AddressImpl.

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="customer")
public class CustomerImpl implements Customer {

    private Address address;

    @XmlElement(type=AddressImpl.class)
    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}

AddressImpl

public class AddressImpl implements Address {

    private String street;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

}

input.xml

<?xml version="1.0" encoding="UTF-8"?>
<customer>
    <address>
        <street>1 Any Street</street>
    </address>
</customer>
Community
  • 1
  • 1
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • @Blaise: but if I am only allowed to call the Java interface. That means I can not use JAXB? am I correct? – olidev May 11 '11 at 22:36
  • Other problem if I tried to call implementation of the object: doesnt contain ObjectFactory.class or jaxb.index or – olidev May 11 '11 at 22:49
  • @JoseyXHN - I have updated my answer. The new example demonstrates how to map to the impl class, but still interact with the interface. If you bootstrap on a package name (context path) you need to include the jaxb.index file with carriage return separated impl classes. Some people find it easier to pass the classes in directly when creating the JAXBContext. – bdoughan May 12 '11 at 13:26
  • Hi Blaise: the java objects are in a Java library, I can not modify the code to add: @XmlRootElement(name="customer") so I still get the problem: does not have a no-arg default constructor. It is working fine with xstream. Thanks a lot for your help! – olidev May 16 '11 at 12:59
  • 1
    Hi Blaise: I am having a problem of deserialzing a java object using xStream. So i want to try JAXB again, as I mentioned we got a java library so I can not modify their implementation to add: @XmlRootElement(name="customer"), what should I do? thanks in advance – olidev May 27 '11 at 15:29
  • @JoesyXHN - Without an @XmlRootElement annotation you can use the unmarshal methods that take a class parameter to tell JAXB what type to unmarshal. You can also leverage the external mapping file in EclipseLink JAXB (MOXy) to provide the metadata: http://bdoughan.blogspot.com/2010/12/extending-jaxb-representing-annotations.html – bdoughan May 27 '11 at 16:09
  • Hi Blais! Thanks for your answer. I still have this problem: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions AImpl does not have a no-arg default constructor. this problem is related to the following location: at AImpl => In my case, AImpl is a java object provided in a java library so I can not modify AImpl. Could you please help me how to solve this problem? – olidev May 30 '11 at 09:24
  • Hi Blaise: I already added a file: jaxb.properties with content: javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory in my package implementation but I could not add in the domain class because those classes are in a java library! – olidev May 30 '11 at 09:33
  • Following this demo: http://bdoughan.blogspot.com/2010/12/extending-jaxb-representing-annotations.html, the binding.xml is generated automatically or manually. if it is in an automatically way, so how can I do it? thanks in advance – olidev May 30 '11 at 09:34
  • Following this tutorial: http://wiki.eclipse.org/EclipseLink/Examples/MOXy/JAXB/GenerateSchema,I tried to generate xml binding but I have this problem: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions AImpl does not have a no-arg default constructor – olidev May 30 '11 at 09:40
  • @JoesyXHN - The binding.xml file is created manually as an alternative to supplying annotations. To use MOXy you need to supply a jaxb.properties file (http://bdoughan.blogspot.com/2011/05/specifying-eclipselink-moxy-as-your.html), if you see com.sun.xml.internal.bind in the stack trace you have not configured MOXy properly. – bdoughan Jun 02 '11 at 20:12
1

If you don't have to use JAXB, perhaps you can use XStream ?

It imposes very few restrictions on what you can serialise to/from XML, and may be appropriate if you don't need JAXB specifically.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • Agreed. There are lots of libraries that serialize objects to XML. JAXB is not the most well-known of them. – Cyde Weys May 11 '11 at 13:49
  • Check out: http://bdoughan.blogspot.com/2010/10/how-does-jaxb-compare-to-xstream.html – bdoughan May 11 '11 at 14:11
  • @Cyde Weys - (Note: I lead the EclipseLink JAXB (MOXy) implementation and am a member of the JAXB (JSR-222 expert group)) I would argue that JAXB is the most well known API for converting objects to from XML. 1) An implementation is included in Java SE 6 2) It is a standard part of Java EE (binding layer for JAX-WS and JAX-RS), and included in every application server 3) Large number of questions on SO 4) Shows up in polls: http://java.dzone.com/polls/how-do-you-handle-xml-your 5) Multiple open source implementations: Metro, MOXy, JaxMe, etc – bdoughan May 11 '11 at 14:16
  • Yes, Xtream is indeed simpler than JAXB! – olidev May 11 '11 at 22:49
  • 1
    @JoseyXHN - XStream is a serializer not a mapper (http://xstream.codehaus.org/faq.html#Uses). It can be easy to get an XML representation, but not necessarily the one you have defined by your XML schema as XStream may add serialization artifacts (http://stackoverflow.com/questions/5541677/howto-prevent-xstream-from-displaying-class-string). Also it can be difficult to use XStream to map XML with namespaces (http://www.experts123.com/q/why-does-xstream-not-have-any-namespace-support.html), where it is quite easy with JAXB: http://bdoughan.blogspot.com/2010/08/jaxb-namespaces.html – bdoughan May 12 '11 at 13:47