spring-data-dynamodbを使ったときのエラー回避のメモ

## Spring Data DynamoDBを使う

Spring Data DynamoDBの使い方は、[GitHubのプロジェクトページ](https://github.com/derjust/spring-data-dynamodb)をご参照ください。

### バージョンではまる

spring-data-dynamodb 4.5.0だと、上記公式ページのチュートリアルどおりに書いてもなぜかエラーが出るので、Compatibilityの表を見て、同じくSpring Framework4.3以降で使える、4.3.1まで下げると、エラーがでなくなりました。

4.3.1だと発生せず、4.4.x以降だと発生するエラーは下記の通りで

``` log:console
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBRepositoryFactoryBean]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBRepositoryFactoryBean.<init>()
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1102)
	... 47 more
Caused by: java.lang.NoSuchMethodException: org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBRepositoryFactoryBean.<init>()
	at java.lang.Class.getConstructor0
	at java.lang.Class.getDeclaredConstructor(Class.java:2178)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
	... 48 more
```
Publicコンストラクタが無いために見えるのですが、チュートリアルどおりだとrepositoryはinterfaceで、

``` XxxRepository.java
@EnableScan
public interface XxxRepository extends CrudRepository<Xxx, String> {
```

実装クラスはSpring framework側でproxyのインスタンスが動的に作成されるはずなので、どう回避したものやら…
＃ご存知の方がいらっしゃいましたら、教えて頂けると助かります


## エラー「No field annotated with interface org.springframework.data.annotation.Id found!」が発生する

しかし、お試しでハッシュキーだけ使って書くと動作したのに、ハッシュキーとレンジキーの両方をアノテーションで指定すると、途端にこのようなエラーが発生します。

これにはまった方は、こちらの[issue報告](https://github.com/derjust/spring-data-dynamodb/issues/24)および回避策のソース[[1]](https://github.com/michaellavelle/spring-data-dynamodb-demo/blob/master/src/main/java/org/socialsignin/springframework/data/dynamodb/demo/domain/Reply.java)[[2]](https://github.com/michaellavelle/spring-data-dynamodb-demo/blob/master/src/main/java/org/socialsignin/springframework/data/dynamodb/demo/domain/ReplyId.java)をご参照ください。
[追記]最終的なガイドのページは[こちら](https://github.com/derjust/spring-data-dynamodb/wiki/Use-Hash-Range-keys)のようです。

僕もこれで、動作するようになりました。

ポイントは『ハッシュキーとレンジキーを格納するIDクラスを作成する』ということです。

細かい規則は下記です。

- IDクラスは、Serializableを実装する
- IDクラスには、ハッシュキーとレンジキーのフィールドと、getter/setterを作成する
- IDクラスのハッシュキーのgetterに@DynamoDBHashKeyを、レンジキーのgetterに@DynamoDBRangeKeyを付与する
- 元のEntityクラスは、IDクラスにSpringの@IDアノテーションを付与する
- Entityクラスに、ハッシュキーとレンジキーのgetter/setterを作成し、IDクラスのgetter/setterを呼出す
- このとき、Entityクラスのフィールドにハッシュキーとレンジキーそのものがあるかどうかは特に気にしない
- Entityクラスのハッシュキーのgetterに@DynamoDBHashKeyを、レンジキーのgetterに@DynamoDBRangeKeyを付与する。これはIDクラスのアノテーションと重複する（けど、気にしない）

直接記載はされていませんが、忘れやすいこととして
- RepositoryクラスのGenerics内のIDのクラスは、上記で作製したIDクラスを指定する

＃サンプルソースだと、ハッシュキーがThreadIdクラスという少し特殊なクラスなので、Marshallerが定義されていますが、Stringなどがハッシュキーの場合は、@DynamoDBMarshallingの指定は無くて大丈夫です。

こちらの[isuue報告](https://github.com/michaellavelle/spring-data-dynamodb/issues/74)でのコメントによると、
Spring-DataとAWS-SDKでのアノテーションがそれぞれあり、Spring-Data-Dynamodbはそれら2つの統合作業なので、どうしてもこのような（アノテーション関連の）エラーが出てしまう、それは驚きではないんだけれども、ということでした。

振り返ると、いろんなページのチュートリアル[[1]](http://www.baeldung.com/spring-data-dynamodb)[[2]](https://tech.smartling.com/getting-started-with-amazon-dynamodb-and-java-universal-language-850fa1c8a902#.4bj1egb4b)[[3]](https://tech.zalando.com/blog/integrating-amazon-dynamodb-into-your-development-process/)[[4]](http://dev.classmethod.jp/server-side/java/spring-data-dynamodb/)で、Hashキーだけのサンプルが多いんですが、そういうことなんでしょうかね…

### 今後

DynamoDBMapperでもアノテーションは実現できているし、spring-data-dynamodbを使って悩まし過ぎるときは、DynamoDBMapperを直接使う（つまり、AWS SDKだけ使う）ようにしてもいいかなと考えています。

以上です。