diff --git a/jackson/pom.xml b/jackson/pom.xml index 9f8e652359..e9008a81a7 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 com.baeldung jackson @@ -54,6 +55,12 @@ com.fasterxml.jackson.datatype jackson-datatype-joda ${jackson.version} + + + + com.fasterxml.jackson.module + jackson-module-jsonSchema + 2.6.0 @@ -168,4 +175,4 @@ - \ No newline at end of file + diff --git a/jackson/src/test/java/org/baeldung/jackson/annotation/extra/AppendBean.java b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/AppendBean.java new file mode 100644 index 0000000000..26b0b2681c --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/AppendBean.java @@ -0,0 +1,31 @@ +package org.baeldung.jackson.annotation.extra; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonAppend; + +@JsonAppend(attrs = {@JsonAppend.Attr(value = "appendedProperty", include = JsonInclude.Include.ALWAYS)}) +public class AppendBean { + private int id; + private String name; + + public AppendBean(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/annotation/extra/ExtraAnnotationTest.java b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/ExtraAnnotationTest.java new file mode 100644 index 0000000000..330e15a239 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/ExtraAnnotationTest.java @@ -0,0 +1,100 @@ +package org.baeldung.jackson.annotation.extra; + +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.instanceOf; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping; +import com.fasterxml.jackson.module.jsonSchema.JsonSchema; +import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper; + +public class ExtraAnnotationTest { + @Test + public void whenUsingJsonIdentityReferenceAnnotation_thenCorrect() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + IdentityReferenceBean bean = new IdentityReferenceBean(1, "Identity Reference Bean"); + String jsonString = mapper.writeValueAsString(bean); + + assertEquals("1", jsonString); + } + + @Test + public void whenUsingJsonAppendAnnotation_thenCorrect() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + AppendBean bean = new AppendBean(2, "Append Bean"); + String jsonString = mapper.writeValueAsString(bean); + + assertThat(jsonString, containsString("appendedProperty")); + } + + @Test + public void whenUsingJsonNamingAnnotation_thenCorrect() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + NamingBean bean = new NamingBean(3, "Naming Bean"); + String jsonString = mapper.writeValueAsString(bean); + + assertThat(jsonString, containsString("bean_name")); + } + + @Test + public void whenUsingJsonPropertyDescriptionAnnotation_thenCorrect() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + SchemaFactoryWrapper wrapper = new SchemaFactoryWrapper(); + mapper.acceptJsonFormatVisitor(PropertyDescriptionBean.class, wrapper); + JsonSchema jsonSchema = wrapper.finalSchema(); + String jsonString = mapper.writeValueAsString(jsonSchema); + + assertThat(jsonString, containsString("This is a description of the name property")); + } + + @Test + public void whenUsingJsonPOJOBuilderAnnotation_thenCorrect() throws IOException { + ObjectMapper mapper = new ObjectMapper(); + String jsonString = "{\"id\":5,\"name\":\"POJO Builder Bean\"}"; + POJOBuilderBean bean = mapper.readValue(jsonString, POJOBuilderBean.class); + + assertEquals(5, bean.getIdentity()); + assertEquals("POJO Builder Bean", bean.getBeanName()); + } + + @Test + public void whenUsingJsonTypeIdAnnotation_thenCorrect() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.enableDefaultTyping(DefaultTyping.NON_FINAL); + TypeIdBean bean = new TypeIdBean(6, "Type Id Bean"); + String jsonString = mapper.writeValueAsString(bean); + + assertThat(jsonString, containsString("Type Id Bean")); + } + + @Test + public void whenUsingJsonTypeIdResolverAnnotation_thenCorrect() throws IOException { + TypeIdResolverStructure.FirstBean bean1 = new TypeIdResolverStructure.FirstBean(1, "Bean 1"); + TypeIdResolverStructure.LastBean bean2 = new TypeIdResolverStructure.LastBean(2, "Bean 2"); + + List beans = new ArrayList<>(); + beans.add(bean1); + beans.add(bean2); + + TypeIdResolverStructure.BeanContainer serializedContainer = new TypeIdResolverStructure.BeanContainer(); + serializedContainer.setBeans(beans); + + ObjectMapper mapper = new ObjectMapper(); + String jsonString = mapper.writeValueAsString(serializedContainer); + assertThat(jsonString, containsString("bean1")); + assertThat(jsonString, containsString("bean2")); + + TypeIdResolverStructure.BeanContainer deserializedContainer = mapper.readValue(jsonString, TypeIdResolverStructure.BeanContainer.class); + List beanList = deserializedContainer.getBeans(); + assertThat(beanList.get(0), instanceOf(TypeIdResolverStructure.FirstBean.class)); + assertThat(beanList.get(1), instanceOf(TypeIdResolverStructure.LastBean.class)); + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/annotation/extra/IdentityReferenceBean.java b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/IdentityReferenceBean.java new file mode 100644 index 0000000000..831f3efc79 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/IdentityReferenceBean.java @@ -0,0 +1,33 @@ +package org.baeldung.jackson.annotation.extra; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonIdentityReference; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; + +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") +@JsonIdentityReference(alwaysAsId = true) +public class IdentityReferenceBean { + private int id; + private String name; + + public IdentityReferenceBean(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/annotation/extra/NamingBean.java b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/NamingBean.java new file mode 100644 index 0000000000..eed4ec9237 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/NamingBean.java @@ -0,0 +1,31 @@ +package org.baeldung.jackson.annotation.extra; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) +public class NamingBean { + private int id; + private String beanName; + + public NamingBean(int id, String beanName) { + this.id = id; + this.beanName = beanName; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/annotation/extra/POJOBuilderBean.java b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/POJOBuilderBean.java new file mode 100644 index 0000000000..d285ce6870 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/POJOBuilderBean.java @@ -0,0 +1,51 @@ +package org.baeldung.jackson.annotation.extra; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +@JsonDeserialize(builder = POJOBuilderBean.BeanBuilder.class) +public class POJOBuilderBean { + private int identity; + private String beanName; + + @JsonPOJOBuilder(buildMethodName = "createBean", withPrefix = "construct") + public static class BeanBuilder { + private int idValue; + private String nameValue; + + public BeanBuilder constructId(int id) { + idValue = id; + return this; + } + + public BeanBuilder constructName(String name) { + nameValue = name; + return this; + } + + public POJOBuilderBean createBean() { + return new POJOBuilderBean(idValue, nameValue); + } + } + + public POJOBuilderBean(int identity, String beanName) { + this.identity = identity; + this.beanName = beanName; + } + + public int getIdentity() { + return identity; + } + + public void setIdentity(int identity) { + this.identity = identity; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/annotation/extra/PropertyDescriptionBean.java b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/PropertyDescriptionBean.java new file mode 100644 index 0000000000..05038aef65 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/PropertyDescriptionBean.java @@ -0,0 +1,25 @@ +package org.baeldung.jackson.annotation.extra; + +import com.fasterxml.jackson.annotation.JsonPropertyDescription; + +public class PropertyDescriptionBean { + private int id; + @JsonPropertyDescription("This is a description of the name property") + private String name; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/annotation/extra/TypeIdBean.java b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/TypeIdBean.java new file mode 100644 index 0000000000..6969c3df73 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/TypeIdBean.java @@ -0,0 +1,30 @@ +package org.baeldung.jackson.annotation.extra; + +import com.fasterxml.jackson.annotation.JsonTypeId; + +public class TypeIdBean { + private int id; + @JsonTypeId + private String name; + + public TypeIdBean(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/annotation/extra/TypeIdResolverStructure.java b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/TypeIdResolverStructure.java new file mode 100644 index 0000000000..07f44b5a77 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/annotation/extra/TypeIdResolverStructure.java @@ -0,0 +1,130 @@ +package org.baeldung.jackson.annotation.extra; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; +import com.fasterxml.jackson.databind.DatabindContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver; +import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase; + +public class TypeIdResolverStructure { + public static class BeanContainer { + private List beans; + + public List getBeans() { + return beans; + } + + public void setBeans(List beans) { + this.beans = beans; + } + } + + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type") + @JsonTypeIdResolver(BeanIdResolver.class) + public static class AbstractBean { + private int id; + + protected AbstractBean() { + } + + protected AbstractBean(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + } + + public static class FirstBean extends AbstractBean { + String firstName; + + public FirstBean() { + } + + public FirstBean(int id, String name) { + super(id); + setFirstName(name); + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String name) { + firstName = name; + } + } + + public static class LastBean extends AbstractBean { + String lastName; + + public LastBean() { + } + + public LastBean(int id, String name) { + super(id); + setLastName(name); + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String name) { + lastName = name; + } + } + + public static class BeanIdResolver extends TypeIdResolverBase { + private JavaType superType; + + @Override + public void init(JavaType baseType) { + superType = baseType; + } + + @Override + public Id getMechanism() { + return Id.NAME; + } + + @Override + public String idFromValue(Object obj) { + return idFromValueAndType(obj, obj.getClass()); + } + + @Override + public String idFromValueAndType(Object obj, Class subType) { + String typeId = null; + switch (subType.getSimpleName()) { + case "FirstBean": + typeId = "bean1"; + break; + case "LastBean": + typeId = "bean2"; + } + return typeId; + } + + @Override + public JavaType typeFromId(DatabindContext context, String id) { + Class subType = null; + switch (id) { + case "bean1": + subType = FirstBean.class; + break; + case "bean2": + subType = LastBean.class; + } + return context.constructSpecializedType(superType, subType); + } + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceAnnotationStructure.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceAnnotationStructure.java new file mode 100644 index 0000000000..a873d3e3c4 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceAnnotationStructure.java @@ -0,0 +1,96 @@ +package org.baeldung.jackson.inheritance; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +public class IgnoranceAnnotationStructure { + public static abstract class Vehicle { + private String make; + private String model; + + protected Vehicle() { + } + + protected Vehicle(String make, String model) { + this.make = make; + this.model = model; + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + } + + @JsonIgnoreProperties({ "model", "seatingCapacity" }) + public static abstract class Car extends Vehicle { + private int seatingCapacity; + @JsonIgnore + private double topSpeed; + + protected Car() { + } + + protected Car(String make, String model, int seatingCapacity, double topSpeed) { + super(make, model); + this.seatingCapacity = seatingCapacity; + this.topSpeed = topSpeed; + } + + public int getSeatingCapacity() { + return seatingCapacity; + } + + public void setSeatingCapacity(int seatingCapacity) { + this.seatingCapacity = seatingCapacity; + } + + public double getTopSpeed() { + return topSpeed; + } + + public void setTopSpeed(double topSpeed) { + this.topSpeed = topSpeed; + } + } + + public static class Sedan extends Car { + public Sedan() { + } + + public Sedan(String make, String model, int seatingCapacity, double topSpeed) { + super(make, model, seatingCapacity, topSpeed); + } + } + + public static class Crossover extends Car { + private double towingCapacity; + + public Crossover() { + } + + public Crossover(String make, String model, int seatingCapacity, double topSpeed, double towingCapacity) { + super(make, model, seatingCapacity, topSpeed); + this.towingCapacity = towingCapacity; + } + + public double getTowingCapacity() { + return towingCapacity; + } + + public void setTowingCapacity(double towingCapacity) { + this.towingCapacity = towingCapacity; + } + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceMixinOrIntrospection.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceMixinOrIntrospection.java new file mode 100644 index 0000000000..bca9572fc1 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceMixinOrIntrospection.java @@ -0,0 +1,91 @@ +package org.baeldung.jackson.inheritance; + +public class IgnoranceMixinOrIntrospection { + public static abstract class Vehicle { + private String make; + private String model; + + protected Vehicle() { + } + + protected Vehicle(String make, String model) { + this.make = make; + this.model = model; + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + } + + public static abstract class Car extends Vehicle { + private int seatingCapacity; + private double topSpeed; + + protected Car() { + } + + protected Car(String make, String model, int seatingCapacity, double topSpeed) { + super(make, model); + this.seatingCapacity = seatingCapacity; + this.topSpeed = topSpeed; + } + + public int getSeatingCapacity() { + return seatingCapacity; + } + + public void setSeatingCapacity(int seatingCapacity) { + this.seatingCapacity = seatingCapacity; + } + + public double getTopSpeed() { + return topSpeed; + } + + public void setTopSpeed(double topSpeed) { + this.topSpeed = topSpeed; + } + } + + public static class Sedan extends Car { + public Sedan() { + } + + public Sedan(String make, String model, int seatingCapacity, double topSpeed) { + super(make, model, seatingCapacity, topSpeed); + } + } + + public static class Crossover extends Car { + private double towingCapacity; + + public Crossover() { + } + + public Crossover(String make, String model, int seatingCapacity, double topSpeed, double towingCapacity) { + super(make, model, seatingCapacity, topSpeed); + this.towingCapacity = towingCapacity; + } + + public double getTowingCapacity() { + return towingCapacity; + } + + public void setTowingCapacity(double towingCapacity) { + this.towingCapacity = towingCapacity; + } + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceTest.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceTest.java new file mode 100644 index 0000000000..5680f870a4 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/IgnoranceTest.java @@ -0,0 +1,92 @@ +package org.baeldung.jackson.inheritance; + +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; + +import org.junit.Test; + +import java.util.List; +import java.util.ArrayList; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.AnnotatedMember; +import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; + +public class IgnoranceTest { + private static abstract class CarMixIn { + @JsonIgnore + public String make; + @JsonIgnore + public String topSpeed; + } + + private static class IgnoranceIntrospector extends JacksonAnnotationIntrospector { + private static final long serialVersionUID = 1422295680188892323L; + + public boolean hasIgnoreMarker(AnnotatedMember m) { + return m.getDeclaringClass() == IgnoranceMixinOrIntrospection.Vehicle.class && m.getName() == "model" || m.getDeclaringClass() == IgnoranceMixinOrIntrospection.Car.class || m.getName() == "towingCapacity" || super.hasIgnoreMarker(m); + } + } + + @Test + public void givenAnnotations_whenIgnoringProperties_thenCorrect() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + + IgnoranceAnnotationStructure.Sedan sedan = new IgnoranceAnnotationStructure.Sedan("Mercedes-Benz", "S500", 5, 250.0); + IgnoranceAnnotationStructure.Crossover crossover = new IgnoranceAnnotationStructure.Crossover("BMW", "X6", 5, 250.0, 6000.0); + + List vehicles = new ArrayList<>(); + vehicles.add(sedan); + vehicles.add(crossover); + + String jsonDataString = mapper.writeValueAsString(vehicles); + + assertThat(jsonDataString, containsString("make")); + assertThat(jsonDataString, not(containsString("model"))); + assertThat(jsonDataString, not(containsString("seatingCapacity"))); + assertThat(jsonDataString, not(containsString("topSpeed"))); + assertThat(jsonDataString, containsString("towingCapacity")); + } + + @Test + public void givenMixIns_whenIgnoringProperties_thenCorrect() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.addMixIn(IgnoranceMixinOrIntrospection.Car.class, CarMixIn.class); + + String jsonDataString = instantiateAndSerializeObjects(mapper); + + assertThat(jsonDataString, not(containsString("make"))); + assertThat(jsonDataString, containsString("model")); + assertThat(jsonDataString, containsString("seatingCapacity")); + assertThat(jsonDataString, not(containsString("topSpeed"))); + assertThat(jsonDataString, containsString("towingCapacity")); + } + + @Test + public void givenIntrospection_whenIgnoringProperties_thenCorrect() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setAnnotationIntrospector(new IgnoranceIntrospector()); + + String jsonDataString = instantiateAndSerializeObjects(mapper); + + assertThat(jsonDataString, containsString("make")); + assertThat(jsonDataString, not(containsString("model"))); + assertThat(jsonDataString, not(containsString("seatingCapacity"))); + assertThat(jsonDataString, not(containsString("topSpeed"))); + assertThat(jsonDataString, not(containsString("towingCapacity"))); + } + + private String instantiateAndSerializeObjects(ObjectMapper mapper) throws JsonProcessingException { + IgnoranceMixinOrIntrospection.Sedan sedan = new IgnoranceMixinOrIntrospection.Sedan("Mercedes-Benz", "S500", 5, 250.0); + IgnoranceMixinOrIntrospection.Crossover crossover = new IgnoranceMixinOrIntrospection.Crossover("BMW", "X6", 5, 250.0, 6000.0); + + List vehicles = new ArrayList<>(); + vehicles.add(sedan); + vehicles.add(crossover); + + return mapper.writeValueAsString(vehicles); + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeConstructorStructure.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeConstructorStructure.java new file mode 100644 index 0000000000..aca627a593 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeConstructorStructure.java @@ -0,0 +1,92 @@ +package org.baeldung.jackson.inheritance; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class SubTypeConstructorStructure { + public static class Fleet { + private List vehicles; + + public List getVehicles() { + return vehicles; + } + + public void setVehicles(List vehicles) { + this.vehicles = vehicles; + } + } + + public static abstract class Vehicle { + private String make; + private String model; + + protected Vehicle(String make, String model) { + this.make = make; + this.model = model; + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + } + + public static class Car extends Vehicle { + private int seatingCapacity; + private double topSpeed; + + @JsonCreator + public Car(@JsonProperty("make") String make, @JsonProperty("model") String model, @JsonProperty("seating") int seatingCapacity, @JsonProperty("topSpeed") double topSpeed) { + super(make, model); + this.seatingCapacity = seatingCapacity; + this.topSpeed = topSpeed; + } + + public int getSeatingCapacity() { + return seatingCapacity; + } + + public void setSeatingCapacity(int seatingCapacity) { + this.seatingCapacity = seatingCapacity; + } + + public double getTopSpeed() { + return topSpeed; + } + + public void setTopSpeed(double topSpeed) { + this.topSpeed = topSpeed; + } + } + + public static class Truck extends Vehicle { + private double payloadCapacity; + + @JsonCreator + public Truck(@JsonProperty("make") String make, @JsonProperty("model") String model, @JsonProperty("payload") double payloadCapacity) { + super(make, model); + this.payloadCapacity = payloadCapacity; + } + + public double getPayloadCapacity() { + return payloadCapacity; + } + + public void setPayloadCapacity(double payloadCapacity) { + this.payloadCapacity = payloadCapacity; + } + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeConversionStructure.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeConversionStructure.java new file mode 100644 index 0000000000..babff8f255 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeConversionStructure.java @@ -0,0 +1,87 @@ +package org.baeldung.jackson.inheritance; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class SubTypeConversionStructure { + public static abstract class Vehicle { + private String make; + private String model; + + protected Vehicle() { + } + + protected Vehicle(String make, String model) { + this.make = make; + this.model = model; + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + } + + public static class Car extends Vehicle { + @JsonIgnore + private int seatingCapacity; + @JsonIgnore + private double topSpeed; + + public Car() { + } + + public Car(String make, String model, int seatingCapacity, double topSpeed) { + super(make, model); + this.seatingCapacity = seatingCapacity; + this.topSpeed = topSpeed; + } + + public int getSeatingCapacity() { + return seatingCapacity; + } + + public void setSeatingCapacity(int seatingCapacity) { + this.seatingCapacity = seatingCapacity; + } + + public double getTopSpeed() { + return topSpeed; + } + + public void setTopSpeed(double topSpeed) { + this.topSpeed = topSpeed; + } + } + + public static class Truck extends Vehicle { + @JsonIgnore + private double payloadCapacity; + + public Truck() { + } + + public Truck(String make, String model, double payloadCapacity) { + super(make, model); + this.payloadCapacity = payloadCapacity; + } + + public double getPayloadCapacity() { + return payloadCapacity; + } + + public void setPayloadCapacity(double payloadCapacity) { + this.payloadCapacity = payloadCapacity; + } + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeHandlingTest.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeHandlingTest.java new file mode 100644 index 0000000000..eb373ff607 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/SubTypeHandlingTest.java @@ -0,0 +1,43 @@ +package org.baeldung.jackson.inheritance; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import java.util.List; +import java.util.ArrayList; +import java.io.IOException; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class SubTypeHandlingTest { + @Test + public void givenSubTypes_whenConvertingObjects_thenDataValuesArePreserved() { + ObjectMapper mapper = new ObjectMapper(); + + SubTypeConversionStructure.Car car = new SubTypeConversionStructure.Car("Mercedes-Benz", "S500", 5, 250.0); + SubTypeConversionStructure.Truck truck = mapper.convertValue(car, SubTypeConversionStructure.Truck.class); + + assertEquals("Mercedes-Benz", truck.getMake()); + assertEquals("S500", truck.getModel()); + } + + @Test + public void givenSubType_whenNotUsingNoArgsConstructors_thenSucceed() throws IOException{ + ObjectMapper mapper = new ObjectMapper(); + mapper.enableDefaultTyping(); + + SubTypeConstructorStructure.Car car = new SubTypeConstructorStructure.Car("Mercedes-Benz", "S500", 5, 250.0); + SubTypeConstructorStructure.Truck truck = new SubTypeConstructorStructure.Truck("Isuzu", "NQR", 7500.0); + + List vehicles = new ArrayList<>(); + vehicles.add(car); + vehicles.add(truck); + + SubTypeConstructorStructure.Fleet serializedFleet = new SubTypeConstructorStructure.Fleet(); + serializedFleet.setVehicles(vehicles); + + String jsonDataString = mapper.writeValueAsString(serializedFleet); + mapper.readValue(jsonDataString, SubTypeConstructorStructure.Fleet.class); + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoAnnotatedStructure.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoAnnotatedStructure.java new file mode 100644 index 0000000000..698fddfd60 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoAnnotatedStructure.java @@ -0,0 +1,102 @@ +package org.baeldung.jackson.inheritance; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; + +public class TypeInfoAnnotatedStructure { + public static class Fleet { + private List vehicles; + + public List getVehicles() { + return vehicles; + } + + public void setVehicles(List vehicles) { + this.vehicles = vehicles; + } + } + + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") + @JsonSubTypes({ @Type(value = Car.class, name = "car"), @Type(value = Truck.class, name = "truck") }) + public static abstract class Vehicle { + private String make; + private String model; + + protected Vehicle() { + } + + protected Vehicle(String make, String model) { + this.make = make; + this.model = model; + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + } + + public static class Car extends Vehicle { + private int seatingCapacity; + private double topSpeed; + + public Car() { + } + + public Car(String make, String model, int seatingCapacity, double topSpeed) { + super(make, model); + this.seatingCapacity = seatingCapacity; + this.topSpeed = topSpeed; + } + + public int getSeatingCapacity() { + return seatingCapacity; + } + + public void setSeatingCapacity(int seatingCapacity) { + this.seatingCapacity = seatingCapacity; + } + + public double getTopSpeed() { + return topSpeed; + } + + public void setTopSpeed(double topSpeed) { + this.topSpeed = topSpeed; + } + } + + public static class Truck extends Vehicle { + private double payloadCapacity; + + public Truck() { + } + + public Truck(String make, String model, double payloadCapacity) { + super(make, model); + this.payloadCapacity = payloadCapacity; + } + + public double getPayloadCapacity() { + return payloadCapacity; + } + + public void setPayloadCapacity(double payloadCapacity) { + this.payloadCapacity = payloadCapacity; + } + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoInclusionTest.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoInclusionTest.java new file mode 100644 index 0000000000..67d953bcb3 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoInclusionTest.java @@ -0,0 +1,57 @@ +package org.baeldung.jackson.inheritance; + +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.instanceOf; + +import org.junit.Test; + +import java.util.List; +import java.util.ArrayList; +import java.io.IOException; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class TypeInfoInclusionTest { + @Test + public void givenTypeInfo_whenAnnotatingGlobally_thenTypesAreCorrectlyRecovered() throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.enableDefaultTyping(); + + TypeInfoStructure.Car car = new TypeInfoStructure.Car("Mercedes-Benz", "S500", 5, 250.0); + TypeInfoStructure.Truck truck = new TypeInfoStructure.Truck("Isuzu", "NQR", 7500.0); + + List vehicles = new ArrayList<>(); + vehicles.add(car); + vehicles.add(truck); + + TypeInfoStructure.Fleet serializedFleet = new TypeInfoStructure.Fleet(); + serializedFleet.setVehicles(vehicles); + + String jsonDataString = mapper.writeValueAsString(serializedFleet); + TypeInfoStructure.Fleet deserializedFleet = mapper.readValue(jsonDataString, TypeInfoStructure.Fleet.class); + + assertThat(deserializedFleet.getVehicles().get(0), instanceOf(TypeInfoStructure.Car.class)); + assertThat(deserializedFleet.getVehicles().get(1), instanceOf(TypeInfoStructure.Truck.class)); + } + + @Test + public void givenTypeInfo_whenAnnotatingPerClass_thenTypesAreCorrectlyRecovered() throws IOException { + ObjectMapper mapper = new ObjectMapper(); + + TypeInfoAnnotatedStructure.Car car = new TypeInfoAnnotatedStructure.Car("Mercedes-Benz", "S500", 5, 250.0); + TypeInfoAnnotatedStructure.Truck truck = new TypeInfoAnnotatedStructure.Truck("Isuzu", "NQR", 7500.0); + + List vehicles = new ArrayList<>(); + vehicles.add(car); + vehicles.add(truck); + + TypeInfoAnnotatedStructure.Fleet serializedFleet = new TypeInfoAnnotatedStructure.Fleet(); + serializedFleet.setVehicles(vehicles); + + String jsonDataString = mapper.writeValueAsString(serializedFleet); + TypeInfoAnnotatedStructure.Fleet deserializedFleet = mapper.readValue(jsonDataString, TypeInfoAnnotatedStructure.Fleet.class); + + assertThat(deserializedFleet.getVehicles().get(0), instanceOf(TypeInfoAnnotatedStructure.Car.class)); + assertThat(deserializedFleet.getVehicles().get(1), instanceOf(TypeInfoAnnotatedStructure.Truck.class)); + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoStructure.java b/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoStructure.java new file mode 100644 index 0000000000..2c48a6e980 --- /dev/null +++ b/jackson/src/test/java/org/baeldung/jackson/inheritance/TypeInfoStructure.java @@ -0,0 +1,96 @@ +package org.baeldung.jackson.inheritance; + +import java.util.List; + +public class TypeInfoStructure { + public static class Fleet { + private List vehicles; + + public List getVehicles() { + return vehicles; + } + + public void setVehicles(List vehicles) { + this.vehicles = vehicles; + } + } + + public static abstract class Vehicle { + private String make; + private String model; + + protected Vehicle() { + } + + protected Vehicle(String make, String model) { + this.make = make; + this.model = model; + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + } + + public static class Car extends Vehicle { + private int seatingCapacity; + private double topSpeed; + + public Car() { + } + + public Car(String make, String model, int seatingCapacity, double topSpeed) { + super(make, model); + this.seatingCapacity = seatingCapacity; + this.topSpeed = topSpeed; + } + + public int getSeatingCapacity() { + return seatingCapacity; + } + + public void setSeatingCapacity(int seatingCapacity) { + this.seatingCapacity = seatingCapacity; + } + + public double getTopSpeed() { + return topSpeed; + } + + public void setTopSpeed(double topSpeed) { + this.topSpeed = topSpeed; + } + } + + public static class Truck extends Vehicle { + private double payloadCapacity; + + public Truck() { + } + + public Truck(String make, String model, double payloadCapacity) { + super(make, model); + this.payloadCapacity = payloadCapacity; + } + + public double getPayloadCapacity() { + return payloadCapacity; + } + + public void setPayloadCapacity(double payloadCapacity) { + this.payloadCapacity = payloadCapacity; + } + } +} \ No newline at end of file diff --git a/jackson/src/test/java/org/baeldung/jackson/test/JacksonAnnotationTest.java b/jackson/src/test/java/org/baeldung/jackson/test/JacksonAnnotationTest.java index c188e9bce1..068b54ca60 100644 --- a/jackson/src/test/java/org/baeldung/jackson/test/JacksonAnnotationTest.java +++ b/jackson/src/test/java/org/baeldung/jackson/test/JacksonAnnotationTest.java @@ -345,7 +345,7 @@ public class JacksonAnnotationTest { assertThat(result, containsString("John")); final ObjectMapper mapper = new ObjectMapper(); - mapper.addMixInAnnotations(String.class, MyMixInForString.class); + mapper.addMixIn(String.class, MyMixInForString.class); result = mapper.writeValueAsString(user); assertThat(result, not(containsString("John"))); diff --git a/jackson/src/test/java/org/baeldung/jackson/test/JacksonSerializationIgnoreUnitTest.java b/jackson/src/test/java/org/baeldung/jackson/test/JacksonSerializationIgnoreUnitTest.java index 64614fb854..fe0b18e859 100644 --- a/jackson/src/test/java/org/baeldung/jackson/test/JacksonSerializationIgnoreUnitTest.java +++ b/jackson/src/test/java/org/baeldung/jackson/test/JacksonSerializationIgnoreUnitTest.java @@ -87,7 +87,7 @@ public class JacksonSerializationIgnoreUnitTest { @Test public final void givenFieldTypeIsIgnored_whenDtoIsSerialized_thenCorrect() throws JsonParseException, IOException { final ObjectMapper mapper = new ObjectMapper(); - mapper.addMixInAnnotations(String.class, MyMixInForString.class); + mapper.addMixIn(String.class, MyMixInForString.class); final MyDto dtoObject = new MyDto(); dtoObject.setBooleanValue(true);