7

I am trying to json-serialize a class MyRootClass with a property that is a collection of elements of a second class MyClass:

public class MyRootClass {
   private List<MyInterface> list = new ArrayList<MyInterface>();
   // getter / setter
}

public class MyClass implements MyInterface {
   private String value = "test";    
   // getter / setter
}

The following code:

MyRootClass root = new MyRootClass();
root.getList().add(new MyClass());
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(System.out, root);

Generates this JSON output:

{"list": [ {"value":"test"} ] }

instead of what I need, every object in the collection serialized with a name:

{"list": [ {"myclass": {"value":"test"}} ] }

Is there any way to achieve it using Jackson? I thought about writing a custom serializer, but I've not found anything related to a collection of objects.

Guido
  • 46,642
  • 28
  • 120
  • 174

3 Answers3

7

It depends on what exactly you want to achieve with name; but yes, this can be done if you want to include 'myclass' here is type information (or can act as if it was used; if you do not use Jackson to deserialize it does not really matter).

If so, you would annotate MyInterface:

@JsonTypeInfo(use=Id.NAME, include=As.WRAPPER_OBJECT)

and MyClass with:

@JsonTypeName("myclass")

(if you don't define that, default name would be unqualified name of the class)

@JsonTypeInfo above defines that type name is to be used (instead of Java class name, or custom method), and inclusion is done by using a wrapper object (alternatives are wrapper array and as-property)

So you should then see expected output.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
StaxMan
  • 113,358
  • 34
  • 211
  • 239
1

What you want is to include the name of the class in the output. This is not how json serializers behave - they include only field names.

What you can do is to introduce another class.

class MyClass implements MyInterface {
    private MyOtherClass myclass;
}

class MyOtherClass {
    private String value = "test";
}
Guido
  • 46,642
  • 28
  • 120
  • 174
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • Thank you. That is what I was trying to avoid, because I'm using a legacy class model (I can not modify it), but I need to obtain that JSON format (also a restriction imposed by a third party system). – Guido Oct 17 '10 at 17:38
  • 1
    you can wrap the legacy class model for the purpose of serialization. – Bozho Oct 17 '10 at 17:50
1

You can use a helper object like this:

public static class MyObject {
    public int i;
    public MyObject(int i) { this.i = i; }
    public MyObject() {}
}

@JsonDeserialize(contentAs=MyObject.class)
public static class MyHelperClass extends ArrayList<MyObject> {

}

@Test
public void testCollection() throws JsonGenerationException, JsonMappingException, IOException {
    final Collection<MyObject> l = new ArrayList<MyObject>();
    l.add(new MyObject(1));
    l.add(new MyObject(2));
    l.add(new MyObject(3));

    final ObjectMapper mapper = new ObjectMapper();

    final String s = mapper.writeValueAsString(l);
    final Collection<MyObject> back = mapper.readValue(s, MyHelperClass.class);

}
Joscha
  • 4,643
  • 1
  • 27
  • 34