【问题标题】:JAVA DynamoDB: not supported; requires @DynamoDBTyped or @DynamoDBTypeConvertedJAVA DynamoDB:不支持;需要 @DynamoDBTyped 或 @DynamoDBTypeConverted
【发布时间】:2018-05-07 08:43:58
【问题描述】:

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

这是我的添加方法代码:

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;
}

这是我的 editProduct 方法:

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

在模型课上,我认为我做的一切都是正确的:

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:

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

@Override
public String convert(List<ProductKind> objects) {
    //Jackson 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;
}
}

dbcontroller 中的保存方法:

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

}

从 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;
}

单元测试通过,一切正常,但是当我使用 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}

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

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

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

【问题讨论】:

    标签: java amazon-web-services amazon-dynamodb aws-lambda


    【解决方案1】:

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

    Item item = new Item()
    

    使用

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

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

    在你的模型类中这样做:

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

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

    编辑:您的 saveProduct 方法应符合

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

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

    编辑: 您的 saveProduct 方法应该采用 Product 对象,而不是 item 对象。不要使用 putItem 因为它不知道您的模型类。使用 DynamoDBMapper 保存功能。您不需要指定表名,因为这是您的 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;
    }
    

    编辑: 您可以像这样构建一个 AmazonDynamoDB 接口

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

    编辑: DynamoDBMapper 仅支持某些data types

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

    编辑:您的产品集 ProductKind 将需要一个看起来像 this 的转换器。只需将“MyObject”更改为 ProductKinds。

    【讨论】:

    • 我这样做了,但没有任何改变:(
    • 更新了答案。我认为问题在于您没有构建 Product 对象。
    • 好的,谢谢,这就是问题所在 - 我更改了 saveProduct 方法,现在项目已存储,但现在出现另一个错误:“ReturnValues 只能是 ALL_OLD 或 NONE(服务:AmazonDynamoDBv2;状态代码:400;错误代码:ValidationException;
    • 我认为这可能是您的 saveProduct 方法中的问题。你能发帖吗?保存对象时,您可以选择设置返回值
    • 完成但没有帮助,还是一样:“ReturnValues 只能是 ALL_OLD 或 NONE”
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      我也有这个错误,它有点误导,我们需要做的就是在引用类的类文件上使用@DynamoDBDocument。

      对于您的情况,只需将此注释放在 ProductKind 上,如下所示:

      @DynamoDBDocument
      class ProductKind {
          ...
      }
      

      它应该作为产品表中的映射持久化到 dynamoDB 中。

      【讨论】:

        猜你喜欢
        • 2021-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多