0
votes

It's a rather strange problem. In Spring I've configured a bean as session.

@Component
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class UserSession implements Serializable{...}

There is an interceptor which who interact with this session.

public class UserInterceptor extends HandlerInterceptorAdapter{
    ...
    @Autowired private UserSession userSession;
    @Autowired private WebUser webUser;

    public boolean preHandle(...){
        userSession.setUserId(webUser.getUserId());
        userSession.setUserList(webUser.getUsers());
        ...
    }
...
}

The WebUser is an interface, in which depend on environment it will inject different WebUser. In profile LOCAL, in will inject LocalWebUser

@Component
@Primary
@Profile({"LOCAL"})
public class LocalWebUser implements WebUser, Serializable{
   @Autowired private transient UserManager userManager;

   @Value("${env.tester.userId}")
   private transient String userId;

   @Override
   public List<String> getUsers() {
       return this.userManager.getUsers();
   }
   ...
}

Notice that I did give make field as transient to prevent common serialization problem. However, in tomcat it throws that LocalWebUser is not serializable.

Caused by: java.io.NotSerializableException: com.company.component.web.LocalWebUser$1 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483) ....

LocalWebUser is actually not stored in session, it's just that session retrieve value from it. Why it complains about it is not serializable?

I did found out a solution that by removing @Value injection from properties, the exception went away, which confuse me even more....

2

2 Answers

1
votes

It's not complaining about LocalWebUser. It's complaining about LocalWebUser$1 which is an anonymous inner class within LocalWebUser. Look through the code in LocalWebUser for something like this:

Object something = new Something() { .... };

That's an anonymous inner class. If that isn't serializable and a reference to that is being leaked into an object stored in the session, then there's your problem.

0
votes

One possibility is that the @Value annotation modifies the type of the userId field to some other, non serializable type, through bytecode manipulation.

So when you call userSession.setUserId(webUser.getUserId()) it copies that non serializable type to the UserSession.

However I could not find any reference about the @Value annotation to support that, so this is just a hunch.

You could probably validate this by inspecting the type of the userId field at runtime with a debugger.