vendredi 27 février 2015

Vaadin Spring Addon NotSerializableException for XmlWebApplicationContext even with transient ApplicationContext UI's member

I am integrating Spring into Vaadin and thanks to the Vaadin Spring addon and to this wiki: http://ift.tt/1Dhk2GN I was actually able to do it.


However when I restart Tomcat and the Vaadin application is restarted I get the following NotSerializableException complaining about Spring's XmlWebApplicationContext:



SEVERE: Exception loading sessions from persistent storage
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.springframework.web.context.support.XmlWebApplicationContext
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1355)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1918)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at java.util.LinkedList.readObject(LinkedList.java:1149)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1896)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:501)
at com.vaadin.server.VaadinSession.readObject(VaadinSession.java:1443)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1896)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at org.apache.catalina.session.StandardSession.doReadObject(StandardSession.java:1634)
at org.apache.catalina.session.StandardSession.readObjectData(StandardSession.java:1099)
at org.apache.catalina.session.StandardManager.doLoad(StandardManager.java:261)
at org.apache.catalina.session.StandardManager.load(StandardManager.java:180)
at org.apache.catalina.session.StandardManager.startInternal(StandardManager.java:460)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5213)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.NotSerializableException: org.springframework.web.context.support.XmlWebApplicationContext
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at java.util.LinkedList.writeObject(LinkedList.java:1131)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.apache.catalina.session.StandardSession.doWriteObject(StandardSession.java:1710)
at org.apache.catalina.session.StandardSession.writeObjectData(StandardSession.java:1116)
at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:401)
at org.apache.catalina.session.StandardManager.unload(StandardManager.java:320)
at org.apache.catalina.session.StandardManager.stopInternal(StandardManager.java:487)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5409)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1425)
at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1414)
... 4 more


Actually the code is really simple (based on the tutorial and some other Spring features):


Here is the UI class:



package com.example.vaadinwithspring;

//...

@SpringUI("")
@Theme("valo")
@SuppressWarnings("serial")
public class MyUI extends UI {

private transient ApplicationContext appContext;

@Override
protected void init(VaadinRequest vaadinRequest) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);

UserService service = getUserService(vaadinRequest);
User user = service.getUser();
String userName = user.getName();
Label userHelloLabel = new Label("Hello " + userName + "!");

layout.addComponent(userHelloLabel);

}

@WebListener
public static class MyContextLoaderListener extends ContextLoaderListener {
}

@Configuration
@EnableVaadin
public static class MyConfiguration {

@Bean(name="userService")
public UserService helloWorld() {
return new UserServiceImpl();
}

}

@WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
@VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
public static class MyUIServlet extends SpringAwareVaadinServlet {
}

private UserService getUserService(VaadinRequest request) {
WrappedSession session = request.getWrappedSession();
HttpSession httpSession = ((WrappedHttpSession) session).getHttpSession();
ServletContext servletContext = httpSession.getServletContext();
appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);

return (UserService) appContext.getBean("userService");
}

}


Although quite messy (I followed the wiki), the only important things here are the Vaadin Spring annotations (@SpringUI(""), @EnableVaadin, as for the linked tutorial) and some Spring's annotations (beyond the @Configuration one I also define a Spring bean named "userService" via the @Bean annotation inside the MyConfiguration class). Please also note that I have a member transient field which references Spring's ApplicationContext (which I use inside the UI's getUserService(VaadinRequest) method in order to get the "userService" bean).


Here is the code either for the UserService interface and for the class UserServiceImpl:



package com.example.vaadinwithspring;

public class UserService {

public User getUser();

}

-------------------------------------------------------------------

package com.example.vaadinwithspring;

public class UserServiceImpl implements UserService {

@Override
public User getUser() {
User user = new User();
user.setName("UserName");
return user;
}

}


And then, the User class:



package com.example.vaadinwithspring;

public class User {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}


All components are dummy implementations, just to see that Vaadin cooperates fine with Spring and that everything works.


Finally, the Vaadin Spring tutorial advises to use an applicationContext.xml and put it inside src/main/webapp/WEB-INF/ when not using Spring Boot or JavaConfig.


I have created the following applicationContext.xml:



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://ift.tt/GArMu6"
xmlns:xsi="http://ift.tt/ra1lAU" xmlns:context="http://ift.tt/GArMu7"
xsi:schemaLocation="http://ift.tt/GArMu6
http://ift.tt/1jdM0fG
http://ift.tt/GArMu7
http://ift.tt/1tY3uA9">

<bean class="com.example.vaadinwithspring.MyUI.MyConfiguration" />
<context:component-scan base-package="com.example.vaadinwithspring" />
</beans>


Now, as I said, if I launch the application, everything works great. The only issue I am facing is that NotSerializableException related to XmlWebApplicationContext when I restart the application.


Why the exception is thrown at all if I have a transient ApplicationContext member which shouldn't be serialized? I suppose that Spring uses another instance of XmlWebApplicationContext and uses it internally, is it so? Then:


Is there a way to fix it? How?


Thanks for the attention!


Aucun commentaire:

Enregistrer un commentaire