2

Using MOXy I'm trying to marshal a java class like this to JSON:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Request {
   String method;
   @XmlAnyElement(lax=true)
   Object[] arguments;
}

I would expect something like:

{
    "method": "test",
    "arguments": ["a", "b"]
}

but the JSON output results to:

{
    "method": "test",
    "value": ["a", "b"]
}

Where is the value coming from?

If I put a @XmlElementWrapper over the arguments field, it gets even worse:

{
    "method":"test",
    "arguments":"a""value":["b"]
}

My JUnit TestCase looks like this:

import static org.junit.Assert.assertEquals;

import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.*;
import javax.xml.bind.annotation.*;

import org.junit.Test;

public class JsonRequestTest {

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Request {
    String method;

    @XmlAnyElement(lax=true)
    Object[] arguments;
} // InvocationRequest

@Test
public void testObjectArray() throws JAXBException {
    System.setProperty(JAXBContext.class.getName(), "org.eclipse.persistence.jaxb.JAXBContextFactory");
    Map<String, Object> props= new HashMap<String, Object>();
    props.put("eclipselink.media-type", "application/json");
    props.put("eclipselink.json.include-root", false);

    JAXBContext ctx = JAXBContext.newInstance(new Class<?>[]{Request.class},props);
    Marshaller m = ctx.createMarshaller();
    StringWriter writer = new StringWriter();
    Request req = new Request(); 
    req.method="test";
    req.arguments = new Object[]{"a","b"};
    m.marshal(req, writer);
    assertEquals("{\"method\":\"test\", \"arguments\":[\"a\",\"b\"]}", writer.toString());
}
} // class JsonRequestTest
siddhadev
  • 16,501
  • 2
  • 28
  • 35
  • In the case of string arguments, I was able to get, what I need, by adding @XmlElements(@XmlElement(name="arguments")) to the arguments. This does not work however, if I use non-string arguments, i.e. some annotated bean. – siddhadev Nov 19 '13 at 16:05

1 Answers1

1

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

TL:DR

You can set the following property to override the value key.

    props.put(MarshallerProperties.JSON_VALUE_WRAPPER, "arguments");

Full Test Case

Below is the full working test case. In addition to setting the property I removed an extra space you had in your control document to get the test to pass.

import static org.junit.Assert.assertEquals;

import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.*;
import javax.xml.bind.annotation.*;

import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.junit.Test;

public class JsonRequestTest {

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class Request {
        String method;

        @XmlAnyElement(lax = true)
        Object[] arguments;
    } // InvocationRequest

    @Test
    public void testObjectArray() throws JAXBException {
        System.setProperty(JAXBContext.class.getName(),
                "org.eclipse.persistence.jaxb.JAXBContextFactory");
        Map<String, Object> props = new HashMap<String, Object>();
        props.put("eclipselink.media-type", "application/json");
        props.put("eclipselink.json.include-root", false);
        props.put(MarshallerProperties.JSON_VALUE_WRAPPER, "arguments");

        JAXBContext ctx = JAXBContext.newInstance(
                new Class<?>[] { Request.class }, props);
        Marshaller m = ctx.createMarshaller();
        StringWriter writer = new StringWriter();
        Request req = new Request();
        req.method = "test";
        req.arguments = new Object[] { "a", "b" };
        m.marshal(req, writer);
        assertEquals("{\"method\":\"test\",\"arguments\":[\"a\",\"b\"]}",
                writer.toString());
    }

} // class JsonRequestTest

@XmlElementWrapper Issue

I have opened the following bug for the issue with @XmlElementWrapper:

Charles Follet
  • 827
  • 1
  • 10
  • 28
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • Eclipse implementation. Is it possible to doe the dame without org.eclipse ? – ses Nov 19 '13 at 20:08
  • @ses - I'm not sure what you mean by your comment, can you expand on it? – bdoughan Nov 19 '13 at 20:09
  • I mean what if not use this package (org.eclipse) and MarshallerProperties that provides jaxb-implementation. But use default one that comes with java. Then, is it possible to do the same? I guess not because I could not find.. there javax.json package in java 6, but only javax.xml. – ses Nov 19 '13 at 20:16
  • @ses - The JAXB reference implementation doesn't offer native JSON-binding. To produce JSON with it you need to use an external library like Jettison: http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison.html – bdoughan Nov 19 '13 at 20:43
  • Unfortunately the link to `EclipseLink JAXB (MOXy)` is broken (and I couldn't find a new one) – yair Sep 08 '15 at 18:57