diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/BasicStudent.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/BasicStudent.java new file mode 100644 index 0000000000..9c8d5f0923 --- /dev/null +++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/BasicStudent.java @@ -0,0 +1,64 @@ +package com.baeldung.gson.multiplefields; + +import java.util.Objects; + +import com.google.gson.annotations.SerializedName; + +public class BasicStudent { + + private String name; + + private transient String major; + + @SerializedName("major") + private String concentration; + + public BasicStudent() { + + } + + public BasicStudent(String name, String major, String concentration) { + this.name = name; + this.major = major; + this.concentration = concentration; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof BasicStudent)) + return false; + BasicStudent student = (BasicStudent) o; + return Objects.equals(name, student.name) && Objects.equals(major, student.major) && Objects.equals(concentration, student.concentration); + } + + @Override + public int hashCode() { + return Objects.hash(name, major, concentration); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getMajor() { + return major; + } + + public void setMajor(String major) { + this.major = major; + } + + public String getConcentration() { + return concentration; + } + + public void setConcentration(String concentration) { + this.concentration = concentration; + } +} diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentExclusionStrategy.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentExclusionStrategy.java new file mode 100644 index 0000000000..5dad30a138 --- /dev/null +++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentExclusionStrategy.java @@ -0,0 +1,18 @@ +package com.baeldung.gson.multiplefields; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; + +public class StudentExclusionStrategy implements ExclusionStrategy { + + @Override + public boolean shouldSkipField(FieldAttributes field) { + // Ignore all field values from V1 type + return field.getDeclaringClass() == StudentV1.class; + } + + @Override + public boolean shouldSkipClass(Class aClass) { + return false; + } +} diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentV1.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentV1.java new file mode 100644 index 0000000000..49a09b830c --- /dev/null +++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentV1.java @@ -0,0 +1,34 @@ +package com.baeldung.gson.multiplefields; + +public class StudentV1 { + + private String firstName; + private String lastName; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + // Default constructor for Gson + public StudentV1() { + + } + + public StudentV1(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + +} diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentV2.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentV2.java new file mode 100644 index 0000000000..e31d33e3fd --- /dev/null +++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/multiplefields/StudentV2.java @@ -0,0 +1,71 @@ +package com.baeldung.gson.multiplefields; + +import java.util.Objects; + +import com.google.gson.annotations.Expose; + +public class StudentV2 extends StudentV1 { + + @Expose + private String firstName; + + @Expose + private String lastName; + + @Expose + private String major; + + @Override + public String getFirstName() { + return firstName; + } + + @Override + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + @Override + public String getLastName() { + return lastName; + } + + @Override + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getMajor() { + return major; + } + + public void setMajor(String major) { + this.major = major; + } + + // Default constructor for Gson + public StudentV2() { + + } + + public StudentV2(String firstName, String lastName, String major) { + this.firstName = firstName; + this.lastName = lastName; + this.major = major; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof StudentV2)) + return false; + StudentV2 studentV2 = (StudentV2) o; + return Objects.equals(firstName, studentV2.firstName) && Objects.equals(lastName, studentV2.lastName) && Objects.equals(major, studentV2.major); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName, major); + } +} diff --git a/json-modules/gson-2/src/test/java/com/baeldung/gson/multiplefields/GsonMultipleFieldsUnitTest.java b/json-modules/gson-2/src/test/java/com/baeldung/gson/multiplefields/GsonMultipleFieldsUnitTest.java new file mode 100644 index 0000000000..1ee2cd1bd8 --- /dev/null +++ b/json-modules/gson-2/src/test/java/com/baeldung/gson/multiplefields/GsonMultipleFieldsUnitTest.java @@ -0,0 +1,65 @@ +package com.baeldung.gson.multiplefields; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.Test; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class GsonMultipleFieldsUnitTest { + + @Test + public void givenBasicStudent_whenSerializingWithGson_thenTransientFieldNotSet() { + // Given a class with a transient field + BasicStudent student = new BasicStudent("Henry Winter", "Greek Studies", "Classical Greek Studies"); + + // When serializing using Gson + Gson gson = new Gson(); + String json = gson.toJson(student); + + // Then the deserialized instance doesn't contain the transient field value + BasicStudent deserialized = gson.fromJson(json, BasicStudent.class); + assertThat(deserialized.getMajor()).isNull(); + } + + @Test + public void givenStudentV2_whenSerializingWithGson_thenIllegalArgumentExceptionIsThrown() { + // Given a class with a class hierarchy that defines multiple fields with the same name + StudentV2 student = new StudentV2("Henry", "Winter", "Greek Studies"); + + // When serializing using Gson, then an IllegalArgumentException exception is thrown + Gson gson = new Gson(); + assertThatThrownBy(() -> gson.toJson(student)).isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("declares multiple JSON fields named 'firstName'"); + } + + @Test + public void givenStudentV2_whenSerializingWithGsonExposeAnnotation_thenSerializes() { + // Given a class with a class hierarchy that defines multiple fields with the same name + StudentV2 student = new StudentV2("Henry", "Winter", "Greek Studies"); + + // When serializing using Gson exclude fields without @Expose + Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation() + .create(); + + // Then ensure the student can be serialized, then deserialized back into an equal instance + String json = gson.toJson(student); + assertThat(gson.fromJson(json, StudentV2.class)).isEqualTo(student); + } + + @Test + public void givenStudentV2_whenSerializingWithGsonExclusionStrategy_thenSerializes() { + // Given a class with a class hierarchy that defines multiple fields with the same name + StudentV2 student = new StudentV2("Henry", "Winter", "Greek Studies"); + + // When serializing using Gson add an ExclusionStrategy + Gson gson = new GsonBuilder().setExclusionStrategies(new StudentExclusionStrategy()) + .create(); + + // Then ensure the student can be serialized, then deserialized back into an equal instance + assertThat(gson.fromJson(gson.toJson(student), StudentV2.class)).isEqualTo(student); + } + +} \ No newline at end of file