简体   繁体   English

Spring JSON序列化,Gson反序列化

[英]Spring JSON serialization, Gson deserialization

I'm currently having an issue with the deserialization of certain inner-objects, in spring, I initialize all of my objects before outputting them using @ResponseBody . 我目前遇到了某些内部对象反序列化的问题,在Spring中,我在使用@ResponseBody输出它们之前初始化所有对象。

As an example, this is a response: 举个例子,这是一个回应:

[{id:1, location:{id:1, ... extra location data}},
 {id:2, location:1}
]

Now, GSON throws an error as it is not able to understand that location:1 refers to the location object already deserialized in the previous object. 现在,GSON抛出一个错误,因为它无法理解该location:1指的是在前一个对象中已经反序列化的位置对象。 Deserialization is done in the following method: 反序列化按以下方法完成:

@Override
public void handleReader(Reader reader) {
    try {
        String json = readerToString(reader);
        T object = getGson().fromJson(json, returnType);
        handleObject(object);
    } catch (Exception e) {
        Sentry.captureException(e);
    }
}

As an example, this is called through a regular generic class, I'd use the type Event[] as the T generic in order to return an array. 例如,这是通过常规泛型类调用的,我使用类型Event[]作为T泛型以返回数组。

How can I either fix this using Gson or make spring output the full data every time? 我怎样才能使用Gson修复此问题或每次弹出输出完整数据? Ideally I'd like to fix with Gson as it would allow for seriously reduced bandwidth but I'm not too fussed at this point. 理想情况下,我想修复Gson,因为这样可以大幅降低带宽,但此时我并不太感兴趣。

My Spring returning method is as follows: 我的Spring返回方法如下:

@Override
public List<T> list() {
    return service.findAll();
}

with the initialization like so: 初始化如下:

@Override
@Transactional
public List<Event> findAll() {
    List<Event> list = eventRepository.findByArchivedFalse();
    for (Event event : list) {
        this.initialize(event);
    }
    return list;
}
@Override
public Event initialize(Event obj) {
    Hibernate.initialize(obj.getLocation());
    Hibernate.initialize(obj.getLocation().get... inner data here);
    return obj;
}

I imagine this is going to require a real structure review but, if I can help it, I'd like to keep the structure roughly the same. 我想这需要一个真正的结构审查,但是,如果我能帮助它,我想保持结构大致相同。

You're going to have to write a custom deserializer, if you're not willing to change the JSon. 如果你不愿意改变JSon,你将不得不编写自定义反序列化器。 However, changing the JSon is exactly what I would recommend. 但是,更改JSon正是我建议的。

Option 1: Changing the JSon 选项1:更改JSon

I think the right thing to do is to have two separate messages, eg 我认为正确的做法是有两个单独的消息,例如

{
  "uniqueLocations":
    [
      {"id":1, ... extra location details} ,
    ],
  "locationMap":
    [ 
      {"id":1,"location":1},
      {"id":2,"location":1}
      ... etc.
    ]
}

This is clearer; 这更清楚; this separates your json so that you always have the same types of data in the same places. 这会将您的json分开,以便您在相同位置始终拥有相同类型的数据。


Option 2: Making Gson able to do more complicated deserializations 选项2:让Gson能够进行更复杂的反序列化

However, if you're not willing to do that, you could write a custom deserializer. 但是,如果您不愿意这样做,您可以编写自定义反序列化程序。 The most straightforward way to do that, extending TypeAdapter , only uses specific, concrete classes, not parameterized types . 最直接的方法是扩展TypeAdapter ,它只使用特定的具体类, 而不是参数化类型 However, if you want to use a parameterized type, you must use a TypeAdapterFactory . 但是,如果要使用参数化类型,则必须使用TypeAdapterFactory

You can read more about how to do this here: How do I implement TypeAdapterFactory in Gson? 您可以在此处阅读有关如何执行此操作的更多信息: 如何在Gson中实现TypeAdapterFactory?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM