JAVA DynamoDB:不支持;需要 @DynamoDBTyped 或 @DynamoDBTypeConverted

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47454555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 09:37:56  来源:igfitidea点击:

JAVA DynamoDB: not supported; requires @DynamoDBTyped or @DynamoDBTypeConverted

javaamazon-web-servicesamazon-dynamodbaws-lambda

提问by D.Zet

I've created CRUD methods but i have some problems with that.

我已经创建了 CRUD 方法,但我对此有一些问题。

This is my add method code:

这是我的添加方法代码:

public Product addProduct(Product content) {
    Product item = new Product();

    item.setName(content.getName());
    item.setCalories(content.getCalories());
    item.setFat(content.getFat());
    item.setCarbo(content.getCarbo());
    item.setProtein(content.getProtein());
    item.setProductKinds(content.getProductKinds());
    item.setAuthor(content.getAuthor());
    item.setMedia(content.getMedia());
    item.setApproved(content.getApproved());


    databaseController.saveTest(item);
    logger.log("Item created");


    return item;
}

This is my editProduct method:

这是我的 editProduct 方法:

public Product editProduct(Product product) {
    Product databaseProduct = databaseController.get(Product.class, product.getId());
    databaseProduct.setAllProducts(product);
    databaseController.save(databaseProduct);
    return databaseProduct;
}

In model class I think that I have made everything right :

在模型课上,我认为我已经把一切都做好了:

package pl.javamill.model.kitchen;

import com.amazonaws.services.dynamodbv2.datamodeling.*;
import pl.javamill.model.Request;
import pl.javamill.model.common.Author;
import pl.javamill.model.common.AuthorConverter;
import pl.javamill.model.common.Media;
import pl.javamill.model.common.MediaConverter;

import java.util.List;

@DynamoDBTable(tableName = "product")
public class Product extends Request {

/**
 * Id of kitchen content
 */
private String id;
/**
 * Name of product
 */
private String name;

/**
 * Calories in 100g
 */
private Integer calories;

/**
 * Fat in 100g
 */
private Double fat;

/**
 * Total carbo in 100g
 */
private Double carbo;

/**
 * Total Protein in 100g
 */
private Double protein;

/**
 * Labels of product for example gluten fee product
 */
private List<ProductKind> productKinds;

/**
 * Author of content.
 */
private Author author;

/**
 * Address of content image.
 */
private Media media;

private Boolean approved;

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

public void setId(String id) {
    this.id = id;
}

@DynamoDBAttribute(attributeName = "Name")
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@DynamoDBAttribute(attributeName = "Calories")
public Integer getCalories() {
    return calories;
}

public void setCalories(Integer calories) {
    this.calories = calories;
}

@DynamoDBAttribute(attributeName = "Fat")
public Double getFat() {
    return fat;
}

public void setFat(Double fat) {
    this.fat = fat;
}

@DynamoDBAttribute(attributeName = "Carbo")
public Double getCarbo() {
    return carbo;
}

public void setCarbo(Double carbo) {
    this.carbo = carbo;
}

@DynamoDBAttribute(attributeName = "Protein")
public Double getProtein() {
    return protein;
}

public void setProtein(Double protein) {
    this.protein = protein;
}

@DynamoDBTypeConvertedEnum
@DynamoDBTypeConverted(converter = ProductKindConverter.class)
@DynamoDBAttribute(attributeName = "ProductKinds")
public List<ProductKind> getProductKinds() {
    return productKinds;
}

public void setProductKinds(List<ProductKind> productKinds) {
    this.productKinds = productKinds;
}

@DynamoDBTypeConverted(converter = AuthorConverter.class)
@DynamoDBAttribute(attributeName = "Author")
public Author getAuthor() {
    return author;
}

public void setAuthor(Author author) {
    this.author = author;
}

@DynamoDBTypeConverted(converter = MediaConverter.class)
@DynamoDBAttribute(attributeName = "Media")
public Media getMedia() {
    return media;
}

public void setMedia(Media media) {
    this.media = media;
}

@DynamoDBAttribute(attributeName = "Approved")
public Boolean getApproved() {
    return approved;
}

public void setApproved(Boolean approved) {
    this.approved = approved;
}



public void setAllProducts(Product product) {
    if (!getName().equals(product.getName())) {
        setName(product.getName());
    }
    if (!getCalories().equals(product.getCalories())) {
        setCalories(product.getCalories());
    }
    if (!getFat().equals(product.getFat())) {
        setFat(product.getFat());
    }
    if (!getCarbo().equals(product.getCarbo())) {
        setCarbo(product.getCarbo());
    }
    if (!getProtein().equals(product.getProtein())) {
        setProtein(product.getProtein());
    }
    if (!getProductKinds().equals(product.getProductKinds())) {
        setProductKinds(product.getProductKinds());
    }
    if (!getAuthor().equals(product.getAuthor())) {
        setAuthor(product.getAuthor());
    }
    if (!getMedia().equals(product.getMedia())) {
        setMedia(product.getMedia());
    }
    if (!getApproved().equals(product.getApproved())) {
        setApproved(product.getApproved());
    }

}


@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Product product = (Product) o;

    if (name != null ? !name.equals(product.name) : product.name != null) return false;
    if (calories != null ? !calories.equals(product.calories) : product.calories != null) return false;
    if (fat != null ? !fat.equals(product.fat) : product.fat != null) return false;
    if (carbo != null ? !carbo.equals(product.carbo) : product.carbo != null) return false;
    if (protein != null ? !protein.equals(product.protein) : product.protein != null) return false;
    if (productKinds != null ? !productKinds.equals(product.productKinds) : product.productKinds != null)
        return false;
    if (author != null ? !author.equals(product.author) : product.author != null) return false;
    if (media != null ? !media.equals(product.media) : product.media != null) return false;
    return approved != null ? approved.equals(product.approved) : product.approved == null;
}

@Override
public int hashCode() {
    int result = id != null ? id.hashCode() : 0;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    result = 31 * result + (calories != null ? calories.hashCode() : 0);
    result = 31 * result + (fat != null ? fat.hashCode() : 0);
    result = 31 * result + (carbo != null ? carbo.hashCode() : 0);
    result = 31 * result + (protein != null ? protein.hashCode() : 0);
    result = 31 * result + (productKinds != null ? productKinds.hashCode() : 0);
    result = 31 * result + (author != null ? author.hashCode() : 0);
    result = 31 * result + (media != null ? media.hashCode() : 0);
    result = 31 * result + (approved != null ? approved.hashCode() : 0);
    return result;
}

}

}

ProductKindConventor:

ProductKindConventor:

public class ProductKindConverter implements DynamoDBTypeConverter<String, List<ProductKind>> {

@Override
public String convert(List<ProductKind> objects) {
    //Hymanson object mapper
    ObjectMapper objectMapper = new ObjectMapper();
    try {
        String objectsString = objectMapper.writeValueAsString(objects);
        return objectsString;
    } catch (JsonProcessingException e) {
        //do something
    }
    return null;
}

@Override
public List<ProductKind> unconvert(String objectsString) {
    ObjectMapper objectMapper = new ObjectMapper();
    try {
        List<ProductKind> objects = objectMapper.readValue(objectsString, new TypeReference<List<ProductKind>>(){});
        return objects;
    } catch (JsonParseException e) {
        //do something
    } catch (JsonMappingException e) {
        //do something
    } catch (IOException e) {
        //do something
    }
    return null;
}

}

}

Save method in dbcontroller:

dbcontroller 中的保存方法:

public void saveTest(Product product){
    AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
            .withRegion(regions).build();
    mapper = new DynamoDBMapper(client);
    mapper.save(product);

}

Get product from DB method:

从 DB 方法获取产品:

public Product getTest(String id) {
    AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
            .withRegion(regions).build();
    mapper = new DynamoDBMapper(client);
    Product retrivedProduct = mapper.load(Product.class, id);
    return retrivedProduct;
}

Unit test passed, everything seems to be ok, but when I was using POSTMAN to test, i got some errors. I send product as json and it seems like that:

单元测试通过了,看起来一切正常,但是当我使用 POSTMAN 进行测试时,出现了一些错误。我将产品作为 json 发送,看起来是这样的:

{"id":null,"name":"yoloornotyolo","calories":1000,"fat":400.0,"carbo":20.0,"protein":40.0,"productKinds":["MEAT"],"author":{"name":"Plejer Anno?n","id":"testID2"},"media":{"name":"heheszki","url":"http://blabla.pl","mediaType":"IMAGE"},"approved":false}

{"id":null,"name":"yoloornotyolo","calories":1000,"fat":400.0,"carbo":20.0,"protein":40.0,"productKinds":["MEAT"]," author":{"name":"Plejer Anno?n","id":"testID2"},"media":{"name":"heheszki","url":" http://blabla.pl" ,"mediaType":"IMAGE"},"approved":false}

Then I got ""message": "Internal server error"", so I check log file and that what I can see:

然后我收到了“消息”:“内部服务器错误”,所以我检查了日志文件以及我可以看到的内容:

not supported; requires @DynamoDBTyped or @DynamoDBTypeConverted: com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException

不支持; 需要@DynamoDBTyped 或@DynamoDBTypeConverted:com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException

I dont know what is wrong. Can someone explain me what I suppose to do?

我不知道出了什么问题。有人可以解释一下我想做什么吗?

回答by F_SO_K

It would be useful to see your saveProduct method. You are using DynamoDBMapper annotations but it looks like you are trying to save an item object, not a Product object. Rather than

查看您的 saveProduct 方法会很有用。您正在使用 DynamoDBMapper 注释,但看起来您正在尝试保存项目对象,而不是产品对象。而不是

Item item = new Item()

Use

利用

Product item = new Product();
item.setName...

One thing I would mention is that you can offload the handling of your generated id to DyanmoDBMapper using the DynamoDBAutoGeneratedKey annotation

我要提到的一件事是,您可以使用DynamoDBAutoGeneratedKey 注释将生成的 id 的处理卸载到 DyanmoDBMapper

In your model class do this:

在您的模型类中执行以下操作:

@DynamoDBHashKey(attributeName = "Id")
@DynamoDBAutoGeneratedKey
public String getId() { return id; }
public void setId(String id) { this.id = id; } 

And then you dont need to handle id in your addProduct method

然后你不需要在你的 addProduct 方法中处理 id

EDIT: Your saveProduct method should be along the lines of

编辑:您的 saveProduct 方法应该是

DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient);
mapper.save(item)

I doubt you need to be passing a tablename as that is an annotation on your Product object. You shouldn't be using putItem.

我怀疑您是否需要传递表名,因为它是 Product 对象上的注释。您不应该使用 putItem。

EDIT: Your saveProduct method should take a Product object, not an item object. Dont use putItem because this doesn't know about your model class. Use DynamoDBMapper save function. You dont need to specify the table name as that's an annotation on your Product class (the table is called 'product'). You should use AmazonDynamoDB for interfacing to DynamoDB. The method below return is void, so you will need to update the addProduct method.

编辑:您的 saveProduct 方法应该采用 Product 对象,而不是 item 对象。不要使用 putItem 因为它不知道您的模型类。使用 DynamoDBMapper 保存功能。您不需要指定表名,因为它是 Product 类上的注释(该表称为“product”)。您应该使用 AmazonDynamoDB 连接到 DynamoDB。return 下面的方法是无效的,因此您需要更新 addProduct 方法。

public void saveProduct(Product item) {

logger.log("Starting to save an item");

//You need a new method to return an AmazonDynamoDB interface 
AmazonDynamoDB dynamoDB = getAmazonDynamoDB();
DynamoDBMapper mapper = new DynamoDBMapper(dynamoDB);
mapper.save(item)

logger.log("Item stored");

return saved;
}

EDIT: You build an AmazonDynamoDB interface like this

编辑:您像这样构建 AmazonDynamoDB 接口

   // Set to your chosen region
   AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
   .withRegion(Regions.US_WEST_2)
   .build(); 

EDIT: DynamoDBMapper only supports certain data types.

编辑:DynamoDBMapper 仅支持某些数据类型

You have three complex data types there; productKind, author and media. If you want to store these in your database, you will need to write a Convertor Classfor each one. The convertor class typically define how you convert your object to a string and back again.

那里有三种复杂的数据类型;productKind、作者和媒体。如果要将这些存储在数据库中,则需要为每个编写一个转换器类。转换器类通常定义您如何将对象转换为字符串并再次返回。

EDIT: Your set, ProductKind, will need a convertor that looks like this. Just change 'MyObject' to ProductKinds.

编辑:您的设置,ProductKind,需要一个转换器,看起来像这样。只需将“MyObject”更改为 ProductKinds。

回答by Volodymyr Zubariev

It would be useful to have a stack trace for the exception. In the intermediate message it contains the data type and field information which can not be converted.

对异常进行堆栈跟踪会很有用。在中间消息中,它包含无法转换的数据类型和字段信息。

Usually you do not need to make any convertors, just be sure to have @DynamoDBDocument on all custom classes, and @DynamoDBTypeConvertedEnum on all custom enums used.

通常您不需要制作任何转换器,只需确保在所有自定义类上使用@DynamoDBDocument,并在所有使用的自定义枚举上使用@DynamoDBTypeConvertedEnum。