JSON parsing using Jettison

prem picture prem · Mar 29, 2012 · Viewed 11.7k times · Source

I am trying to parse JSON object using Jettison. This the code I'm using

String s ="{\"appUsage\":[{\"appName\":\"ANDROID\",\"totalUsers\":\"0\"},{\"appName\":\"IOS\",\"totalUsers\":\"4\"}]}";

JSONObject obj = new JSONObject(s);

ArrayList<MiAppUsage> l1 =  (ArrayList<MiAppUsage>) jsonParser(ArrayList.class, obj);

public static Object jsonParser(Class c, JSONObject obj)
            throws JSONException, XMLStreamException, JAXBException {
        JAXBContext jc = JAXBContext.newInstance(c);
        Configuration config = new Configuration();
        MappedNamespaceConvention con = new MappedNamespaceConvention(config);
        XMLStreamReader xmlStreamReader = new MappedXMLStreamReader(obj, con);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        ArrayList<MiAppUsage>customer = (ArrayList<MiAppUsage>) unmarshaller.unmarshal(xmlStreamReader);
        return customer;
    }

I'm getting this error

Exception in thread "main" javax.xml.bind.UnmarshalException - with linked exception: [javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"appUsage"). Expected elements are (none)] at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(Unknown Source) at com.json.UnmarshalDemo.jsonParser(UnmarshalDemo.java:56) at com.json.UnmarshalDemo.main(UnmarshalDemo.java:33) Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"appUsage"). Expected elements are (none) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXStreamConnector.handleStartElement(Unknown Source) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(Unknown Source) ... 4 more Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"appUsage"). Expected elements are (none) ... 14 more

How to resolve this problem

Answer

bdoughan picture bdoughan · Mar 29, 2012

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

If you are ultimately looking for a way to interact with JSON using a JAXB (JSR-222) implementation, then the following is how it can be done using MOXy. Jettison is an interesting library but there are some issue you will encounter using it:

Demo

Only the standard Java SE APIs are used. There are two MOXy specific properties that need to be set on the Unmarshaller: "eclipselink.media-type" to specify "application/json", and "eclipselink.json.include-root" to indicate that there is no root node.

package forum9924567;

import java.io.StringReader;
import java.util.ArrayList;

import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    private static final String s ="{\"appUsage\":[{\"appName\":\"ANDROID\",\"totalUsers\":\"0\"},{\"appName\":\"IOS\",\"totalUsers\":\"4\"}]}";

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setProperty("eclipselink.media-type", "application/json");
        unmarshaller.setProperty("eclipselink.json.include-root", false);
        StreamSource json = new StreamSource(new StringReader(s));
        Root root = unmarshaller.unmarshal(json, Root.class).getValue();

        ArrayList<MiAppUsage> customer = root.appUsage;
        for(MiAppUsage miAppUsage : customer) {
            System.out.print(miAppUsage.appName);
            System.out.print(' ');
            System.out.println(miAppUsage.totalUsers);
        }
    }

}

Root

I had to introduce this class to meet your use case. We could eliminate this class if your JSON looked like: [{"appName":"ANDROID","totalUsers":"0"},{"appName":"IOS","totalUsers":"4"}].

package forum9924567;

import java.util.ArrayList;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    ArrayList<MiAppUsage> appUsage;

}

MiAppUsage

package forum9924567;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class MiAppUsage {

    String appName;
    int totalUsers;

}

jaxb.properties

To specify MOXy as your JAXB provider you need to add a file called java.properties with the following entry in the same package as your domain classes:

javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory

Output

The following is the output from running the demo code:

ANDROID 0
IOS 4

For More Information