- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我目前正在研究在Android上使用Gson for Json,刚遇到这个问题。假设我们有如下类:
class Command {
public int id = COMMAND_ID_UNSPECIFIED;
}
class CommandSpecific1 extends Command{
public String specialStr;
public CommandSpecific1 () {
id = COMMAND_ID_SPECIAL1;
specialStr= "special";
}
}
class CommandSpecific2 extends Command{
public int specialInt;
public CommandSpecific2 () {
id = COMMAND_ID_SPECIAL2;
specialInt = 3.1415926;
}
}
我使用以下代码创建 Json 字符串
CommandSpecific specialCmd = new CommandSpecific();
Gson gson = new Gson();
String json = gson.toJson(specialCmd);
现在我想做这样的事情(错误的代码)
Command genericCmd = gson.fromJson(json, Command.class)
if(genericCmd.id == COMMAND_ID_SPECIAL1) {
CommandSpecific1 cmd1 = (CommandSpecific1)genericCmd;
//do sth with cmd1.specialStr
} else if(genericCmd.id == COMMAND_ID_SPECIAL2) {
CommandSpecific2 cmd2 = (CommandSpecific2)genericCmd;
//do sth with cmd2.specialInt
}
代码不起作用,因为 gson.fromJson(json, Command.class) 只为父类(super class)创建对象。我知道我可以调用 fromJson 并指定真实的类类型,但是有没有更好的方法呢?我应该使用定制的反序列化方法来解决这个问题吗?怎么办?
最佳答案
我会尝试像这个准备运行的例子那样反序列化。作为评论,您不想使用 id 字段在命令之间切换,因此您必须信任字段结构并假设每个子类都存在一个唯一标识您的子类的字段组合。
package stackoverflow.questions.q20185625;
import java.lang.reflect.Type;
import com.google.gson.*;
public class Q20185625 {
public static class Command {
public int id = -1;
}
public static class CommandSpecific1 extends Command {
public String specialStr;
public CommandSpecific1() {
id = 1;
specialStr = "special";
}
}
public static class CommandSpecific2 extends Command {
public int specialInt;
public CommandSpecific2() {
id = 2;
specialInt = 42;
}
}
public static class CustomDeserializer implements JsonDeserializer<Command> {
public Command deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json == null)
return null;
else {
JsonElement e = json.getAsJsonObject().get("specialStr");
if (e != null && e.isJsonPrimitive() && e.getAsString() instanceof String) {
CommandSpecific1 c = new CommandSpecific1();
c.specialStr = e.getAsString(); // do you need this?
return c;
}
e = json.getAsJsonObject().get("specialInt");
if (e != null && e.isJsonPrimitive() && e.getAsNumber() instanceof Number) {
CommandSpecific2 c = new CommandSpecific2();
c.specialInt = e.getAsInt(); // do you need this?
return c;
}
return null; // or throw an IllegalArgumentException
}
}
}
public static void main(String[] args) {
GsonBuilder gb = new GsonBuilder();
gb.registerTypeAdapter(Command.class, new CustomDeserializer());
Gson customGson = gb.create();
String jsonTest1 = "{\"specialStr\":\"AA\"}";
String jsonTest2 = "{\"specialInt\":13}";
String jsonTest3 = "{}";
String jsonTest4 = "";
System.out.println("Deserialize test 1: " + customGson.fromJson(jsonTest1, Command.class));
System.out.println("Deserialize test 2: " + customGson.fromJson(jsonTest2, Command.class));
System.out.println("Deserialize test 3: " + customGson.fromJson(jsonTest3, Command.class));
System.out.println("Deserialize test 4: " + customGson.fromJson(jsonTest4, Command.class));
}
}
这就是结果(我避免使用 toString,向您展示类类型)
Deserialize test 1: stackoverflow.questions.qww.Q20185625$CommandSpecific1@30d5aa
Deserialize test 2: stackoverflow.questions.qww.Q20185625$CommandSpecific2@13552ed
Deserialize test 3: null
Deserialize test 4: null
编辑如果您的 JSON 还包含 id
字段,则更容易。您始终可以使用 TypeAdapter,但要以一种直接的方式:
public static class CustomDeserializer implements JsonDeserializer<Command> {
public Command deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json == null)
return null;
else {
// null management can be improved
int id = json.getAsJsonObject().get("id").getAsInt();
switch(id){
case COMMAND_TYPE_1:
return context.deserialize(json, CommandSpecific1.class);
case COMMAND_TYPE_2:
return context.deserialize(json, CommandSpecific2.class);
default:
return null;
}
}
}
}
但是,如果您对 JSON 的其余部分感兴趣并且担心性能(但这不是原始问题,您询问的是子类化问题),您可以尝试 TypeAdapter
。
关于android - JSON(Gson)反序列化为父类(super class)对象然后转换为子类对象的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20185625/
出于好奇,我尝试了一些原型(prototype)制作,但似乎只允许在第一个位置使用子例程的原型(prototype) &。 当我写作时 sub test (&$$) { do_somethin
我需要开发一个类似于 Android Play 商店应用程序或类似 this app 的应用程序.我阅读了很多教程,发现几乎每个教程都有与 this one 类似的例子。 . 我已经开始使用我的应用程
考虑一个表示“事件之间的时间”的列: (5, 40, 3, 6, 0, 9, 0, 4, 5, 18, 2, 4, 3, 2) 我想将这些分组到 30 个桶中,但桶会重置。期望的结果: (0, 1,
我是一名优秀的程序员,十分优秀!