5

The class I'm serializing:

public class LogsDTO {

    /** The logs. */
    private List<LogDTO> logs;

    /** Meta data. */
    private Meta meta = new Meta();

    // more
}

And the generated JSON:

{"LogsDTO":{"logs":[{"id":11,"archived":false}],"meta":{"totalPages":0}}}

I'd like my JSON to look like:

{"logs":[{"id":11,"archived":false}],"meta":{"totalPages":0}} 

Is there a way to annotate so that this happens?

Thanks

user2819101
  • 109
  • 1
  • 6
  • 3
    The correct standard behaviour for Jackson is the way you want it. Are you configuring a custom ObjectMapper? – Leon Apr 17 '15 at 10:52
  • @Leon Yeah the objectMapper is configured to wrap it, but I'm wondering if there was an annotation to override that at all? – user2819101 Apr 17 '15 at 10:55
  • Try using @JsonRootName and set the value to an empty string – Leon Apr 17 '15 at 10:58
  • I tried that now, it does not work. – Leon Apr 17 '15 at 11:07
  • Alternatively you should be able to construct an `ObjectWriter` from `ObjectMapper` (writer = mapper.writer()), then configure that without root name (`writer = writer.withRootName("")). I think the problem with annotation is that empty String means "just use the class name". – StaxMan Apr 20 '15 at 20:27

3 Answers3

2

@JsonRootName: class annotation used to indicate name of "wrapper" entry used for root value, if root-wrapping is enabled.

Says in jackson docs : https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations

Related Jira Task: http://jira.codehaus.org/browse/JACKSON-630 1.9 and above versions supports it.

When investigate the source code of @JsonRootName,

They commented alwaysWrap method.

/* * Optional marker property that can be defined as true to force * wrapping of root element, regardless of whether globally * "root wrapping" is enabled or not. *

* Note that value of false is taken to mean "use defaults", * and will not block use of wrapper if use is indicated by global features. * * @since 2.4 public boolean alwaysWrap() default false; */

They have a plan to activate it on v2.5

As of 2.4, one missing feature is property "alwaysWrap", which is hoped * to be added in 2.5, and would be used to force root name wrapping * for individual types.

İlker Korkut
  • 3,129
  • 3
  • 30
  • 51
0

Use Map of type Map<String, Object>. This not really nice solution uses no Annotation. I just want to show other possibility how to do avoid json wrapping:

public static void main(String[] args) {

    Map<String, Object> map = new HashMap<String, Object>();

    List<LogDTO> logs = new ArrayList<LogDTO>();
    logs.add(new LogDTO(1, true));
    logs.add(new LogDTO(2, false));
    logs.add(new LogDTO(3, true));

    map.put("logs", logs);
    map.put("meta", new Meta(33));

    Gson gson   = new GsonBuilder().create();
    String json = gson.toJson(map);
    LogsDTO dto = gson.fromJson(json, LogsDTO.class);

    System.out.println(json);
    System.out.println(dto);

}

produces:

{
    "meta":{
       "id":33
    },
    "logs":[
       {
          "id":1,
          "archived":true
       },
       {
          "id":2,
          "archived":false
       },
       {
          "id":3,
          "archived":true
       }
    ]
 }

and

LogsDTO [logs=[Log [id=1, archived=true], Log [id=2, archived=false], Log [id=3, archived=true]], meta=Meta [id=33]]
alex
  • 8,904
  • 6
  • 49
  • 75
0

I solved it using a custom serializer,turning off global wrapping off, and turning on wrapping per class. It seems that even when you turn global wrapping off, Jackson adds wrapping for list elements of a class that has wrapping. One difference from your code is that for me the list was wrapped by its own class. It was something like this:

    @JsonTypeName("interface") 
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)  // wrapping per class instead of global in the mapper
    public class InterfaceDTO
    {        
        private InterfaceIpListDTO interfaceIpListDTO; // The list property for which I want to turn off wrapping

        @JsonSerialize(using = com.tufin.securetrack.integration.rest.facade.serializer.InterfaceIPListWithoutWrapperNameSerializer.class)  // Gonen
        public InterfaceIpListDTO getInterfaceIpListDTO() {
            return interfaceIpListDTO;
        }
}

public class InterfaceIPListWithoutWrapperNameSerializer extends JsonSerializer<InterfaceIpListDTO>{
    @Override
    public void serialize(InterfaceIpListDTO interfaceIpListDTO, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeStartArray();
        for (InterfaceIpDTO interfaceIpDTO : interfaceIpListDTO.getInterfaceIpDTOs()) {
            jsonGenerator.writeObject(interfaceIpDTO);
        }
        jsonGenerator.writeEndArray();
    }    
}
Gonen I
  • 5,576
  • 1
  • 29
  • 60