Asturio
Asturio

Reputation: 532

Unmarshal JSON String to some "Object" using MOXy

I'm trying to write a method to pretty print JSON Strings, using MOXy. So what I want is to have a method like this

public String formatJson(String input) { ... }

I think the way to go is to parse the String to a generic Object (Something like a SAX-Document, or the kind), and then marshal this Object back to JSON using some formatting properties (which is not the problem :-) ).

The Problem is, when reading the JSON-String-Input, I don't have a Class to unmarshal to (as I want the method to be as generic as possible).

[edited] GSON and Jackson examples removed, as only MOXy is the question.

I tried this:

public static String toFormattedJson(final String jsonString) {
    String formatted;
    try {
        JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] { JAXBElement.class }, null);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setProperty(MEDIA_TYPE, MediaType.APPLICATION_JSON);
        unmarshaller.setProperty(JSON_INCLUDE_ROOT, true);
        StringReader reader = new StringReader(jsonString);
        Object element = unmarshaller.unmarshal(reader); // Exception is thrown here
        formatted = toFormattedJson(element);
    } catch (final JAXBException e) {
        formatted = jsonString;
    }
    return formatted;
}

but I get an this Exception

javax.xml.bind.UnmarshalException - with linked exception: [java.lang.ClassCastException: org.eclipse.persistence.internal.oxm.record.SAXUnmarshallerHandler cannot be cast to org.eclipse.persistence.internal.oxm.record.UnmarshalRecord]

So how can I read an arbitrary JSON String in to a Java Object, if I don't have any Class for that specific String?

Update: This is the method used to format an Object into a JSON String:

private static String toFormattedJson(Object obj) {
    String result;
    try (StringWriter writer = new StringWriter()) {
        final JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] { obj.getClass() }, null);
        final Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.setProperty(JAXBContextProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
        marshaller.setProperty(MarshallerProperties.JSON_REDUCE_ANY_ARRAYS, false);
        marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false);
        marshaller.setProperty(JAXBContextProperties.JSON_WRAPPER_AS_ARRAY_NAME, false);
        marshaller.setProperty(JAXBContextProperties.JSON_INCLUDE_ROOT, true);
        marshaller.marshal(obj, writer);
        writer.flush();
        result = writer.toString();
    } catch (JAXBException | IOException e) {
        result = obj.toString();
    }
    return result;
}

And using now the code from below (Martin Vojtek), when I try to format

String jsonString = "{\"p\" : [ 1, 2, 3]}";

I get:

{
   "p" : "1"
}

Upvotes: 3

Views: 3435

Answers (1)

Martin Vojtek
Martin Vojtek

Reputation: 391

You can specify String as the unmarshal target:

public static void main(String[] args) {
        System.out.println(toFormattedJson("[{\"test\":true}, \"ok\", [\"inner\",1]]"));
}

public static String toFormattedJson(final String jsonString) {
    String formatted;
    try {
        JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] { JAXBElement.class }, null);
        System.out.println("jaxbContext="+jaxbContext);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setProperty(JAXBContextProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
        unmarshaller.setProperty(JAXBContextProperties.JSON_INCLUDE_ROOT, true);
        StringReader reader = new StringReader(jsonString);
        Object element = unmarshaller.unmarshal(new StreamSource(reader), String.class);
        formatted = toFormattedJsonElement(element);
    } catch (final JAXBException e) {
        e.printStackTrace();
        formatted = jsonString;
    }
    return formatted;
}

private static String toFormattedJsonElement(Object element) {
    return "formatted: " + element;
}

Upvotes: 2

Related Questions