重构方法以使用泛型进行反序列化
这是我要重构的方法:
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}]
另请参见:
- How do I parametrize response parsing in Java?
- Deserializing or serializing any type of object using Jackson ObjectMapper and handling exceptions