Jackson dynamic property names
Using a custom JsonSerializer
.
public class Response {
private String status;
private String error;
@JsonProperty("p")
@JsonSerialize(using = CustomSerializer.class)
private Object data;
// ...
}
public class CustomSerializer extends JsonSerializer<Object> {
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeObjectField(value.getClass().getName(), value);
jgen.writeEndObject();
}
}
And then, suppose you want to serialize the following two objects:
public static void main(String... args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Response r1 = new Response("Error", "Some error", 20);
System.out.println(mapper.writeValueAsString(r1));
Response r2 = new Response("Error", "Some error", "some string");
System.out.println(mapper.writeValueAsString(r2));
}
The first one will print:
{"status":"Error","error":"Some error","p":{"java.lang.Integer":20}}
And the second one:
{"status":"Error","error":"Some error","p":{"java.lang.String":"some string"}}
I have used the name p
for the wrapper object since it will merely serve as a p
laceholder. If you want to remove it, you'd have to write a custom serializer for the entire class, i.e., a JsonSerializer<Response>
.
Dynamic property name for Jackson serialization
Attribute values for Annotations must be constant, so you cannot change that. I'm not sure I see a problem here. Why would your solution below not work? The @JsonProperty
just tells the ObjectMapper
what the name of the Json field should be.
public class Something {
@JsonProperty(value = "id")
Identifier identifier
// other properties
}
If you serialized one of these objects it would come out to something this:
{
"id": FOO,
...
}
Without having the value - "id"
for @JsonProperty
it would just use the field name:
{
"identifier": FOO,
...
}
Jackson has a bunch of ways to customize it serializes and deserializes object. If you want the serialization to have more information (say if you add any fields to your Enum) or want to change how it was serialized there are ways to do that.. For Example, if you wanted the Enum to be serialized as an Object in Jackson 2.1.2 @JsonFormat
you could do:
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Identifier {...}
EDIT:
I don't think serializing the data into the format described above necessarily makes sense as you are not really representing the object as JSON anymore as you are representing it as a different object. You already have a field on the object that discriminates what the Identifier
for that object is and you can use that anywhere else. If you really wanted to serialize the data into the way you have described above, I believe you would have to implement your own JsonSerializer
for that type like this (at least for Jackson 2.1):
public SomethingSerializer extends JsonSerializer<Something> {
// Define serialization methods
...
}
And then extend SimpleModule, add the serializer, and register the module with ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
testModule.addSerializer(new SomethingSerializer());
mapper.registerModule(testModule);
Example adapted from JacksonHowToCustomSerializers
How to use dynamic property names for a Json object
You can use JsonAnySetter JsonAnyGetter annotations. Behind you can use Map
instance. In case you have always one-key-object
you can use Collections.singletonMap
in other case use HashMap
or other implementation. Below example shows how easy you can use this approach and create as many random key
-s as you want:
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
public class JsonApp {
public static void main(String[] args) throws Exception {
DynamicJsonsFactory factory = new DynamicJsonsFactory();
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(factory.createUser("Vika")));
System.out.println(mapper.writeValueAsString(factory.createPhone("123-456-78-9")));
System.out.println(mapper.writeValueAsString(factory.any("val", "VAL!")));
}
}
class Value {
private Map<String, String> values;
@JsonAnySetter
public void put(String key, String value) {
values = Collections.singletonMap(key, value);
}
@JsonAnyGetter
public Map<String, String> getValues() {
return values;
}
@Override
public String toString() {
return values.toString();
}
}
class DynamicJsonsFactory {
public Value createUser(String name) {
return any("name", name);
}
public Value createPhone(String number) {
return any("phone", number);
}
public Value any(String key, String value) {
Value v = new Value();
v.put(Objects.requireNonNull(key), Objects.requireNonNull(value));
return v;
}
}
Above code prints:
{"name":"Vika"}
{"phone":"123-456-78-9"}
{"val":"VAL!"}
Dynamic change of JsonProperty name using Jackson java library
You can provide name in constructor and use JsonAnyGetter
. Below solution:
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
ResponseEntity entity = new ResponseEntity("dynList",
Collections.singletonList(Collections.singletonMap("key", "value1")));
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
System.out.println(mapper.writeValueAsString(entity));
}
}
class ResponseEntity implements Serializable {
private static final long serialVersionUID = 1L;
private int total_record_count;
private int filtered_record_count;
private String propertyName;
@JsonIgnore
private List<Map<String, Object>> entityList;
public ResponseEntity(String propertyName, List<Map<String, Object>> entityList) {
this.propertyName = propertyName;
this.entityList = entityList;
this.filtered_record_count = entityList.size();
}
@JsonAnyGetter
public Map<String, Object> otherProperties() {
return Collections.singletonMap(propertyName, entityList);
}
// other methods
}
prints:
{
"total_record_count" : 0,
"filtered_record_count" : 1,
"dynList" : [ {
"key" : "value1"
} ]
}
deserialize json using jackson with dynamic field name
You could deserialize the JSON as a Map<String, Object>
:
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> typeReference =
new TypeReference<HashMap<String, Object>>() {};
Map<String, Object> data = mapper.readValue(json, typeReference);
Or you could use @JsonAnySetter
:
public class Data {
private String id;
private Map<String, Object> unknownFields = new HashMap<>();
// Getters and setters (except for unknownFields)
@JsonAnySetter
public void setUnknownField(String name, Object value) {
unknownFields.put(name, value);
}
}
If you know the possible names of the property, you could use the @JsonAlias
annotation, which was introduced in Jackson 2.9:
public class Data {
private String id;
@JsonAlias({ "onePossibleName", "anotherPossibleName" })
private Foo something;
// Getters and setters
}
How to map a dynamic json property name with jackson for spring rest template request
If you are having id
dynamically generated i will recommend to use Map
public class RequestData {
private Map<String, String> slug;
public Map<String, List<String>> getSlug(){
return properties;
}
public void add(String property, String List<String> value){
properties.put(property, value);
}
}
Related Topics
JPA Query.Getresultlist() - Use in a Generic Way
Access "This" from Java Anonymous Class
How to Save User Settings in Java Application
Using Javafx.Beans Properties in Model Classes
Java How Expensive Is a Method Call
JSON Parameter in Spring MVC Controller
Extract Integer Part in String
Programmatically Import Ca Trust Cert into Existing Keystore File Without Using Keytool
String S = New String("Xyz"). How Many Objects Has Been Made After This Line of Code Execute
How to Set an Environment Variable at Runtime from Java
Java Lambda Returning a Lambda
Copy Entire Directory Contents to Another Directory