sunmingtao / sample-code

3 stars 4 forks source link

Spring boot dynanodb error: DynamoDBMappingException requires @DynamoDBTyped or @DynamoDBTypeConverted #256

Closed sunmingtao closed 3 years ago

sunmingtao commented 3 years ago

Save an entity and get error

com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: not supported; requires @DynamoDBTyped or @DynamoDBTypeConverted
    at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$Rules$NotSupported.set(StandardModelFactories.java:664) ~[aws-java-sdk-dynamodb-1.11.443.jar:na]
    at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$Rules$NotSupported.set(StandardModelFactories.java:650) ~[aws-java-sdk-dynamodb-1.11.443.jar:na]
    at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$AbstractRule.convert(StandardModelFactories.java:709) ~[aws-java-sdk-dynamodb-1.11.443.jar:na]
    at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$AbstractRule.convert(StandardModelFactories.java:691) ~[aws-java-sdk-dynamodb-1.11.443.jar:na]
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel.convert(DynamoDBMapperFieldModel.java:138) ~[aws-java-sdk-dynamodb-1.11.443.jar:na]

Entity class:

@Setter
@DynamoDBTable(tableName = "soccer-bet")
@NoArgsConstructor
public class Match {

    private String id;
    private String matchDate;
    private Team homeTeam;
    private Team awayTeam;
    private int homeScore;
    private int awayScore;
    private double winProb;
    private double drawProb;

    public Match(String matchDate, Team homeTeam, Team awayTeam, int homeScore,
                 int awayScore, double winProb, double drawProb) {
        this.matchDate = matchDate;
        this.homeTeam = homeTeam;
        this.awayTeam = awayTeam;
        this.homeScore = homeScore;
        this.awayScore = awayScore;
        this.winProb = winProb;
        this.drawProb = drawProb;
    }

    @DynamoDBHashKey
    @DynamoDBAutoGeneratedKey
    public String getId() {
        return id;
    }

    @DynamoDBAttribute
    public String getMatchDate() {
        return matchDate;
    }

    public Team getHomeTeam() {
        return homeTeam;
    }

    public Team getAwayTeam() {
        return awayTeam;
    }

    @DynamoDBAttribute
    public int getHomeScore() {
        return homeScore;
    }

    @DynamoDBAttribute
    public int getAwayScore() {
        return awayScore;
    }

    @DynamoDBAttribute
    public double getWinProb() {
        return winProb;
    }

    @DynamoDBAttribute
    public double getDrawProb() {
        return drawProb;
    }

    public void addToTeamMatchStats() {
        homeTeam.addMatchStats(toMatchStats(true));
        awayTeam.addMatchStats(toMatchStats(false));
    }

    private MatchStats toMatchStats(boolean home) {
        String opponent = home ? awayTeam.getName() : homeTeam.getName();
        double winProb = home ? this.winProb : 1 - this.winProb - drawProb;
        return new MatchStats(opponent, home, getActualPoints(home), winProb, drawProb);
    }

    private int getActualPoints(boolean home) {
        int score1 = home ? homeScore : awayScore;
        int score2 = home ? awayScore : homeScore;
        if (score1 > score2) {
            return 2;
        }
        return score1 < score2 ? 0 : 1;
    }
}
sunmingtao commented 3 years ago

If a getter method is not annotated with anything, Dynamodb still tries to map it. They need to specifically ignored by @DynamoDBIgnore

@DynamoDBIgnore
public Team getHomeTeam() {
    return homeTeam;
}

@DynamoDBIgnore
public Team getAwayTeam() {
    return awayTeam;
}

That also means the @DynamoDBAttribute is redundant. But it's good to have them explicitly.