Reuse value from parent object to construct child when deserializing with Jackson - java

I have two classes with a redundant shared attribute:
class Parent {
int version;
Child child;
}
class Child {
int version;
String name;
}
The version field from Child is just a local copy of the Parent's own field, so it is represented like this in JSON:
{
"version": 2,
"child": {
"name": "john"
}
}
I want to deserialize this JSON payload to the corresponding Parent object with parent.child.version == 2 (the value is copied from the parent). How can I achieve this?
I thought about using #JacksonInject to pass the version to the Child, but that requires populating the injected values while deserializing the parent object. I could not find any way to register an injected value in a custom deserializer: the findInjectableValue method of DeserializationContext only lets us look up such a value.

It's not really a Jackson-specific solution but it's probably the simplest one: create a PreChild class whose attributes match the JSON payload, then convert the PreChild to a Child in the constructor of Parent.
class PreChild {
String name;
public Child withVersion(int version) {
return Child(version, name);
}
}
class Parent {
int version;
Child child;
#JsonCreator
Parent(
#JsonProperty("version") int version,
#JsonProperty("child") PreChild preChild) {
this.version = version;
this.child = preChild.withVersion(version);
}
}

Related

How do I attach the enum value to an object, instead of the enum name?

So my title is probably not the best one, but I think I can better show it in code what I want to achieve. I'm doing things with Spring Boot, JPA and React.
So let's say I have this enum:
public enum MyEnum {
FIRST_ENUM("First"),
SECOND_ENUM("Second")
}
And there's a class that contains one of the enums:
public class MyClass {
private int id;
private MyEnum myEnum;
}
When I convert an instance of this class to JSON (so I can pass it to React as JSON), this is what I get:
{
"id": 1,
"myEnum": "FIRST_ENUM"
}
But instead I want it to use the value instead (I know I can manually create JSONObject instances, but is there a way to automatically use the value instead?):
{
"id": 1,
"myEnum": "First"
}
public enum MyEnum {
FIRST_ENUM("First"),
SECOND_ENUM("Second");
#JsonValue
private final String name;
MyEnum(String name) {
this.name = name;
}
#JsonCreator
public static MyEnum fromString(String string) {
...//find enum constant by name
}
}
Another option is to use #JsonProperty for the enum values if the purpose of the custom name is to represent the enum's value in JSON:
public enum MyEnum {
#JsonProperty("First") FIRST_ENUM,
#JsonProperty("Second") SECOND_ENUM;
}

Jackson JSON to pojo from array of objects with no property name

Considering this structure, what is the correct notation for getting the array of objects (property, type fields) inside of the parent property.
{"parent":
[
{"property":[2,5],"type":2},
{"property":[1,2],"type":1},
{"property":[4,0],"type":0}
],
"prop2":"something"
}
Currently the java looks like
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Parent{
<WHAT TO PUT HERE??>
List<PropertyTypeObj> propertyTypes;
}
This is part of something larger like:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Container{
#JsonProperty("parent")
List<Parent> parent;
#JsonProperty("prop2")
String prop2
}
The solution was to bypass the parent element creation and instead use the PropertyTypeObject itself
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Container{
#JsonProperty("parent")
List<PropertyTypeObject> properties;
#JsonProperty("prop2")
String prop2
}
And then specify the PropertyTypeObject as having #JsonRootName("parent")
See approved answer for clarity.
A possible class structure is the following:
public class External {
private List<External.Internal> parent;
private String prop2;
#JsonRootName("parent")
public static class Internal {
private List<Integer> property;
private Integer type;
}
}
where the external class has:
a parent property that is a List (array in the json) of Inner elements
prop2 property of type String
and an internal class that has for each element:
a property property of type List (array in json) of integers
a type property of type integer

Force Jackson Backreference to be resolved first

I have a JSON object tree like this:
{
"name": "parent",
"children": [
{
"name":"child",
"value":5
}
]
}
In Java the parent class has a list of children marked with #JsonManagedReference and the child class has a corresponding #JsonBackReference. My problem is that the setter method of the value property depends on the parent. Sadly in all my experiments the back reference is resolved last and thus the parent field in the child object is still null when the value is set. Is there a way to change this deserialization order? Or is there another way to solve this elegantly without introducing unnecessary fields.
public class Parent {
#JsonManagedReference
private List<Child> children;
private String name;
//getter/setter
public int doStuff(int input) {
return 0; //complex calculations here
}
}
public class Child{
#JsonBackReference
private Parent parent;
private String name;
private int value;
//getter/setter
public void setValue(int v) {
this.value = getParent().doStuff(v);
}
}

JAVA JACKSON: serialize a class with two field instead of all class

I need to serialize an entity with only two column when it's called by a foreign key. I'am working in Wildfly, so I'am searching for a jackson solutions.
Suppose I have entity class A
public class A{
private Long id;
private String name;
private String anotherinfo;
private String foo;
...
}
and another class B:
public class B{
private Long id;
private String name;
private A parent;
}
I want to serialize A with all his field when i search for A, but when i need to retrieve an istance of B, i need only two field (an ID and a label)
If I use annotations:
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
#JsonIdentityReference(alwaysAsId=true)
private A parent;
i'll return only the id.
The result i want will be like:
B: {
"id" : 1,
"name" : "test",
"parent" : {
"id" : 1,
"name" : 2
}
}
You can use the JsonIgnoreProperties annotation, to disable specific fields for serialization (and deserialization):
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
public class B {
private Long id;
private String name;
#JsonIgnoreProperties({"anotherinfo", "foo"})
private A parent;
Have A extend another class, say C:
class C {
Long id;
String name;
}
class A extends C {
String anotherinfo;
String foo;
...
}
Then, in B:
class B {
Long id;
String name;
#JsonSerialize(as=C.class)
A parent;
}
When you serialize B, its parent field will have just the fields from C, but everywhere else that you serialize an A object you will see all the fields from both A and C.
For more information, take a look at https://github.com/FasterXML/jackson-annotations#annotations-for-choosing-moreless-specific-types
Solved adding a Json Serializer.
I have created an NationJsonSerializer for the parent class:
public class NationJsonSerializer extends JsonSerializer<TNation> {
#Override
public void serialize(TNation value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.getId());
jgen.writeStringField("name", value.getComune());
jgen.writeStringField("iso", value.getCap());
jgen.writeEndObject();
}
}
Then,in the city class, i put the annotation
#JoinColumn(name = "idtnation",referencedColumnName = "id",nullable = true)
#ManyToOne(targetEntity = TNation.class, fetch = FetchType.EAGER)
#JsonSerialize(using = NationJsonSerializer.class)
private TNation nation;
So, if I use a method Nation n = getNation(long id); i'll receive all columns, but if i use getCity(), I'll receive a simplified version.

Can I use mapped Jackson Mixin properties to create a JSON subclass when deserializing?

I have JSON output correctly annotated and mapped with mixins for the User class with appropriate setters and getters for those properties:
public class User {
String first;
String middle;
String last;
...
}
When I use my Mixin:
public interface UserMixin {
#JsonProperty("first")
void setFirst(String first);
#JsonProperty("middle")
void setMiddle(String middle);
#JsonProperty("last")
void setLast(String last);
}
After registering the mixin and writing the User class using the ObjectMapper I get:
"User" :
{
"first" : "William",
"middle" : "S",
"last" : "Preston"
}
So to this point, for brevity, I lied a little bit - User as cited above is a large, legacy DTO class that is resistant towards modification.
And, while the mixin works great, our customer would rather see something like:
"User" :
{
"Name" :
{
"first" : "William",
"middle" : "S",
"last" : "Preston"
}
...
}
I repeat, the DTO is resistant to change. Ideally I'd refactor the DTO and do it correctly.
What I think I'm asking - is there some combination of Mixin/Annotation I can use to sub-class "Name" from already existing data in the User class? There's no Name subclass ... but all of the pieces necessary to "write out" the JSON in this format exist.
Lacking the existence of a #JsonWrapped annotation, my personal preferred solution here would be to use the converter functionality of #JsonSerialize (looks like you'd need Jackson 2.3+ for this; the annotation is supported in 2.2.2 but I got unexpected runtime errors).
Basically, a converter lets you do a pre-serialization transformation from one data structure to another. This lets you work with simple data classes rather than mucking about creating a custom serializer.
First, model your DTO how you want it to be serialized:
public static class UserDto {
private final Name name;
private UserDto(Name name) { this.name = name; }
public static UserDto fromUser(User user) {
return new UserDto(Name.fromUser(user));
}
public Name getName() { return name; }
public static class Name {
private final String first;
private final String middle;
private final String last;
private Name(String first, String middle, String last) {
this.first = first;
this.middle = middle;
this.last = last;
}
public static Name fromUser(User user) {
return new Name(user.getFirst(), user.getMiddle(), user.getLast());
}
public String getFirst() { return first; }
public String getMiddle() { return middle; }
public String getLast() { return last; }
}
}
Next, create a simple Converter class (I nested it in UserDto):
public static class Converter extends StdConverter<User, UserDto> {
#Override
public UserDto convert(User value) {
return UserDto.fromUser(value);
}
}
Then, use that converter class in your mixin:
#JsonSerialize(converter = UserDto.Converter.class)
public interface UserMixin {
}

Categories