Use Class Name as Root Key for JSON Jackson Serialization

How to rename root key in JSON serialization with Jackson

Well, by default Jackson uses one of two annotations when trying to determine the root name to be displayed for wrapped values - @XmlRootElement or @JsonRootName. It expects this annotation to be on the type being serialized, else it will use the simple name of the type as the root name.

In your case, you are serializing a list, which is why the root name is 'ArrayList' (simple name of the type being serialized). Each element in the list may be of a type annotated with @JsonRootName, but the list itself is not.

When the root value you are trying to wrap is a collection then you need some way of defining the wrap name:

Holder/Wrapper Class

You can create a wrapper class to hold the list, with an annotation to define the desired property name (you only need to use this method when you do not have direct control of the ObjectMapper/JSON transformation process):

class MyInterfaceList {
@JsonProperty("rootname")
private List<MyInterface> list;

public List<MyInterface> getList() {
return list;
}

public void setList(List<MyInterface> list) {
this.list = list;
}
}

final List<MyInterface> lists = new ArrayList<MyInterface>(4);
lists.add(new MyImpl(1L, "test name"));
MyInterfaceList listHolder = new MyInterfaceList();
listHolder.setList(lists);
final String json = mapper.writeValueAsString(listHolder);

Object Writer

This is the preferable option. Use a configured ObjectWriter instance to generate the JSON. In particular, we are interested in the withRootName method:

final List<MyInterface> lists = new ArrayList<MyInterface>(4);
lists.add(new MyImpl(1L, "test name"));
final ObjectWriter writer = mapper.writer().withRootName("rootName");
final String json = writer.writeValueAsString(lists);

SerializationFeature.WRAP_ROOT_VALUE as annotation in jackson json

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Test2 {
public static void main(String[] args) throws JsonProcessingException {
UserWithRoot user = new UserWithRoot(1, "John");

ObjectMapper objectMapper = new ObjectMapper();

String userJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);

System.out.println(userJson);
}

@JsonTypeName(value = "user")
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
private static class UserWithRoot {
public int id;
public String name;
}
}

@JsonTypeName and @JsonTypeInfo together make it possible.

Result:

{
"user" : {
"id" : 1,
"name" : "John"
}
}

Jackson serialize nested attribute with same name

Mapping starts from the root of JSON so the correct class definition for this JSON will be this

public class Demo {
@JsonProperty("user")
private DemoUser user;
}
public class DemoUser {
@JsonProperty("user")
private User user;

@JsonProperty("address")
private Address address;
}

If you want to keep the class as it is and only want to use the inner 'user', you can do it using JsonNode like this

ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readValue(jsonString, JsonNode.class);
Demo demo = mapper.readValue(node.at("/user").toString(), Demo.class);

The at() method accepts the JSON path expression which is the path to a particular node in the JSON.

Here, "/user" means it will find the node user from the root of JSON and will return it.

Similarly,

node.at("/user/user").toString();

will give you

{
"name":"Demo",
"age":25,
"eail":"demo@abc.com"
}

spring-boot json root name

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);
}

Keep root element name in JSON generated by Jackson

If you put an @XmlRootElement(name="EvaluationType") at the top of your class definition it should provide the name. Or are you stating that you cannot add an @XmlRootElement to your class for some reason?

Update

Jackson 2 will use the class name for the JSON key if there is no @XmlRootElement available. Jackson 2 requires a new set of maven dependencies, specifically:

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.1.3</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.1.2</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.1.3</version>
</dependency>


Related Topics



Leave a reply



Submit