5

I'm using spring-boot 1.3.3 and trying to figure out how to have root names on JSON serialization. For example, I would like...

{ stores: [
  {
    id: 1,
    name: "Store1"
  },
  {
    id: 2,
    name: "Store2"
  }]
}

but instead I am getting

[
  {
    id: 1,
    name: "Store1"
  },
  {
    id: 2,
    name: "Store2"
  }
]

I've been looking at @JsonRootName and customizing the Jackson2ObjectMapperBuilder config but to no avail. In grails, this is pretty simple with Json Views and I was trying also to see how that translated directly to spring-boot but still can't seem to figure it out.

I realize this is similar to this question but I feel like in the context of Spring (boot) it might be applied differently and would like to know how.

Community
  • 1
  • 1
Gregg
  • 34,973
  • 19
  • 109
  • 214
  • Possible duplicate of [How to wrap a List as top level element in JSON generated by Jackson](http://stackoverflow.com/questions/16022795/how-to-wrap-a-list-as-top-level-element-in-json-generated-by-jackson) – Nicolas Labrot Apr 20 '16 at 14:23
  • Possibly, but in the context of Spring (boot) oft times it is different / easier / etc. So still would like to know if there is actually a "spring" way of doing this. – Gregg Apr 20 '16 at 15:33
  • Not to my knowledge an easy way other than wrapping – Nicolas Labrot Apr 20 '16 at 16:26

4 Answers4

15

SpringBoot use Jackson as json tool, so this will work well:

@JsonTypeName("stores")
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public class stores { 
    ...
}
ℛɑƒæĿᴿᴹᴿ
  • 4,983
  • 4
  • 38
  • 58
lizhipeng
  • 661
  • 7
  • 6
14

Solution 1: Jackson JsonRootName

I've been looking at @JsonRootName and

customizing the Jackson2ObjectMapperBuilder config but to no avail

What are your errors with @JsonRootName and the Jackson2ObjectMapperBuilder?

This works in my Spring Boot (1.3.3) implementation:

Jackson configuration Bean

@Configuration
public class JacksonConfig {
    @Bean
    public Jackson2ObjectMapperBuilder jacksonBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.featuresToEnable(SerializationFeature.WRAP_ROOT_VALUE); 
        // enables wrapping for root elements
        return builder;
    }
}

Reference: Spring Documentation - Customizing the Jackson ObjectMapper

Add @JsonRootElement to your response entity

@JsonRootName(value = "lot")
public class LotDTO { ... }

Json Result for HTTP-GET /lot/1

{
  "lot": {
    "id": 1,
    "attributes": "...",
    }
}

At least this works for a response with one object.

I haven't figured out how to customize the root name in a collection. @Perceptions' answer might help How to rename root key in JSON serialization with Jackson


EDIT

Solution 2: Without Jackson configuration

Since I couldn't figure out how to customize the json root name in a collection with Kackson

I adapted the answer from @Vaibhav (see 2):

Custom Java Annotation

@Retention(value = RetentionPolicy.RUNTIME)
public @interface CustomJsonRootName {
    String singular(); // element root name for a single object
    String plural(); // element root name for collections
}

Add annotation to DTO

@CustomJsonRootName(plural = "articles", singular = "article")
public class ArticleDTO { // Attributes, Getter and Setter }

Return a Map as result in Spring Controller

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Map<String, List<ArticleDTO>>> findAll() {
  List<ArticleDTO> articles = articleService.findAll();
  if (articles.isEmpty()) {
      return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  }
  Map result = new HashMap();
  result.put(ArticleDTO.class.getAnnotation(CustomJsonRootName.class).plural(), articles);
  return new ResponseEntity<>(result, HttpStatus.OK);
}
Community
  • 1
  • 1
Pascal
  • 1,984
  • 1
  • 21
  • 25
3

I found a really easy way to do that. Instead of returning an

ArrayList<Object>

of your objects to the frontend, just return a

HashMap<String, ArrayList<Object>>

and initilize the list of your objects and the according HashMap in the following way:

List<Object> objectList = new ArrayList<>();

... fill your objectList with your objects and then:

HashMap<String, ArrayList<Object>> returnMap = new HashMap<>();
returnMap.put("lot", objectList);
return returnMap;

The head of your controller method looks someting like this:

@ResponseBody
@RequestMapping(value = "/link", method = RequestMethod.POST)
public HashMap<String, List<Object>> processQuestions(@RequestBody List<incomingObject> controllerMethod) {

This will result in the desired JSON without further definitions through annotations or whatever.

Maxinator
  • 81
  • 4
  • I actually had moved to this exact model with the only exception being that I created an annotation to hold the pluralized version of the root name so I can pull it off as the key in the map instead of a hardcoded string. – Gregg Sep 24 '16 at 16:24
0

I think the easiest way would be to return Map <String, Object>. Just put the key as 'stores' and object as stores object.

ex-

Map<String, Object> response = new LinkedHashMap<String, Object>();


response.put("stores", stores)
ts178
  • 321
  • 1
  • 6
  • 20