【问题标题】:JsonDeserializer of nested json array (multiple type object) in retrofit2改造2中嵌套json数组(多类型对象)的JsonDeserializer
【发布时间】:2017-05-17 20:34:52
【问题描述】:

我的 json 响应

[
     [
        {
          "header_id": 1,
          "name" : "Tom",
          "group" : "A"
        },
        {
          "header_id": 2,
          "name" : "Marry",
          "group" : "B"
         }
    ],

    [
         {
             "object_id" : 1,
             "SerialNo" : 123456
         },
         {
             "object_id" : 2,
             "SerialNo" : 89545
         }
     ],

     [
        {
           "workflow_id" : 1,
           "StatusName" : "start"
         },
         {
            "workflow_id" : 2,
            "StatusName" : "end"
          }

    ]
]

Header.class

public class Header{
    @SerializedName("header_id")
    private int HeaderID;
    @SerializedName("name")
    private String name;
    @SerializedName("group")
    private String group;
}

ObjectWork.class

public class ObjectWork {
    @SerializedName("object_id")
    private int ObjectID;
    @SerializedName("SerialNo")
    private int SerialNo;
}

工作流.class

public class WorkFlow{
    @SerializedName("workflow_id")
    private int WorkflowID;
    @SerializedName("StatusName")
     private String statusName;
}

在 json 数组中,有 3 种类型的 json 对象。我将如何在改造 2 中设计 pojo 和自定义 JsonDeserializer。现在我使用 gson 来解析它。我不知道设计类来支持这个 json 并将其反序列化为 pojo 模型。

谢谢

【问题讨论】:

    标签: android json gson retrofit2


    【解决方案1】:

    由于 Gson 禁止 java.lang.Object 覆盖(注意推荐的 fieldNamesCaseThatIsAlwaysCamelCase),因此引入一个通用包装器让 Gson 识别您:

    abstract class AbstractCommon {
    }
    
    final class Header
            extends AbstractCommon {
    
        @SerializedName("header_id")
        final int headerId = Integer.valueOf(0);
    
        @SerializedName("name")
        final String name = null;
    
        @SerializedName("group")
        final String group = null;
    
        @Override
        public String toString() {
            return headerId + ": " + name;
        }
    
    }
    
    final class ObjectWork
            extends AbstractCommon {
    
        @SerializedName("object_id")
        final int objectId = Integer.valueOf(0);
    
        @SerializedName("SerialNo")
        final int serialNo = Integer.valueOf(0);
    
        @Override
        public String toString() {
            return objectId + ": " + serialNo;
        }
    
    }
    
    final class WorkFlow
            extends AbstractCommon {
    
        @SerializedName("workflow_id")
        final int workflowId = Integer.valueOf(0);
    
        @SerializedName("StatusName")
        final String statusName = null;
    
        @Override
        public String toString() {
            return workflowId + ": " + statusName;
        }
    
    }
    

    现在引入一个JsonDeserializer,它将尝试识别实际类型:

    private static final Gson gson = new GsonBuilder()
            .registerTypeAdapter(AbstractCommon.class, (JsonDeserializer<AbstractCommon>) (jsonElement, type, context) -> {
                final JsonObject jsonObject = jsonElement.getAsJsonObject();
                if ( jsonObject.has("header_id") ) {
                    return context.deserialize(jsonElement, Header.class);
                }
                if ( jsonObject.has("object_id") ) {
                    return context.deserialize(jsonElement, ObjectWork.class);
                }
                if ( jsonObject.has("workflow_id") ) {
                    return context.deserialize(jsonElement, WorkFlow.class);
                }
                throw new IllegalArgumentException("Cannot recognize: " + jsonElement);
            })
            .create();
    

    现在你可以轻松做到:

    private static final Type commonsType = new TypeToken<List<List<AbstractCommon>>>() {
    }.getType();
    
    public static void main(final String... args)
            throws IOException {
        try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q44034331.class, "arrays.json") ) {
            final List<List<AbstractCommon>> commons = gson.fromJson(jsonReader, commonsType);
            commons.stream()
                    .flatMap(Collection::stream)
                    .forEach(abstractCommon -> System.out.println(abstractCommon.getClass().getSimpleName() + ": " + abstractCommon));
        }
    }
    

    输出:

    标题:1:汤姆
    标题:2:结婚
    对象工作:1:123456
    对象工作:2:89545
    工作流程:1:开始
    工作流程:2:结束

    坦率地说,我觉得您的 JSON 有点奇怪(假设子数组元素 看起来确实彼此相关,但已解构):它有点像结构的由内而外。如果你可以控制 JSON 格式,我真的建议你重新设计它。如果它不在你的控制之下,看起来你需要这样的东西(这也可以使用 Gson 类型适配器):

    final class Wrapper {
    
        final Header header;
        final ObjectWork objectWork;
        final WorkFlow workFlow;
    
        Wrapper(final Header header, final ObjectWork objectWork, final WorkFlow workFlow) {
            this.header = header;
            this.objectWork = objectWork;
            this.workFlow = workFlow;
        }
    
    }
    
    private static Collection<Wrapper> combine(final List<List<AbstractCommon>> commons) {
        @SuppressWarnings({ "unchecked", "rawtypes" })
        final List<Header> headers = (List) commons.get(0);
        @SuppressWarnings({ "unchecked", "rawtypes" })
        final List<ObjectWork> objectWorks = (List) commons.get(1);
        @SuppressWarnings({ "unchecked", "rawtypes" })
        final List<WorkFlow> workFlows = (List) commons.get(2);
        final Iterator<Header> headerIterator = headers.iterator();
        final Iterator<ObjectWork> objectWorkIterator = objectWorks.iterator();
        final Iterator<WorkFlow> workFlowIterator = workFlows.iterator();
        final Collection<Wrapper> wrappers = new ArrayList<>();
        while ( headerIterator.hasNext() && objectWorkIterator.hasNext() && workFlowIterator.hasNext() ) {
            final Header header = headerIterator.next();
            final ObjectWork objectWork = objectWorkIterator.next();
            final WorkFlow workFlow = workFlowIterator.next();
            final Wrapper wrapper = new Wrapper(header, objectWork, workFlow);
            wrappers.add(wrapper);
        }
        return wrappers;
    }
    
    combine(commons)
            .forEach(wrapper -> System.out.println(wrapper.header + ", " + wrapper.objectWork + ", " + wrapper.workFlow));
    

    输出:

    1:汤姆,1:123456,1:开始
    2:结婚,2:89545,2:结束

    【讨论】:

      【解决方案2】:

      点击链接直接从 JSON 制作 pojo:http://www.jsonschema2pojo.org/

      package com.example;
      
      import com.google.gson.annotations.Expose;
      import com.google.gson.annotations.SerializedName;
      
      public class Example {
      
      @SerializedName("header_id")
      @Expose
      private Integer headerId;
      @SerializedName("name")
      @Expose
      private String name;
      @SerializedName("group")
      @Expose
      private String group;
      
      public Integer getHeaderId() {
      return headerId;
      }
      
      public void setHeaderId(Integer headerId) {
      this.headerId = headerId;
      }
      
      public String getName() {
      return name;
      }
      
      public void setName(String name) {
      this.name = name;
      }
      
      public String getGroup() {
      return group;
      }
      
      public void setGroup(String group) {
      this.group = group;
      }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-12
        • 2017-09-02
        • 2019-02-14
        • 1970-01-01
        • 2018-09-23
        • 1970-01-01
        • 2019-08-11
        • 2021-03-12
        相关资源
        最近更新 更多