I have the following three applications:
Project 1 holds
- Business logic (Spring Cloud Function)
 - An interface IDemoEntity
 
Project 2
- AWS-specific handler
 - One implementation of IDemoEntity, with DynamoDB-specific annotations
 - The project is based on Spring Boot
 
Project 3
- One implementation of IDemoEntity, with CosmosDB annotation
 - Azure-specific handler
 
The classes of project 1 look like this:
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;
    }
}
For project 2, the implementation of IDemoEntity looks like this:
@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;
    }    
}
For project 3, the implementation of IDemoEntity would look similar to DynamoDemoEntity, but with CosmosDB annotations.
The structure might look a bit complicated, but the idea is the following:
- Implement business logic and data model one time (in project 1) (leveraging Spring Cloud Function)
 - Implement just a wrapper project for each platform (I'm starting with AWS Lambda in project 2, but project 3 for Azure would look similar), as well as platform-specific things (like entity implementation, which needs DB-specific annotations)
 - Compile the platform-specific project (e. g. project 2 for AWS Lambda) with project 1 as dependency
 
I've tried it, and the setup works basically. However, there is one big problem:
When calling the StoreFunction above, Jackson throws the following exception:
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
That makes sense, because Jackson does not know, to which implementation if IDemoEntity it shall deserialize the received JSON.
The easiest way now would be to place a @JsonDeserialize(as = DynamoDemoEntity.class) on IDemoEntity.
However, that would break my complete structure: Project 1 shall have no information, which platform-specific project it is compiled with.
Any ideas, how I could provide a custom deserializer (e. g. as Spring bean), but without making platform-specific modifications in project 1?