如何使用Jackson和Spring Boot提供自定义反序列化程序



我有以下三个应用程序:

项目1持有

  • 业务逻辑(Spring Cloud Function(
  • 接口IDemoEntity

项目2

  • AWS特定处理程序
  • IDemoEntity的一个实现,带有DynamoDB特定的注释
  • 该项目基于Spring Boot

项目3

  • IDemoEntity的一个实现,带有CosmosDB注释
  • Azure特定处理程序

项目1的类如下所示:

public interface IDemoEntity {
String getName();
void setName(String name);
}
@Component
public class StoreFunction implements Consumer<Message<IDemoEntity>> {
@Override
public void accept(Message<IDemoEntity> t) {
System.out.println("Stored entity " + t.getPayload().getName());
return;
}
}

对于项目2,IDemoEntity的实现如下所示:

@DynamoDBTable(tableName = "DemoEntity")
public class DynamoDemoEntity implements IDemoEntity {
private String name;
@Override
@DynamoDBHashKey
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}    
}

对于项目3,IDemoEntity的实现看起来类似于

DynamoDemoEntity结构可能看起来有点复杂,但想法如下:

  1. 一次性实现业务逻辑和数据模型(在项目1中((利用Spring Cloud Function(
  2. 只为每个平台实现一个包装器项目(我在项目2中从AWS Lambda开始,但Azure的项目3看起来很相似(,以及特定于平台的东西(比如实体实现,它需要特定于DB的注释(
  3. 编译特定于平台的项目(例如AWS Lambda的项目2(,将项目1作为依赖项

我试过了,设置基本上可以工作。然而,有一个大问题:

当调用上面的StoreFunction时,Jackson抛出以下异常:

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `de.margul.awstutorials.springcloudfunction.logic.IDemoEntity` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (String)"{"name": "Detlef"}"; line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1452)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1028)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:265)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
at de.margul.awstutorials.springcloudfunction.aws.handler.RestSpringBootApiGatewayRequestHandler.deserializeBody(RestSpringBootApiGatewayRequestHandler.java:57)
... 3 more

这是有道理的,因为Jackson不知道如果IDemoEntity,它应该将接收到的JSON反序列化到哪个实现。

现在最简单的方法是在IDemoEntity上放置一个@JsonDeserialize(as = DynamoDemoEntity.class)

然而,这将打破我的完整结构:项目1将没有信息,它是用哪个平台特定的项目编译的。

有什么想法吗?我如何提供一个自定义的反序列化程序(例如Springbean(,但不需要在项目1中进行特定于平台的修改?

首先,您需要创建自定义DynamoDemoEntityDeserializer,如下所示:

class DynamoDemoEntityDeserializer extends JsonDeserializer<DynamoDemoEntity> {
@Override
public DynamoDemoEntity deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
// return DynamoDemoEntity instance;
}
}

然后您可以创建com.fasterxml.jackson.databind.Module的bean,如下所示:

@Bean
public Module dynamoDemoEntityDeserializer() {
SimpleModule module = new SimpleModule();
module.addDeserializer(IDemoEntity.class, new DynamoDemoEntityDeserializer());
return module;
}

com.fasterxml.jackson.databind.Module类型的任何bean都会自动向自动配置的Jackson2ObjectMapperBuilder注册,并应用于它创建的任何ObjectMapper实例。这提供了一种全局机制,用于在向应用程序添加新功能时提供自定义模块。

来源:如何自定义jackson对象映射程序

如果您想将给定对象反序列化为任何实体,则需要为此编写自己的自定义方法。

这里有一个我使用过的例子,它适用于任何实体。请看一看,然后试试。

@Service
public class ObjectSerializer {
private static final Logger logger = LoggerFactory.getLogger(ObjectSerializer.class);
private static ObjectMapper objectMapper;
@Autowired
private ObjectSerializer(ObjectMapper objectMapper) {
ObjectSerializer.objectMapper = objectMapper;
}
public static <T> T getObject(Object obj, Class<T> class1) {
String jsonObj = "";
T objectDto = null;
try {
jsonObj = objectMapper.writeValueAsString(obj);
objectDto =  objectMapper.readValue(jsonObj, class1);
}catch (IOException e) {
logger.error("Exception Occured in ObjectSerializer :    |   {}",e.getMessage());
}
return objectDto;
}

我希望这能有所帮助。

最新更新