How to Use Different Jsonproperty on Serialize & Deserialize Using Jackson API

Different names of JSON property during serialization and deserialization

Just tested and this works:

public class Coordinates {
byte red;

@JsonProperty("r")
public byte getR() {
return red;
}

@JsonProperty("red")
public void setRed(byte red) {
this.red = red;
}
}

The idea is that method names should be different, so jackson parses it as different fields, not as one field.

Here is test code:

Coordinates c = new Coordinates();
c.setRed((byte) 5);

ObjectMapper mapper = new ObjectMapper();
System.out.println("Serialization: " + mapper.writeValueAsString(c));

Coordinates r = mapper.readValue("{\"red\":25}",Coordinates.class);
System.out.println("Deserialization: " + r.getR());

Result:

Serialization: {"r":5}
Deserialization: 25

How to use different JSONProperty on Serialize & Deserialize using Jackson API?

Googling around i have found solution for it.
We can use @JsonAlias using latest Jackson API (2.9.7)
So in my case i wanted this alias for deserialization @JsonAlias(value={"author","authorList"}).

JSON Jackson parse different keys into same field

Different serialization/deserialization names with java jackson

You're on the right track. Here's an example of this working with a test JSON document.

public static class MyClass {
private String defaultReference;

@JsonProperty(value = "default_reference")
public void setDefaultReference(String defaultReference) {
this.defaultReference = defaultReference;
}

@JsonProperty(value = "defaultReference")
public String getDefaultReference() {
return defaultReference;
}

public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
MyClass instance = objectMapper.readValue("{\"default_reference\": \"value\"}", MyClass.class);
objectMapper.writeValue(System.out, instance);
// Output: {"defaultReference":"value"}
}
}

Jackson: Serialize/deserialize with different property name

Try using a different JsonProperty annotation for the getter and the setter. E.g.

@JsonProperty("tagnameOpc")
void setTagName(String name)

@JsonProperty("tagName")
String getTagName()

If that doesn't work try with an extra setter

@JsonIgnore
void setTagName(String name)

@JsonProperty("tagnameOpc")
void setTagNameOpc(String name) {
setTagName(name);
}

@JsonProperty("tagName")
String getTagName()

Different @JsonProperty config for READ and WRITE on same field?

You could use the getters and setters to get that extra customization. The get will act as READ and the set as WRITE. Note that you don't need the access properties or the field level annotation:

    public abstract class StandingMixIn {
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
Integer positionNumber;

// No annotation on the field
String positionText;

@JsonProperty(value = "positionText")
public String getPositionText() {
return positionText;
}

@JsonProperty(value = "position")
public void setPositionText(String positionText) {
this.positionText = positionText;
}
}

JSON Jackson parse different keys into same field

Well, as only deserialization is your concern, @JsonAlias introduced in 2.9 is perfect for this situation. You can do something like this:

@JsonAlias({"cover_asset", "asset"})
private Asset asset;

@JsonAlias docs:

Annotation that can be used to define one or more alternative names
for a property, accepted during deserialization as alternative to the
official name. Alias information is also exposed during POJO
introspection, but has no effect during serialization where primary
name is always used.

Note: Make sure you update all related dependencies(annotations, core, databind) if you are using them. Updating just annotations without others threw me runtime error.

Specifying different JSON property names according to API version with Jackson

You can create a custom annotation to define a list of possible version of property name for a field and create a custom JacksonAnnotationIntrospector to resolve the property name according to a given version.

The custom annotation will look likes:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface VersioningProperties {
Property[] value();

@interface Property {
String version();
String value();
}
}

and the custom JacksonAnnotationIntrospector will look like:

public class VersioningPropertiesIntrospector {
private String version;

public VersioningPropertiesIntrospector(String version) {
this.version = version;
}

@Override
pubilc PropertyName findNameForSerialization(Annotated a) {
PropertyName propertyName = findNameFromVersioningProperties(a);
if (propertyName != null) {
return propertyName;
}
return super.findNameForSerialization(a);
}

@Override
pubilc PropertyName findNameForDeserialization(Annotated a) {
PropertyName propertyName = findNameFromVersioningProperties(a);
if (propertyName != null) {
return propertyName;
}
return super.findNameForDeserialization(a);
}

private PropertyName findNameFromVersioningProperties(Annotated a) {
VersioningProperties annotation = a.getAnnotation(VersioningProperties.class);
if (annotation == null) {
return null;
}
for (Property property : annotation.value()) {
if (version.equals(property.version()) {
return new PropertyName(property.value());
}
}
return null;
}
}

Example of using the annotation:

public class User {
@VersioningProperties({
@Property(version = "1.5", value = "fname"),
@Property(version = "1.6", value = "firstName")
})
private String firstName;

// constructors, getters and setters
}

and an example of using ObjectMapper with the introspector:

User user = new User();
user.setFirstName("catherine");
user.setVersion("1.5");

ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new VersioningPropertiesIntrospector(user.getVersion()));

String userJson = mapper.writeValueAsString(user);
User userRead = mapper.readValue(userJson, User.class);

You may also consider implement a factory to get ObjectMapper by passing the version information.

Jackson Serialize Field to Different Name

I am not sure I completly understand your question, but for what I could understand you can do something like this to achieve different serializtions.

Create a custom annotation to hold all possible different serialization options:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomJsonProperty {
String propertyName();

String format();

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
CustomJsonProperty[] value();
}

}

Annotate your class accordingly:

@JsonSerialize(using = CustomJsonPropertySerializer.class)
public class Bar {

@CustomJsonProperty.List({
@CustomJsonProperty(propertyName = "first-name", format = "A"),
@CustomJsonProperty(propertyName = "firstName", format = "B")
})
private String firstName;

@CustomJsonProperty.List({
@CustomJsonProperty(propertyName = "last-name", format = "A"),
@CustomJsonProperty(propertyName = "lastName", format = "B")
})
private String lastName;

@CustomJsonProperty.List({
@CustomJsonProperty(propertyName = "gender-x", format = "A"),
@CustomJsonProperty(propertyName = "gender", format = "B")
})
private String gender;

@JsonIgnore
private String format;

//getters & setters

}

Create a custom serializer to interpret your new annotation:

public class CustomJsonPropertySerializer extends JsonSerializer<Bar> {

@Override
public void serialize(Bar bar, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();

Field[] fields = bar.getClass().getDeclaredFields();

for (Field field : fields) {
field.setAccessible(true);
Object value = null;

try {
value = field.get(bar);
} catch (IllegalAccessException e) {
e.printStackTrace();
}

if (field.isAnnotationPresent(CustomJsonProperty.List.class)) {
CustomJsonProperty[] properties = field.getAnnotation(CustomJsonProperty.List.class).value();
CustomJsonProperty chosenProperty = null;

for (CustomJsonProperty c : properties) {
if (c.format().equalsIgnoreCase(bar.getFormat())) {
chosenProperty = c;
break;
}
}

if (chosenProperty == null) {
//invalid format given, use first format then
chosenProperty = properties[0];
}

jsonGenerator.writeStringField(chosenProperty.propertyName(), value.toString());
}
}

jsonGenerator.writeEndObject();
}
}

Now you can serialize your objects taking into consideration different formats for the property names:

public static void main(String[] args) throws IOException {
Bar bar1 = new Bar("first", "last", "m", "A");
Bar bar2 = new Bar("first", "last", "m", "B");

ObjectMapper mapper = new ObjectMapper();
String json1 = mapper.writeValueAsString(bar1);
String json2 = mapper.writeValueAsString(bar2);

System.out.println(json1);
System.out.println(json2);

}

Output:

{"first-name":"first","last-name":"last","gender-x":"m"}
{"firstName":"first","lastName":"last","gender":"m"}

Of course the above serializer only works for Bar objects, but that can easily be solved using inheritance with abstract String getFormat(); on the super class and changing the custom serializer to accept the super class type, instead of Bar.

Maybe there is a simpler way than creating your own stuff, but I don't know about it. Let me know if something wasn't clear and I can elaborate it again.



Related Topics



Leave a reply



Submit