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
andcustomizing 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
How to Provide Pagination Support to a Jtable in Swing
How to Find the Index of an Element in an Int Array
Differencebetween Synchronized on Lockobject and Using This as the Lock
Access "This" from Java Anonymous Class
Reverse Hashmap Keys and Values in Java
What Java Ftp Client Library Should I Use
How to Remove Accents from a Unicode String
Cannot Rerun Java JPAckage Installer If Already Installed, Second Time Just Exits Without Warning
Configuration Using Annotation @Springbootapplication
Do Not Use System.Out.Println in Server Side Code
Using Spring Resttemplate in Generic Method with Generic Parameter
How to Load Files into My Java Application
Removing All the Rows of Defaulttablemodel
Create File with Given Size in Java
How to Check If a String Starts with One of Several Prefixes