Reputation: 2168
I have the following class:
public class Message {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
When converting the instance to JSON using Jackson by default I get:
{"text":"Text"}
I would like to get:
{"message":{"text":"Text"}}
Is there any JAXB / Jackson annotation I can use to achieve my goal?
As a workaround, I can wrap my class with another class:
public class MessageWrapper {
private Message message;
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
}
or a more generic solution:
public class JsonObjectWrapper<T> {
/**
* Using a real map to allow wrapping multiple objects
*/
private Map<String, T> wrappedObjects = new HashMap<String, T>();
public JsonObjectWrapper() {
}
public JsonObjectWrapper(String name, T wrappedObject) {
this.wrappedObjects.put(name, wrappedObject);
}
@JsonAnyGetter
public Map<String, T> any() {
return wrappedObjects;
}
@JsonAnySetter
public void set(String name, T value) {
wrappedObjects.put(name, value);
}
}
Which can be used like so:
Message message = new Message();
message.setText("Text");
JsonObjectWrapper<Message> wrapper = new JsonObjectWrapper<Message>("message", message);
Is there any JAXB / Jackson annotation I can use to achieve my goal?
Thanks.
Upvotes: 23
Views: 32805
Reputation: 3328
You could wrap your object with a map
Message message = new Message();
message.setText("Text");
new ObjectMapper().writeValueAsString(Map.of("message", message));
Upvotes: 0
Reputation: 46
I have created a small jackson module that contains a @JsonWrapped annotation, that solves the problem. See here for the code: https://github.com/mwerlitz/jackson-wrapped
Your class would then look like:
public class Message {
@JsonWrapped("message")
private String text;
}
Upvotes: 2
Reputation: 351
With Jackson 2.x use can use the following to enable wrapper without adding addition properties in the ObjectMapper
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
@JsonTypeName(value = "student")
public class Student {
private String name;
private String id;
}
Upvotes: 35
Reputation: 3654
Provided you don't mind the json having a capital m
in message
, then the simplest way to do this is to annotate your class with @JsonTypeInfo
.
You would add:
@JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME)
public class Message {
// ...
}
to get {"Message":{"text":"Text"}}
Upvotes: 4
Reputation: 116620
On workaround: you don't absolutely need those getters/setters, so could just have:
public class MessageWrapper {
public Message message;
}
or perhaps add convenience constructor:
public class MessageWrapper {
public Message message;
@JsonCreator
public MessageWrapper(@JsonProperty("message") Message m) {
message = m;
}
}
There is a way to add wrapping too; with 1.9 you can use SerializationConfig.Feature.WRAP_ROOT_ELEMENT
and DeserializationConfig.Feature.UNWRAP_ROOT_ELEMENT
. And if you want to change the wrapper name (by default it is simply unqualified class name), you can use @JsonRootName
annotation
Jackson 2.0 adds further dynamic options via ObjectReader
and ObjectWriter
, as well as JAX-RS annotations.
Upvotes: 17
Reputation: 7546
If using spring, then in application.properties
file add following:-
spring.jackson.serialization.WRAP_ROOT_VALUE=true
And then use @JsonRootName
annotation on any of your class that you wish to serialize. e.g.
@JsonRootName("user")
public class User {
private String name;
private Integer age;
}
Upvotes: 1
Reputation: 949
A Simpler/Better way to do it:
@JsonRootName(value = "message")
public class Message { ...}
then use
new ObjectMapper().configure(SerializationFeature.WRAP_ROOT_VALUE, true).writeValueAs...
Upvotes: 1
Reputation: 7844
It was sad to learn that you must write custom serialization for the simple goal of wrapping a class with a labeled object. After playing around with writing a custom serializer, I concluded that the simplest solution is a generic wrapper. Here's perhaps a more simple implementation of your example above:
public final class JsonObjectWrapper {
private JsonObjectWrapper() {}
public static <E> Map<String, E> withLabel(String label, E wrappedObject) {
HashMap<String, E> map = new HashMap<String, E>();
map.put(label, wrappedObject);
return map;
}
}
Upvotes: 4