重构方法以使用泛型进行反序列化

重构方法以使用泛型进行反序列化

问题描述:

这是我要重构的方法:

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

我正在尝试重构反序列化方法以使用泛型使我能够反序列化任何类型。我可以对不在集合中的对象做到这一点,就像这样:

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

以下是我将数据反序列化为 ComponentPOCO 类:

Here is an example of the data that I'm deserializing into the ComponentPOCO class:

[
      {   "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类型的代码:

Here is the code of the ComponentPOCO type:

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

有没有办法让我使用类似这样的泛型反序列化整个列表?

Is there a way to enable me to deserialize an entire list using generics like this?

您可以提取与 Jackson 的所有互动上课,把所有的困难藏在那里。 ObjectMapper 可以创建和配置一次。对于单个对象,您可以使用 readValue(String content,Class< T> valueType)方法,对于集合,您需要构建 TypeReference 并使用 readValue(String content,TypeReference valueTypeRef)方法。简单的实现可能如下所示:

You can extract all kind of interaction with Jackson to extra class and hide all difficulties there. ObjectMapper can be created and configured once. For single object you can use readValue(String content, Class<T> valueType) method and for collection you need to build TypeReference and use readValue(String content, TypeReference valueTypeRef) method. Simple implementation could look like below:

class JsonMapper {

  private final ObjectMapper mapper = new ObjectMapper();

  public JsonMapper() {
    // configure mapper instance if required
    mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    // etc...
  }

  public String serialise(Object value) {
    try {
      return mapper.writeValueAsString(value);
    } catch (JsonProcessingException e) {
      throw new IllegalStateException("Could not generate JSON!", e);
    }
  }

  public <T> T deserialise(String payload, Class<T> expectedClass) {
    Objects.requireNonNull(payload);
    Objects.requireNonNull(expectedClass);

    try {
      return mapper.readValue(payload, expectedClass);
    } catch (IOException e) {
      throw new IllegalStateException("JSON is not valid!", e);
    }
  }

  public <T> List<T> deserialiseList(String payload, Class<T> expectedClass) {
    Objects.requireNonNull(payload);
    Objects.requireNonNull(expectedClass);

    try {
      return mapper.readValue(payload, constructListTypeOf(expectedClass));
    } catch (IOException e) {
      throw new IllegalStateException("JSON is not valid!", e);
    }
  }

  private <T> CollectionType constructListTypeOf(Class<T> expectedClass) {
    return mapper.getTypeFactory().constructCollectionType(List.class, expectedClass);
  }
}

和用法:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

public class JsonApp {

  public static void main(String[] args) {
    JsonMapper mapper = new JsonMapper();
    System.out.println(mapper.deserialise("{\"id\":1233}", A.class));
    System.out.println(mapper.deserialiseList("[{\"id\":4567}]", A.class));
  }
}

class A {
  private int id;

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  @Override
  public String toString() {
    return "A{" + "id=" + id + '}';
  }
}

以上代码打印:

A{id=1233}
[A{id=4567}]

另请参见: