diff --git a/json-modules/gson-2/pom.xml b/json-modules/gson-2/pom.xml
index c3935d5721..1184af14ec 100644
--- a/json-modules/gson-2/pom.xml
+++ b/json-modules/gson-2/pom.xml
@@ -18,6 +18,11 @@
gson
${gson.version}
+
+ com.google.guava
+ guava
+ ${guava.version}
+
diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/ParameterizedTypeImpl.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/ParameterizedTypeImpl.java
new file mode 100644
index 0000000000..cb22bd8012
--- /dev/null
+++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/ParameterizedTypeImpl.java
@@ -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;
+ }
+}
diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/School.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/School.java
new file mode 100644
index 0000000000..fc1d72fa29
--- /dev/null
+++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/School.java
@@ -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;
+ }
+}
diff --git a/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/Student.java b/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/Student.java
new file mode 100644
index 0000000000..06fb1e3d44
--- /dev/null
+++ b/json-modules/gson-2/src/main/java/com/baeldung/gson/jsontolist/type/Student.java
@@ -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;
+ }
+}
diff --git a/json-modules/gson-2/src/test/java/com/baeldung/gson/jsontolist/type/JsonArrayStringToListUnitTest.java b/json-modules/gson-2/src/test/java/com/baeldung/gson/jsontolist/type/JsonArrayStringToListUnitTest.java
new file mode 100644
index 0000000000..fe7ffed573
--- /dev/null
+++ b/json-modules/gson-2/src/test/java/com/baeldung/gson/jsontolist/type/JsonArrayStringToListUnitTest.java
@@ -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> typeTokenForListOfStudents = new TypeToken>(){};
+ TypeToken> typeTokenForListOfSchools = new TypeToken>(){};
+ List studentsLst = gson.fromJson(jsonArrayOfStudents, typeTokenForListOfStudents.getType());
+ List 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 studentsLst = gson.fromJson(jsonArrayOfStudents, new ListWithDynamicTypeElement().getType());
+ assertFalse(studentsLst.get(0) instanceof Student);
+ assertThrows(ClassCastException.class, () -> studentsLst.forEach(e -> assertTrue(e instanceof Student)));
+ }
+
+ class ListWithDynamicTypeElement {
+ Type getType() {
+ TypeToken> typeToken = new TypeToken>(){};
+ return typeToken.getType();
+ }
+ }
+
+ @Test
+ void givenJsonArray_whenListElementTypeDynamic_thenConvertToJavaListUsingGetParameterized() {
+ Gson gson = new Gson();
+ List studentsLst = gson.fromJson(jsonArrayOfStudents, getGenericTypeForListFromTypeTokenUsingGetParameterized(Student.class));
+ List 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 studentsLst = createListFromJsonArray(jsonArrayOfStudents, Student.class);
+ List 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 studentsLst = gson.fromJson(jsonArrayOfStudents, getTypeForListUsingTypeTokenFromGuava(Student.class));
+ List 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 studentsLst = gson.fromJson(jsonArrayOfStudents, ParameterizedTypeImpl.make(List.class, Student.class));
+ List 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();
+ }
+
+ List createListFromJsonArray(String jsonArray, Type elementType) {
+ Gson gson = new Gson();
+ List 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;
+ }
+
+ Type getTypeForListUsingTypeTokenFromGuava(Class type) {
+ return new com.google.common.reflect.TypeToken>() {}
+ .where(new TypeParameter() {}, type)
+ .getType();
+ }
+
+}