5

I recently upgraded to Spring Security 4.2.3.RELEASE. I'm also using spymemcached v 2.8.4. I'm running into this situation where for some reason Spring is trying to serialize service implementation classes. I can't figure out where this is coming from. The line of my code that the exception refers to is

Set<Session> userSessions = (Set<Session>) memcachedClient.get(userId);
...
memcachedClient.set(userId, sessionTimeoutInSeconds.intValue(), userSessions); // dies here

with the mysterious error (the "java.io.NotSerializableException: org.mainco.subco.ecom.service.ContractServiceImpl" is buried within) ...

09:06:47,771 ERROR [io.undertow.request] (default task-58) UT005023: Exception handling request to /myproject/registration/save: java.lang.IllegalArgumentException: Non-serializable object
    at net.spy.memcached.transcoders.BaseSerializingTranscoder.serialize(BaseSerializingTranscoder.java:110)
    at net.spy.memcached.transcoders.SerializingTranscoder.encode(SerializingTranscoder.java:162)
    at net.spy.memcached.MemcachedClient.asyncStore(MemcachedClient.java:282)
    at net.spy.memcached.MemcachedClient.set(MemcachedClient.java:733)
    at net.spy.memcached.MemcachedClient.set(MemcachedClient.java:126)
    at org.mainco.subco.session.service.MemcachedSessionService.associateUser(MemcachedSessionService.java:365)
    at org.mainco.subco.session.service.MemcachedSessionService.setSessionSecurityContext(MemcachedSessionService.java:288)
    at org.mainco.subco.core.security.SubcoSecurityContextRepository.saveContext(subcoSecurityContextRepository.java:116)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:114)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:284)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:174)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:198)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:784)
    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.mainco.subco.ecom.service.ContractServiceImpl
    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.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)

How do I figure out the object memcache is trying to serialize and thus figure out how it is referencing a service class to serialize?

The point of this question is not how do I make my service class serializable but why is my session trying to serialize it in the first place.

Dave
  • 15,639
  • 133
  • 442
  • 830

3 Answers3

4

Why don't you try to enumerate the sessions and the attributes and java-serialize them to a dummy output stream until one fails ? when it fails you print attribute name and value class.

I suppose session is org.apache.catalina.Session. In your code add:

for(Session x : userSessions) checkSerializable(x.getSession());

with checkSerializable:

 private static void checkSerializable(HttpSession s) {
        Enumeration e = s.getAttributeNames();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            Object value = s.getAttribute(name);
            try
            {
                ObjectOutputStream out=new ObjectOutputStream(new ByteArrayOutputStream());
                out.writeObject(value);
            }
            catch(NotSerializableException ex)
            {
                ex.printStackTrace();
                System.out.println(name + " is not serializable, class is: " + value.getClass().getName());
            }
            catch(IOException e2)
            {
                throw new RuntimeException("Unexpected", e2);
            }

        }

    }
Testo Testini
  • 2,200
  • 18
  • 29
  • The Session object I reference isn't actually an HttpSession objecct, but rather one I create . As such I don't have a "getAttributeNames" method per se. Is there any way at run-time to print out the object tree of my session, its fields, and then their fields, and so on? – Dave Jun 26 '17 at 15:46
  • You could try some dump utility https://stackoverflow.com/questions/301536/what-is-the-java-equivalent-of-php-var-dump if that can enumerate values I would also try to serialize them – Testo Testini Jun 27 '17 at 10:12
3

I'm running into this situation where for some reason Spring is trying to serialize service implementation classes.

spring don't try to serialize implementation .

looks lite when you do

memcachedClient.set(userId, sessionTimeoutInSeconds.intValue(), userSessions);

it's expect for Serializable object ,but userSessions is not.

Set is not serializable , and type that you get

(Set) memcachedClient.get(userId);

is not serialized to. check if you can cast memcachedClient.get(userId) to something that is Serializable like HashSets or TreeSet ....

the worst it's you can try BUT you might get CastException

memcachedClient.set(userId, sessionTimeoutInSeconds.intValue(), (Serializable)userSessions);


you can iterate set and do simple check :

int count=0;
for(Session session: userSessions ){
    log....
    boolean isSerializable = checkIfSerializable(session);
    count=isSerializable ? count+1 : count;
    log 
}

private static boolean checkIfSerializable(Object value) throws IllegalAccessException {
    try {
        ByteArrayOutputStream bf = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bf);
        oos.writeObject(value);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bf.toByteArray()));
        Object o = ois.readObject();
        return true;

    } catch (Exception e) {
        System.out.println("----->>>> Not exactly Serializable : " + value);
    }
        return false;
}
xyz
  • 5,228
  • 2
  • 26
  • 35
  • When the Set is created, it is created using "userSessions = new HashSet();" so I'm already doing what you are suggesting and yet the error remains. – Dave Jun 18 '17 at 15:47
  • from your source Set userSessions = (Set) memcachedClient.get(userId); check in debug for userSessions type of Set – xyz Jun 18 '17 at 15:49
  • I have verified it is of type java.util.HashSet. – Dave Jun 18 '17 at 15:51
  • what about Session ? is it Serializable ? something in userSessions is not Serializable , if set is , then session is't – xyz Jun 18 '17 at 15:58
  • My question is how do I figure that out. There is probably something in session that's not, but what's the easiest way to know? – Dave Jun 19 '17 at 21:55
  • Chech that all in session is serialable. You can check all objects manually or in debug mode. Also you can get object session and do cast to serializable inteface . Did you try to cast? – xyz Jun 19 '17 at 21:59
  • It's hard to say what is exactly wrong without debug or vision about types of object in session – xyz Jun 19 '17 at 22:01
  • By checking stuff manually, I assume you mean looking through my code. I already did taht before posting the question and I'm stuck so hopefully this bounty will bring out some programmatic ways that I ahven't throught of. – Dave Jun 20 '17 at 14:22
  • Programatticaly- try wiith reflection – xyz Jun 20 '17 at 14:54
  • private static void checkIfSerializable(Object value) throws IllegalAccessException { try { ByteArrayOutputStream bf = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bf); oos.writeObject(value); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bf.toByteArray())); Object o = ois.readObject(); System.out.println(o.toString()); } catch (Exception e) { System.out.println("Not exactly Serializable"); } } – xyz Jun 23 '17 at 19:35
  • try this test for userSessions . add method and call before memcachedClient.set checkIfSerializable(userSessions); – xyz Jun 23 '17 at 19:36
  • and show out put for this : Class>[] inClasses = userSessions .getClass().getInterfaces(); for(Class c : inClasses){ System.out.println(c); } – xyz Jun 23 '17 at 19:47
3

So what about org.mainco.subco.ecom.service.ContractServiceImpl? Is this a spring bean?

I guess it has scope="session" and so it's bound to your session as one of it's attributes. And if you want to serialize your session - all of it's attributes has to be serializable.

Leffchik
  • 1,950
  • 14
  • 16
  • I'm not understanding how this answer helps me figure out why is my session trying to serialize it in the first place. – Dave Jun 21 '17 at 13:54
  • When your session is being serialized, obviously all of it's attributes has to be serialized too. Apparently your service is one of the session attributes – Leffchik Jun 21 '17 at 14:59
  • I don't wnat it to be. How do I programmatically view the contents of hte session? – Dave Jun 22 '17 at 14:37