问题
Using Gson
to deserialize objects of a parameterized class Container<T>
, results in the java.lang.ClassCastException
for certain values of T
, e.g. for a simple Record
type consisting of String
and List<String>
fields:
com.google.gson.internal.LinkedTreeMap cannot be cast to Record
Interestingly enough, the same code works when calling the fromJson()
method inline, i.e. the following statement does return a valid value:
Container<Record> value = new Gson().fromJson(
json, new TypeToken<Container<Record>>(){}.getType());
The definition of Container<T>
is simple, too:
public class Container<T> {
private static final Gson PARSER = new Gson();
private String id;
private List<T> content;
private Object data;
public static <T> Container<T> deserialize(String json, Class<T> type) {
return PARSER.fromJson(json, new TypeToken<Container<T>>(){}.getType());
}
}
Changing the deserialize()
method to non-static does not resolve the issue.
Any ideas?
回答1:
You want ParameterizedType my solution is create
public static <T> Container<T> deserialize(String json, Class<T> clazz) {
Type type = TypeToken.getParameterized(Container.class,clazz).getType();
return new Gson().fromJson(json, type);
}
problem is T because Java does not know what i kind and generate Type of T
public static <T> Container<T> sec(String json, Class<T> clazz) {
Type type1 = new TypeToken<Container<T>>() { }.getType();
Type type = TypeToken.getParameterized(Container.class,clazz).getType();
System.out.println(type1); //==>pl.jac.container.Container<T>
System.out.println(type); //==>pl.jac.container.Container<pl.jac.container.Record>
return new Gson().fromJson(json, type);
}
this is test for more example to correct run test testContainerRecord2 is for your problem
import java.lang.reflect.Type;
import org.junit.Test;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import static org.junit.Assert.assertEquals;
public class ContainerTest {
@Test
public void testContainerRecord() {
//given
String json = "{\"id\":\"new ID\",\"content\":[{\"id\":\"50e0300a-6668-42b3-a474-81a6a08f773f\"},{\"id\":\"f0bee3f3-2c40-4b44-8608-a6fedb226b7a\"}],\"data\":\"AAAAAAAA\"}";
//when
Container<Record> containerRecord = Container.deserializeClass(json, ContainerRecord.class);
//then
assertEquals("50e0300a-6668-42b3-a474-81a6a08f773f", containerRecord.content.get(0).id);
assertEquals("f0bee3f3-2c40-4b44-8608-a6fedb226b7a", containerRecord.content.get(1).id);
}
@Test
public void testContainerRecord2() {
//given
String json = "{\"id\":\"new ID\",\"content\":[{\"id\":\"50e0300a-6668-42b3-a474-81a6a08f773f\"},{\"id\":\"f0bee3f3-2c40-4b44-8608-a6fedb226b7a\"}],\"data\":\"AAAAAAAA\"}";
//when
Container<Record> containerRecord = Container.deserialize(json, Record.class);
//then
assertEquals("50e0300a-6668-42b3-a474-81a6a08f773f", containerRecord.content.get(0).id);
assertEquals("f0bee3f3-2c40-4b44-8608-a6fedb226b7a", containerRecord.content.get(1).id);
}
@Test
public void testGenericWithType() {
//given
String json = "{\"id\":\"new ID\",\"content\":[{\"id\":\"50e0300a-6668-42b3-a474-81a6a08f773f\"},{\"id\":\"f0bee3f3-2c40-4b44-8608-a6fedb226b7a\"}],\"data\":\"AAAAAAAA\"}";
//when
Type type = new TypeToken<Container<Record>>() {
}.getType();
Container<Record> containerRecord = Container.deserializeType(json, type);
//then
assertEquals("50e0300a-6668-42b3-a474-81a6a08f773f", containerRecord.content.get(0).id);
assertEquals("f0bee3f3-2c40-4b44-8608-a6fedb226b7a", containerRecord.content.get(1).id);
}
@Test
public void testRecord() {
//given
String json = "{\"id\":\"new ID\",\"content\":[{\"id\":\"50e0300a-6668-42b3-a474-81a6a08f773f\"},{\"id\":\"f0bee3f3-2c40-4b44-8608-a6fedb226b7a\"}],\"data\":\"AAAAAAAA\"}";
//when
ContainerRecord containerRecord = new Gson().fromJson(json, ContainerRecord.class);
//then
assertEquals("50e0300a-6668-42b3-a474-81a6a08f773f", containerRecord.content.get(0).id);
assertEquals("f0bee3f3-2c40-4b44-8608-a6fedb226b7a", containerRecord.content.get(1).id);
}
@Test
public void testRecordWithType() {
//given
String json = "{\"id\":\"new ID\",\"content\":[{\"id\":\"50e0300a-6668-42b3-a474-81a6a08f773f\"},{\"id\":\"f0bee3f3-2c40-4b44-8608-a6fedb226b7a\"}],\"data\":\"AAAAAAAA\"}";
//when
Type type = new TypeToken<Container<Record>>() {
}.getType();
Container<Record> containerRecord = new Gson().fromJson(json, type);
//then
assertEquals("50e0300a-6668-42b3-a474-81a6a08f773f", containerRecord.content.get(0).id);
assertEquals("f0bee3f3-2c40-4b44-8608-a6fedb226b7a", containerRecord.content.get(1).id);
}
@Test
public void testContainerString() {
//given
String json = "{\"id\":\"new ID\",\"content\":[\"37c84304-ab80-4f92-8b2a-710b362ecb3f\"],\"data\":\"AAAAAAAA\"}";
//when
Type type = new TypeToken<Container<String>>() {
}.getType();
Container<String> containerRecord = new Gson().fromJson(json, type);
//then
assertEquals("37c84304-ab80-4f92-8b2a-710b362ecb3f", containerRecord.content.get(0));
}
}
my class Record
public class Record {
public String id;
}
and my Container
public class ContainerRecord extends Container<Record> {
}
and Container
public class Container<T> {
public String id;
public List<T> content;
public Object data;
public static <T> Container<T> deserializeClass(String json, Class<? extends Container<T>> type) {
return new Gson().fromJson(json, type);
}
public static <T> Container<T> deserializeType(String json, Type type) {
return new Gson().fromJson(json, type);
}
public static <T> Container<T> deserialize(String json, Class<T> clazz) {
Type type = TypeToken.getParameterized(Container.class,clazz).getType();
return new Gson().fromJson(json, type);
}
}
来源:https://stackoverflow.com/questions/55175941/gson-classcastexception-linkedtreemap