【问题标题】:Java: How to write a generic that deserializes a list/collection?Java:如何编写反序列化列表/集合的泛型?
【发布时间】:2020-01-08 10:22:05
【问题描述】:

我正在尝试重构我的反序列化方法以使用泛型来反序列化任何类型。我可以对不在集合中的对象执行此操作,如下所示:

public static <T> T parseProductData(String jsonData, Class<T> typeClass) throws IOException, IllegalAccessException {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    T inputMessage = objectMapper.readValue(jsonData, typeClass);
    return inputMessage;
}

这是我要重构的方法:

public static List<ComponentPOCO> parseJsonComponentFromString(String fileContents){

        try {
            ObjectMapper mapper = new ObjectMapper()
                    .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
                    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            List<ComponentPOCO> component = mapper.readValue(fileContents, new TypeReference<List<ComponentPOCO>>() {});
            return component;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

这是我尝试重构方法以使用泛型的失败尝试:

public static List<T> T parseJsonComponentFromString(String fileContents, Class<T> typeClass){

        try {
            ObjectMapper mapper = new ObjectMapper()
                    .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
                    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            List<T> component = mapper.readValue(fileContents, new TypeReference<List<T>>() {});
            return component;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

但是,此代码无法编译,因为它没有正确使用 Java 泛型。如何将我的 JSON 对象反序列化为通用列表/集合/类似类型?

这是我反序列化到 ComponentPOCO 类中的数据示例:

[
      {   "artifactPathOrUrl": "http://www.java2s.com/Code/JarDownload/sample/sample.jar.zip",
        "namespace": "exampleNamespace1",
        "name": "exampleName1",
        "tenant": "exampleTenant1"
      },

      {   
        "artifactPathOrUrl": "http://www.java2s.com/Code/JarDownload/sample-calculator/sample-calculator-bundle-2.0.jar.zip",
        "namespace": "exampleNamespace1",
        "name": "exampleName2",
        "tenant": "exampleTenant1"
      },
      {   
        "artifactPathOrUrl": "http://www.java2s.com/Code/JarDownload/helloworld/helloworld.jar.zip",
        "namespace": "exampleNamespace1",
        "name": "exampleName3",
        "tenant": "exampleTenant1"
      },
      {   
        "artifactPathOrUrl": "http://www.java2s.com/Code/JarDownload/fabric-activemq/fabric-activemq-demo-7.0.2.fuse-097.jar.zip",
        "namespace": "exampleNamespace1",
        "name": "exampleName4",
        "tenant": "exampleTenant1"
      }
]

这里是ComponentPOCO类型的代码:

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import lombok.experimental.Accessors;
import org.apache.pulsar.common.io.SinkConfig;
import org.apache.pulsar.common.io.SourceConfig;

import java.util.List;
import java.util.Map;

@Setter
@Getter
@EqualsAndHashCode
@ToString
@Accessors(chain = true)
@Data
public class ComponentPOCO {
    @JsonProperty
    private String namespace;
    @JsonProperty
    private String tenant;
    @JsonProperty
    private String name;
    @JsonProperty
    private String type;
    @JsonProperty
    private String destinationTopicName;
    @JsonProperty
    private String artifactPathOrUrl;
    @JsonProperty
    private String className;
    @JsonProperty
    private List<String> inputs;
    @JsonProperty
    private String output;
    @JsonProperty
    private Map<String, Object> userConfig;
    @JsonProperty
    private String logTopic;
    @JsonProperty
    private Map<String, Object> configs;
    @JsonProperty
    private Integer parallelism;
    @JsonProperty
    public String sinkType;
    @JsonProperty
    private String sourceType;
    @JsonProperty
    public String runtimeFlags;
}

【问题讨论】:

标签: java list generics arraylist jackson


【解决方案1】:

您的代码存在几个问题。按照我的想法,让这段代码工作的最快方法是用这个方法替换该方法:

public LinkedHashMap<String,T> parseJsonComponentFromString(String fileContents){
        try {
            ObjectMapper mapper = new ObjectMapper()
                    .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
                    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            return mapper.readValue(fileContents, new TypeReference<T>() {});
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

因为 ObjectMapper.readValue 返回 LinkedHashMap&lt;String,T&gt;(我不知道为什么它在 javadocs 中只显示 T)

然后,如果您知道密钥,则使用 get(key_name) 查找解析的字符串,如果您不知道并且不想假设它们,则使用 forEach 查找。最后一个更好,但需要您使用 java 8+ 并了解 lambda 表达式和函数式接口。 Here 一个教程。 Here另一个。

顺便说一下,我再次借此机会指出这段代码有很多错误,您可能需要重新设计整个系统。如果您真的真的必须使用 List,那么您会遇到不同的问题:“如何将 LinkedHashMap 转换为 List?”。猜猜最快的方法是实现前面提到的 forEach 并将每个元素推送到列表中。

也就是说,是这样的:

LinkedHashMap<String,Integer> linkedHashMap = XXX.parseJsonComponentFromString(yyy);
LinkedList<T> list = new LinkedList<T>();     
linkedHashMap.forEach((k,i) -> list.add(i));

希望我能帮上忙。

【讨论】:

  • “您可能想要重新设计整个系统”是什么意思?我的目标是简单地反序列化 JSON 对象的集合/列表/任何内容,以便我可以处理每个对象。我不确定我是否理解那里的设计缺陷。
  • 例如,没有必要使用列表:只需使用我展示的 LinkedHasMap。我只是假设类似的事情发生在你项目的其他地方
  • LinkedHashMap中的字符串代表什么?
  • 这是JSON 上的“变量名”。例如,以 json 为例:{ "a":100, "b":"bruno", "c":true } String 代表单词“a”、“b”或“c”。
  • 这违反了我的用例。我的变量没有命名。请在我的编辑中查看数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-03
  • 1970-01-01
  • 2017-01-04
相关资源
最近更新 更多