我有一个简单的Json结构,如:
{"MessageType":"TimeData","TimeData":{"hh":12,"mm":13,"ms":15,"ss":14}}
我设计了以下类来反序列化它:
public class JsonMessage
{
public enum MessageTypes{
WhoAreYou,
TimeData
}
JsonMessage(){
}
public MessageTypes MessageType;
}
class TimeData extends JsonMessage{
int hh;
int mm;
int ss;
int ms;
TimeData() {
}
}
我需要将反序列化拆分为两个阶段:
1-反序列化以阅读MessageType
。
2-继续基于MessageType
代码很简单:
public void dispatch(Object message, IoSession session)
{
Gson gson = new Gson();
JsonMessage result = gson.fromJson(message.toString(), JsonMessage.class);
System.out.println(result.MessageType.toString());
switch (result.MessageType)
{
case WhoAreYou:{
//.....
break;
}
case TimeUpdate:
TimeData res = new Gson().fromJson(message.toString(), TimeData.class);
System.out.println(res.hh);
break;
default:break;
}
}
我的程序可以输入正确的switch-case
(TimeUpdate
),但它无法正确解析(println打印0而不是12)
你认为我做错了什么? 谢谢
答案 0 :(得分:5)
问题是你的JSON代表一个Object,它包含你感兴趣的另一个对象,而你的Java只是一个对象。
您实际上可以为每种类型编写反序列化器,并在确定MessageType
后使用它们:
public static void main(String[] args)
{
Gson gson = new GsonBuilder().registerTypeAdapter(TimeData.class, new TimeDataDeserializer()).create();
String json = "{\"MessageType\":\"TimeData\",\"TimeData\":{\"hh\":12,\"mm\":13,\"ms\":15,\"ss\":14}}";
JsonMessage message = gson.fromJson(json, JsonMessage.class);
switch(message.MessageType)
{
case TimeData:
TimeData td = new GsonBuilder()
.registerTypeAdapter(TimeData.class, new TimeDataDeserializer())
.create()
.fromJson(json, TimeData.class);
td.MessageType = message.MessageType
System.out.println(td.hh);
break;
default:
break;
}
}
class TimeDataDeserializer implements JsonDeserializer<TimeData>
{
@Override
public TimeData deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException
{
JsonObject jo = je.getAsJsonObject().getAsJsonObject("TimeData");
Gson g = new Gson();
return g.fromJson(jo, TimeData.class);
}
}
答案 1 :(得分:1)
我设法通过以下方式实现自定义JsonDeserializer
来解决此类问题。
首先根据类型和方法将您的枚举附加到您的枚举中,以根据枚举名称检索正确的Class<?>
:
enum MessageType {
WHO_ARE_YOU(WhoAreYou.class),
TIME_UPDATE(TimeUpdate.class);
public final Class<?> clazz;
MessageType(Class<?> clazz) { this.clazz = clazz; }
public static MessageType forName(String name) {
for (MessageType t : values())
if (name.equals(t.name()))
return t;
return NULL;
}
}
然后在deserialize
方法中我执行了以下操作:
public JsonMessage deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
JsonObject object = json.getAsJsonObject();
String kind = object.get("messageType").getAsString();
Class<?> clazz = MessageType.forName(kind).clazz;
JsonMessage result = null;
try {
result = (JsonMessage)clazz.newInstance();
Field[] fs = clazz.getFields();
for (Field f : fs) {
Object value = context.deserialize(object.get(f.getName()), f.getType());
if (value != null)
f.set(result, value);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
所有内容都通过反射进行管理,以便创建正确的对象,然后相应地反序列化所有字段。
我有一个复杂的对象层次结构,所以我更喜欢这样让gson反序列化器管理所有东西。当然,您需要使用gson解析器实例注册序列化程序。
注意:根据Java标准,您的命名非常不正确。枚举常量应为ALL_CAPITALIZED
,枚举类名应为单数(例如MessageType
)。应该实例化变量(例如messageType
而非MessageType
)