gson-反序列化不同类型

0yycz8jy  于 2021-07-09  发布在  Java
关注(0)|答案(1)|浏览(315)

我正在处理传入的json字符串,并希望使用gson将它们反序列化为类型化的pojo对象。但是,推送字符串的服务器可以发送不同类型的对象—尽管类型是在json负载中定义的。
看下面两个json字符串,其中我有一个tradeevent和一个errorevent对象(还有其他5种类型,如settlementevent、paymentevent等)。
我如何将其反序列化到gson中的实际pojo(可能使用泛型),因为我直到运行时才知道类型-正如您所看到的,第二级元素包含实际的对象类型(tradeevent、errorevent等)。
还应该添加-在pojo方面,我是否将第二个元素(即tradeevent、errorevent)表示为对象或字符串?

  1. {
  2. "data": {
  3. "tradeEvent": {
  4. "tradeId": "2d28d464-a746-4c58-b19f-b586d2f5d015",
  5. "status": 2,
  6. "eventDescription": "Trade Settled"
  7. }
  8. }
  9. }
  10. {
  11. "data": {
  12. "errorEvent": {
  13. "Uuid": "3a36ae26-ba41-40d5-b11d-d8d842eb2356",
  14. "failureCode": 2, "tradeId": "2d28d464-a746-4c58-b19f-b586d2f5d015", "errorMessage": "Returned error: Exception while processing transaction: trade not matched"
  15. }
  16. }
  17. }

谢谢你的指导。

ipakzgxi

ipakzgxi1#

实现数据 Package 类以提取事件对象可能是最简单的方法:

  1. final class WrapperDto {
  2. @Nullable
  3. @SerializedName("data")
  4. @Expose(serialize = false, deserialize = true)
  5. private final DataDto data;
  6. @SuppressWarnings("unused")
  7. private WrapperDto(@Nullable final DataDto data) {
  8. this.data = data;
  9. }
  10. @Nullable
  11. <E extends Event> E toEvent() {
  12. if ( data == null ) {
  13. return null;
  14. }
  15. return data.toEvent();
  16. }
  17. private static final class DataDto {
  18. @Nullable
  19. @SerializedName("tradeEvent")
  20. @Expose(serialize = false, deserialize = true)
  21. private final Event.Trade tradeEvent;
  22. @Nullable
  23. @SerializedName("errorEvent")
  24. @Expose(serialize = false, deserialize = true)
  25. private final Event.Error errorEvent;
  26. @SuppressWarnings("unused")
  27. private DataDto(@Nullable final Event.Trade tradeEvent, @Nullable final Event.Error errorEvent) {
  28. this.tradeEvent = tradeEvent;
  29. this.errorEvent = errorEvent;
  30. }
  31. @Nullable
  32. private <E extends Event> E toEvent()
  33. throws IllegalStateException {
  34. @Nullable
  35. Event bestEvent = null;
  36. for ( final Event event : new Event[]{ tradeEvent, errorEvent } ) {
  37. if ( bestEvent == null ) {
  38. bestEvent = event;
  39. } else if ( event != null ) {
  40. throw new IllegalStateException("Ambiguity detected. event=" + event.getClass().getSimpleName() + ", bestEvent=" + bestEvent.getClass().getSimpleName());
  41. }
  42. }
  43. @SuppressWarnings("unchecked")
  44. final E castBestEvent = (E) bestEvent;
  45. return castBestEvent;
  46. }
  47. }
  48. }

我相信,这种方法比根据您的需要调整runtimetypeadapterfactory更容易实现。但是,实现自定义类型适配器可能会在读取时检测到不明确的字段,因此不会反序列化每个字段(这会花费更多的堆)。
上述方法将通过以下测试:

  1. private static final Gson gson = new GsonBuilder()
  2. .disableHtmlEscaping()
  3. .excludeFieldsWithoutExposeAnnotation()
  4. .create();
  5. ...
  6. try ( final JsonReader jsonReader = open("tradeEvent.json") ) {
  7. Assertions.assertTrue(gson.<WrapperDto>fromJson(jsonReader, WrapperDto.class).toEvent() instanceof Event.Trade);
  8. }
  9. try ( final JsonReader jsonReader = open("errorEvent.json") ) {
  10. Assertions.assertTrue(gson.<WrapperDto>fromJson(jsonReader, WrapperDto.class).toEvent() instanceof Event.Error);
  11. }
  12. Assertions.assertThrows(IllegalStateException.class, () -> {
  13. try ( final JsonReader jsonReader = open("tradeAndErrorEvent.json") ) {
  14. gson.<WrapperDto>fromJson(jsonReader, WrapperDto.class).toEvent();
  15. }
  16. });
展开查看全部

相关问题