我有以下三个应用程序:


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


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


  • 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相似,但带有CosmosDB批注。

    该结构可能看起来有些复杂,但是其思路如下:
  • 一次实现业务逻辑和数据模型(在项目1中)(利用Spring Cloud Function)
  • 仅为每个平台实现一个包装项目(我从项目2中的AWS Lambda开始,但针对Azure的项目3看起来很相似),以及平台特定的内容(例如实体实现,需要特定于数据库的注释)
  • 使用项目1作为依赖项
  • 编译特定于平台的项目(例如,AWS Lambda的项目2)

    我已经尝试过了,安装程序基本上可以正常工作了。
    但是,存在一个大问题:

    当调用上面的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反序列化到哪个实现。

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

    但是,这将破坏我的完整结构:项目1将不包含任何信息,它是与哪个平台特定的项目一起编译的。

    有什么想法,我如何提供自定义解串器(例如Spring bean),而又不对项目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;
    }
    



    资料来源:howto-customize-the-jackson-objectmapper

    09-11 17:24