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:
parent
33e3fc580a
commit
d0a2127248
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user