BAEL-7083: Gson class declares multiple fields (#15244)

* Add initial classes and tests for Gson multiple fields error

* Add test classes and exclusion strategy

* Add test cases

* Simplify example code
This commit is contained in:
Lucian Snare 2023-11-25 10:35:19 -05:00 committed by GitHub
parent 33e3fc580a
commit d0a2127248
5 changed files with 252 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}