Merge pull request #15955 from parthiv39731/BAEL-7426

BAEL-7426, Gson TypeToken with Dynamic ArrayList Item Type
This commit is contained in:
davidmartinezbarua 2024-02-28 11:01:41 -03:00 committed by GitHub
commit 80bc3342ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 214 additions and 0 deletions

View File

@ -18,6 +18,11 @@
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
<properties>

View File

@ -0,0 +1,34 @@
package com.baeldung.gson.jsontolist.type;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class ParameterizedTypeImpl implements ParameterizedType {
private final Class<?> rawType;
private final Type[] actualTypeArguments;
private ParameterizedTypeImpl(Class<?> rawType, Type[] actualTypeArguments) {
this.rawType = rawType;
this.actualTypeArguments = actualTypeArguments;
}
public static ParameterizedType make(Class<?> rawType, Type ... actualTypeArguments) {
return new ParameterizedTypeImpl(rawType, actualTypeArguments);
}
@Override
public Type[] getActualTypeArguments() {
return actualTypeArguments;
}
@Override
public Type getRawType() {
return rawType;
}
@Override
public Type getOwnerType() {
return null;
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.gson.jsontolist.type;
public class School {
private String name;
private String city;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.gson.jsontolist.type;
public class Student {
private String name;
private String grade;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
}

View File

@ -0,0 +1,129 @@
package com.baeldung.gson.jsontolist.type;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.reflect.TypeParameter;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
public class JsonArrayStringToListUnitTest {
Logger LOGGER = LoggerFactory.getLogger(JsonArrayStringToListUnitTest.class);
final String jsonArrayOfStudents =
"["
+ "{\"name\":\"John\", \"grade\":\"1\"}, "
+ "{\"name\":\"Tom\", \"grade\":\"2\"}, "
+ "{\"name\":\"Ram\", \"grade\":\"3\"}, "
+ "{\"name\":\"Sara\", \"grade\":\"1\"}"
+ "]";
final String jsonArrayOfSchools =
"["
+ "{\"name\":\"St. John\", \"city\":\"Chicago City\"}, "
+ "{\"name\":\"St. Tom\", \"city\":\"New York City\"}, "
+ "{\"name\":\"St. Ram\", \"city\":\"Mumbai\"}, "
+ "{\"name\":\"St. Sara\", \"city\":\"Budapest\"}"
+ "]";
@Test
void givenJsonArray_whenListElementTypeDynamic_thenConvertToJavaListUsingTypeToken() {
Gson gson = new Gson();
TypeToken<List<Student>> typeTokenForListOfStudents = new TypeToken<List<Student>>(){};
TypeToken<List<School>> typeTokenForListOfSchools = new TypeToken<List<School>>(){};
List<Student> studentsLst = gson.fromJson(jsonArrayOfStudents, typeTokenForListOfStudents.getType());
List<School> schoolLst = gson.fromJson(jsonArrayOfSchools, typeTokenForListOfSchools.getType());
assertAll(
() -> studentsLst.forEach(e -> assertTrue(e instanceof Student)),
() -> schoolLst.forEach(e -> assertTrue(e instanceof School))
);
}
@Test
void givenJsonArray_whenListElementTypeDynamic_thenConvertToJavaListUsingTypeTokenFails() {
Gson gson = new Gson();
List<Student> studentsLst = gson.fromJson(jsonArrayOfStudents, new ListWithDynamicTypeElement<Student>().getType());
assertFalse(studentsLst.get(0) instanceof Student);
assertThrows(ClassCastException.class, () -> studentsLst.forEach(e -> assertTrue(e instanceof Student)));
}
class ListWithDynamicTypeElement<T> {
Type getType() {
TypeToken<List<T>> typeToken = new TypeToken<List<T>>(){};
return typeToken.getType();
}
}
@Test
void givenJsonArray_whenListElementTypeDynamic_thenConvertToJavaListUsingGetParameterized() {
Gson gson = new Gson();
List<Student> studentsLst = gson.fromJson(jsonArrayOfStudents, getGenericTypeForListFromTypeTokenUsingGetParameterized(Student.class));
List<School> schoolLst = gson.fromJson(jsonArrayOfSchools, getGenericTypeForListFromTypeTokenUsingGetParameterized(School.class));
assertAll(
() -> studentsLst.forEach(e -> assertTrue(e instanceof Student)),
() -> schoolLst.forEach(e -> assertTrue(e instanceof School))
);
}
@Test
void givenJsonArray_whenListElementTypeDynamic_thenConvertToJavaListUsingJsonArray() {
List<Student> studentsLst = createListFromJsonArray(jsonArrayOfStudents, Student.class);
List<School> schoolLst = createListFromJsonArray(jsonArrayOfSchools, School.class);
assertAll(
() -> studentsLst.forEach(e -> assertTrue(e instanceof Student)),
() -> schoolLst.forEach(e -> assertTrue(e instanceof School))
);
}
@Test
void givenJsonArray_whenListElementTypeDynamic_thenConvertToJavaListUsingTypeTokenFromGuava() {
Gson gson = new Gson();
List<Student> studentsLst = gson.fromJson(jsonArrayOfStudents, getTypeForListUsingTypeTokenFromGuava(Student.class));
List<School> schoolLst = gson.fromJson(jsonArrayOfSchools, getTypeForListUsingTypeTokenFromGuava(School.class));
assertAll(
() -> studentsLst.forEach(e -> assertTrue(e instanceof Student)),
() -> schoolLst.forEach(e -> assertTrue(e instanceof School))
);
}
@Test
void givenJsonArray_whenListElementTypeDynamic_thenConvertToJavaListUsingParameterizedType() {
Gson gson = new Gson();
List<Student> studentsLst = gson.fromJson(jsonArrayOfStudents, ParameterizedTypeImpl.make(List.class, Student.class));
List<School> schoolLst = gson.fromJson(jsonArrayOfSchools, ParameterizedTypeImpl.make(List.class, School.class));
assertAll(
() -> studentsLst.forEach(e -> assertTrue(e instanceof Student)),
() -> schoolLst.forEach(e -> assertTrue(e instanceof School))
);
}
Type getGenericTypeForListFromTypeTokenUsingGetParameterized(Class elementClass) {
return TypeToken.getParameterized(List.class, elementClass).getType();
}
<T> List<T> createListFromJsonArray(String jsonArray, Type elementType) {
Gson gson = new Gson();
List<T> list = new ArrayList<>();
JsonArray array = gson.fromJson(jsonArray, JsonArray.class);
for(JsonElement element : array) {
T item = gson.fromJson(element, elementType);
list.add(item);
}
return list;
}
<T> Type getTypeForListUsingTypeTokenFromGuava(Class<T> type) {
return new com.google.common.reflect.TypeToken<List<T>>() {}
.where(new TypeParameter<T>() {}, type)
.getType();
}
}