AWS DynamoDB:无法取消转换属性错误

Posted

技术标签:

【中文标题】AWS DynamoDB:无法取消转换属性错误【英文标题】:AWS DynamoDB: Could not unconvert attribute error 【发布时间】:2018-06-04 05:43:21 【问题描述】:

我有问题,我无法处理。例如,我在 KitchenService 中创建了 CRUD 方法。我有 addProduct 等方法,这些方法很好。但是我有 Recipe 类,我正在使用 Product 类字段。在这种情况下,我遇到了很大的问题。

我的 addRecipe 方法:

public Recipe addRecipe (Recipe recipe)

    List<RecipeElement> recipeElements = recipe.getRecipeElements();
    for (RecipeElement recipeElement : recipeElements) 
        String id = recipeElement.getProduct().getId();
        Product product = databaseController.get(Product.class, id);
        recipeElement.setProduct(product);
    

    databaseController.saveRecipe(recipe);
    logger.log("Recipe created");

    return recipe;

构建成功,所以我想在 POSTMAN 中对其进行测试,这就是我发送的 JSON 女巫的外观:

"id":null,"name":"test3","labels":["GLUTEN_FREE"],"author":"name":"Plejer Annołn","id":"testID2","media":"name":"heheszki","url":"http://blabla.pl","mediaType":"IMAGE","recipeElements":["product":"id":"ecacaf36-29a2-41c6-942e-be5a715ed094","weight":"100"],"approved":false

然后我收到“消息”:“内部服务器错误”,所以我正在检查日志,这就是我在那里发现的:

Product[Media]; could not unconvert attribute: com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException

Caused by: com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: could not invoke public void pl.javamill.model.kitchen.Product.setMedia(pl.javamill.model.common.Media) on class pl.kitchen.Product with value name=heheszki, url=http://blabla.pl, mediaType=IMAGE of type class java.util.LinkedHashMap

Recipe Class 是这样的:

@DynamoDBTable(tableName = "recipe")
public class Recipe extends Request 
/**
 * Id of kitchen content
 */
private String id;
/**
 * Name of recipe
 */
private String name;

/**
 * Labels of product for example gluten fee product
 */
private List<KitchenLabel> labels;

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

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

private Boolean approved;

private List<RecipeElement> recipeElements;

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


@DynamoDBTypeConverted(converter = EnumConverter.class)
@DynamoDBAttribute(attributeName = "Labels")
public List<KitchenLabel> getLabels() 
    return labels;


public void setLabels(List<KitchenLabel> labels) 
    this.labels = labels;


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


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


@DynamoDBTypeConverted(converter = ObjectConverter.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;


@DynamoDBTypeConverted(converter = ObjectConverter.class)
@DynamoDBAttribute(attributeName = "RecipeElements")
public List<RecipeElement> getRecipeElements() 
    return recipeElements;


public void setRecipeElements(List<RecipeElement> recipeElements) 
    this.recipeElements = recipeElements;

RecipeElement 类:

public class RecipeElement 


private Product product;
private Integer weight;

@DynamoDBTypeConverted(converter = ObjectConverter.class)
@DynamoDBHashKey(attributeName = "product")
public Product getProduct() 
    return product;


public void setProduct(Product product) 
        this.product = product;
    

    public Integer getWeight() 
        return weight;
    

    public void setWeight(Integer weight) 
        this.weight = weight;
    

和产品类:

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

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

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

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

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

    @DynamoDBTypeConverted(converter = ObjectConverter.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 class ObjectConverter<T extends Object> 
implements DynamoDBTypeConverter<String, T> 

    ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String convert(T object) 
        try 
            return objectMapper.writeValueAsString(object);
         catch (JsonProcessingException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
        
        throw new IllegalArgumentException("Unable to parse JSON");
    

    @Override
    public T unconvert(String object) 
        try 
            T unconvertedObject = objectMapper.readValue(object, 
                new TypeReference<T>() 
            );
            return unconvertedObject;
         catch (IOException e) 
            e.printStackTrace();
        
        return null;
    

有人可以帮我解决这个问题吗?

【问题讨论】:

这个问题你解决了吗?我现在遇到了。谢谢! 【参考方案1】:

简答

Media 类添加一个公共的空构造函数。

长答案

在您的代码中,当您执行databaseController.get(Product.class, id) 时,您正在调用DynamoDBMapperTableModel 的下划线方法public T unconvert(final Map&lt;String,AttributeValue&gt; object)

@Override
public T unconvert(final Map<String,AttributeValue> object) 
    final T result = StandardBeanProperties.DeclaringReflect.<T>newInstance(targetType);
    if (!object.isEmpty()) 
        for (final DynamoDBMapperFieldModel<T,Object> field : fields()) 
            try 
                final AttributeValue value = object.get(field.name());
                if (value != null) 
                    field.unconvertAndSet(result, value);
                
             catch (final RuntimeException e) 
                throw new DynamoDBMappingException(
                    targetType.getSimpleName() + "[" + field.name() + "]; could not unconvert attribute", e
                );
            
        
    
    return result;

在此方法的第一行中,正在使用反射创建表模型的新实例(在您的情况下是 Product 的新实例),然后将新实例的字段转换为所需的类和相应地设置。

StandardBeanProperties.DeclaringReflect.&lt;T&gt;newInstance(targetType)targetType 上调用.newInstance(),它的类型是Class&lt;T&gt;

如Class.newInstance() documentation 中所写,如果类没有空构造函数,则抛出InstantiationException。还有其他情况会引发此异常,但根据我的经验,这可能是因为未实现公共的空构造函数。

【讨论】:

【参考方案2】:

对我来说,这是 setter 方法中的拼写错误。

@DynamoDBAttribute(attributeName = "closed_date_time")
public Date getClosedDateTime() 
    return closedDateTime;


public void setClosedDate(Date closedDateTime) 
    this.closedDateTime = closedDateTime;

我已将 setClosedDate 替换为 setClosedDateTime,然后它起作用了。

【讨论】:

【参考方案3】:

再次生成 Setter Getter 就可以了! 在我的情况下也是一个错字。

但是如果列的 DataType 是 Long 并且您将 dataType 转换为 String。这也可能导致现有数据出现此问题。

【讨论】:

这并没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review 这并不能真正回答问题。如果您有其他问题,可以点击 提问。一旦你有足够的reputation,你也可以add a bounty 来引起对这个问题的更多关注。 - From Review

以上是关于AWS DynamoDB:无法取消转换属性错误的主要内容,如果未能解决你的问题,请参考以下文章

类 java.lang.String 在 DynamoDB 创建表时无法转换为 Long

AWS Cloudformation遇到不受支持的属性类型

DynamoDB 无法转换为 System.DateTime

AWS:从 dynamodb 到 redshift 的数据转换 [关闭]

从 Parse 迁移到 AWS Dynamo DB

AWS DynamoDB批量获取请求 - iOS