简体   繁体   English

Java:如何编写一个反序列化列表/集合的泛型?

[英]Java: How to write a generic that deserializes a list/collection?

I'm attempting to refactor my deserialization method to use generics to enable me to deserialize any type.我正在尝试重构我的反序列化方法以使用泛型来反序列化任何类型。 I can do this just fine for objects that are not in a collection, like this:对于不在集合中的对象,我可以很好地执行此操作,如下所示:

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;
}

Here is the method that I want to refactor:这是我要重构的方法:

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;
    }

Here is my failed attempt to refactor the method to use generics:这是我重构方法以使用泛型的失败尝试:

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;
    }

However, this code doesn't compile because it's not using Java generics correctly.但是,此代码无法编译,因为它没有正确使用 Java 泛型。 How could I deserialize my JSON objects into a generic list/collection/something-similar type?如何将我的 JSON 对象反序列化为通用列表/集合/类似类型?

Here is an example of the data that I'm deserializing into the ComponentPOCO class:这是我反序列化到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"
      }
]

Here is the code of the ComponentPOCO type:下面是 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;
}

There are several problems with your code.您的代码有几个问题。 The quickiest way to make this code work as I think you want is to replace the method with this one:使此代码按我想的方式工作的最快方法是用以下方法替换该方法:

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;
    }

because ObjectMapper.readValue returns a LinkedHashMap<String,T> (I have no idea why it says just T in the javadocs)因为ObjectMapper.readValue返回一个LinkedHashMap<String,T> (我不知道为什么它在 javadocs 中只说 T)

Then you look up your parsed string with get(key_name) if you know the keys or forEach if you don't and don't want to assume them.然后,如果您知道键,则使用get(key_name)查找解析后的字符串,如果不知道也不想假设它们,则forEach查找。 This last one is better but would require you to use java 8+ and to know about lambda expressions and functional interfaces.最后一个更好,但需要您使用 java 8+ 并了解 lambda 表达式和函数式接口。 Here a tutorial.这里有一个教程。 Here another one.这是另一个。

By the way, I take chance again to point out there is much wrong with this code, you may want to re-design your whole system.顺便说一句,我再次借机指出这段代码有很多错误,您可能需要重新设计整个系统。 If you really really really must use a List, than you have a different problem: " How to convert a LinkedHashMap to a List? ".如果您真的真的必须使用列表,那么您会遇到不同的问题:“如何将 LinkedHashMap 转换为列表? ”。 Guess the quickiest way whould be implement the forEach mentioned earlier and push each element on the List.猜猜最快捷的方法是实现前面提到的 forEach 并将每个元素推送到 List 上。

That is, something like this:也就是说,像这样:

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

Hope I helped.希望我有所帮助。

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

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