I have two class for external API response:
ClassA:
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@Setter
public class ClassA {
private SubClass subClass;
@Getter
@Setter
public static class SubClass {
Integer total;
Integer perPage;
List<Data> dataList;
@Getter
@Setter
public static class Data {
private String field1;
private String field2;
private int field3;
}
}
}
ClassB:
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@Setter
public class ClassB {
private SubClass subClass;
@Getter
@Setter
public static class SubClass {
Integer total;
Integer perPage;
List<Data> dataList;
@Getter
@Setter
public static class Data {
private String field1;
private int field2;
private Date field3;
}
}
}
And deserialization with ObjectMapper:
ClassA classA =
mapper.readValue(bodyResponse, ClassA.class);
What is the best way to get rid of duplicate code in these classes when using inheritance and later using deserialization?
You need to make root and sub classes generic. Use TypeReference
to provide which data class you expect. Take a look at below example:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.Date;
import java.util.List;
public class GenericDataApp {
public static void main(String[] args) throws JsonProcessingException {
JsonMapper mapper = JsonMapper.builder().build();
String srcA = "{\"subClass\":{\"total\":1,\"dataList\":[{\"field2\":\"String value\"}]}}";
RootClass<DataA> dataA = mapper.readValue(srcA, new TypeReference<RootClass<DataA>>() {
});
System.out.println(dataA.getSubClass());
String srcB = "{\"subClass\":{\"total\":1,\"dataList\":[{\"field2\":12}]}}";
RootClass<DataB> dataB = mapper.readValue(srcB, new TypeReference<RootClass<DataB>>() {
});
System.out.println(dataB.getSubClass());
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@Setter
class RootClass<T> {
private SubClass<T> subClass;
@Getter
@Setter
@ToString
public static class SubClass<T> {
Integer total;
Integer perPage;
List<T> dataList;
}
}
@Getter
@Setter
@ToString
class DataA {
private String field1;
private String field2;
private int field3;
}
@Getter
@Setter
@ToString
class DataB {
private String field1;
private int field2;
private Date field3;
}
Above code prints:
RootClass.SubClass(total=1, perPage=null, dataList=[DataA(field1=null, field2=String value, field3=0)])
RootClass.SubClass(total=1, perPage=null, dataList=[DataB(field1=null, field2=12, field3=null)])