自定义反序列化方法
方法一,枚举保存类名与实现类的关系
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import lab.workflow.constant.WorkFlowType;
import lab.workflow.dto.node.WorkflowNode;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.ObjectUtils;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Set;
import java.util.TimeZone;
@Configuration
@Slf4j
public class JsonConfiguration {
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper){
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
SimpleModule module = new SimpleModule();
module.addDeserializer(WorkflowNode.class, new WorkflowNodeDeserializer());
objectMapper.registerModule(module);
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
return mappingJackson2HttpMessageConverter;
}
public static class WorkflowNodeDeserializer extends JsonDeserializer<WorkflowNode> {
Reflections reflections =new Reflections("lab.workflow.dto.node.*");
Set<Class<? extends WorkflowNode>> nodeClass = reflections.getSubTypesOf(WorkflowNode.class);
static ObjectMapper objectMapper = new ObjectMapper();
static {
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
SimpleModule module = new SimpleModule();
module.addDeserializer(WorkflowNode.class, new WorkflowNodeDeserializer());
objectMapper.registerModule(module);
}
public WorkflowNodeDeserializer() {
}
@Override
public WorkflowNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
try {
JsonNode treeNode = p.getCodec().readTree(p);
String type = treeNode.get("type").asText();
log.info(nodeClass.toString());
if(!ObjectUtils.isEmpty(type)){
WorkFlowType workFlowType = WorkFlowType.getByName(type);
if(workFlowType != null){
Class<? extends WorkflowNode> tClass = null;
for (Class<? extends WorkflowNode> aClass : nodeClass) {
if(aClass.getSimpleName().equals(workFlowType.getSimpleName())){
tClass = aClass;
break;
}
}
log.info("tClass:{}", tClass);
if(tClass != null){
return objectMapper.readValue(treeNode.toString(), tClass);
}
}
}
log.info("deserialize is null");
return null;
}catch (Exception e){
log.error(e.getMessage(), e);
throw e;
}
}
}
}
抽象类结构如下
发射工具包:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.12</version>
</dependency>
对应git地址:https://github.com/ronmamo/reflections
方法二 将判断的行为由枚举绑定改为方法(更加灵活)
public static class NodeDeserializer extends JsonDeserializer<Node> {
final Set<Class<? extends Node>> nodeClasses;
final Map<String, Object> map;
public NodeDeserializer() {
Reflections reflections =new Reflections("catl.model.mongo.flow.node.impl.*");
nodeClasses = new HashSet<>();
Set<Class<? extends AbstractNodePoint>> nodeImplClasses = reflections.getSubTypesOf(AbstractNodePoint.class);
nodeClasses.add(LinkNode.class);
nodeClasses.addAll(nodeImplClasses);
map = new HashMap<>();
for (Class<? extends Node> nodeClass : nodeClasses) {
try {
Constructor<? extends Node> constructor = nodeClass.getConstructor();
constructor.setAccessible(true);
map.put(nodeClass.getSimpleName(), constructor.newInstance());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
@Override
public Node deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws JsonProcessingException {
try {
JsonNode treeNode = jsonParser.getCodec().readTree(jsonParser);
String nodeType = treeNode.get("shape").asText();
for (Class<? extends Node> nodeClass : nodeClasses) {
Method method = nodeClass.getMethod("isSupport", String.class);
method.setAccessible(true);
if ((Boolean) method.invoke(map.get(nodeClass.getSimpleName()), nodeType)) {
return jsonParser.getCodec().treeToValue(treeNode, nodeClass);
}
}
}catch (Exception e){
log.error(e.getMessage(), e);
return null;
}
return null;
}
}
public class TaskNode extends AbstractNodePoint {
@Override
public Boolean isSupport(String nodeType) {
return NodeType.generalNode.name().equals(nodeType);
}
}