私は問題を抱えていて、それを処理することができません。たとえばKitchenServiceでCRUDメソッドを作成しました。 addProductなどのメソッドがあり、これらは正常に機能します。しかし、Productクラスフィールドを使用しているRecipeクラスがあります。この場合、大きな問題が発生します。
私の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
レシピクラスは次のようになります。
@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;
}
}
誰かがこの問題で私を助けることができますか?
短い答え:
パブリックの空のコンストラクターをMediaクラスに追加します。
長い答え:
コードでは、databaseController.get(Product.class, id)
を実行しているときに、 DynamoDBMapperTableModel のアンダースコアメソッドpublic T unconvert(final Map<String,AttributeValue> 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.<T>newInstance(targetType)
targetType
で.newInstance()
を呼び出し、そのタイプは_Class<T>
_です。
Class.newInstance()ドキュメント に記述されているように、クラスにnullaryコンストラクターがない場合、InstantiationException
がスローされます。この例外がスローされるシナリオは他にもありますが、私の経験では、おそらくpublicemptyコンストラクターが実装されていないことが原因です。
私にとっては、セッター方式のタイプミスでした。
@DynamoDBAttribute(attributeName = "closed_date_time")
public Date getClosedDateTime() {
return closedDateTime;
}
public void setClosedDate(Date closedDateTime) {
this.closedDateTime = closedDateTime;
}
setClosedDate
をsetClosedDateTime
に置き換えたところ、機能しました。