vaadin-spring-boot-starterを使ってUIを実装するアプリでVaadinのUIとViewに接続した時にSessionをRedisにserializeしようとすると以下の様にSerializationExceptionが出る。

org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:92) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:168) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:129) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
at org.springframework.data.redis.core.DefaultBoundHashOperations.putAll(DefaultBoundHashOperations.java:86) ~[spring-data-redis-1.7.2.RELEASE.jar:na]
at org.springframework.session.data.redis.RedisOperationsSessionRepository$RedisSession.saveDelta(RedisOperationsSessionRepository.java:778) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.data.redis.RedisOperationsSessionRepository$RedisSession.access$000(RedisOperationsSessionRepository.java:670) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.data.redis.RedisOperationsSessionRepository.save(RedisOperationsSessionRepository.java:388) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.data.redis.RedisOperationsSessionRepository.save(RedisOperationsSessionRepository.java:245) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:244) ~[spring-session-1.2.1.RELEASE.jar:na]
(略)

VaadinのTracを見たりStackOverflowでも同じような問題が発生しているよう。vaadin-springの@SpringUIのついたUIクラスと@SpringViewのついたViewにリクエストを送った時にSerializationExceptionが発生するのでSpringUIProviderとSpringViewProviderに問題があると思われる。

環境

問題が発生した環境。

  • Spring boot 1.4.0
  • Vaadin 7.6.3
  • Java 1.8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>

対応

すでに対応している人がいたので助かった。

SpringUIProviderとSpringViewProviderを修正している。変更前はVaadinはWebApplicationContextを参照しているのでVaadinもSpringのApplicatioContextを参照するように変更している。

詳細は以下のPull Requestを参照してください。
https://github.com/vaadin/spring/pull/32/commits/1f88a4ee6bca45ef248e7bc2c1427c7571c8994e

上記、Pull Requestの7ファイルをsrc/main/java以下に設置する。
以下の様なパスで設置すると上書きされてExceptionがでなくなる。

$ tree src/main/java/
src/main/java/
└── com
└── vaadin
└── spring
├── VaadinConfiguration.java
├── navigator
│ └── SpringViewProvider.java
└── server
├── SpringUIProvider.java
├── SpringVaadinApplicationContext.java
├── SpringVaadinServlet.java
├── SpringVaadinServletRequest.java
└── SpringVaadinServletService.java

ファイルを追加した後にSerializationExceptionが出たUIに接続するとExceptionが出ず画面が表示されることが確認できた。

次の様にRedisのSessionを確認してみると中身にVaadinというキーワードが入っているのでVaadinの情報もSessionにserializeできていることがわかる。

$ redis-cli 
127.0.0.1:6379> keys *
1) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:ishii01"
2) "spring:session:sessions:6f47510f-2c6c-4671-bc7b-8a8c0d964081"
3) "spring:session:expirations:1471796640000"
4) "spring:session:sessions:expires:6f47510f-2c6c-4671-bc7b-8a8c0d964081"
127.0.0.1:6379> type "spring:session:sessions:6f47510f-2c6c-4671-bc7b-8a8c0d964081"
hash
127.0.0.1:6379> hgetall "spring:session:sessions:6f47510f-2c6c-4671-bc7b-8a8c0d964081"
1) "lastAccessedTime"
2) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01V\xad\xceR\x01"
3) "sessionAttr:com.vaadin.server.VaadinSession.springVaadinServlet"
(略)
7) "sessionAttr:SPRING_SECURITY_CONTEXT"
9) "maxInactiveInterval"
(略)
11) "sessionAttr:springVaadinServlet.lock"
(略)
127.0.0.1:6379>

おわり。

参考

  1. https://github.com/vaadin/spring/pull/32
  2. http://stackoverflow.com/questions/34400416/enableredishttpsession-fails-with-vaadin
  3. http://stackoverflow.com/questions/29388542/notserializableexception-on-serialization-of-objects-currently-shown-by-vaadin
  4. https://dev.vaadin.com/ticket/19462