Announcement Announcement Module
Collapse
No announcement yet.
Compatibility with Google App Engine/Serialization Issues Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Compatibility with Google App Engine/Serialization Issues

    I've deployed Spring Social into GAE and get the following exception when trying to signin as a user:

    Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: org.springframework.social.connect.ConnectionFacto ryLocator
    at com.google.apphosting.runtime.jetty.SessionManager .deserialize(SessionManager.java:386)
    at com.google.apphosting.runtime.jetty.MemcacheSessio nStore.getSession(MemcacheSessionStore.java:31)

    I believe this is the same problem Craig mentions in his comments to this post:

    http://blog.springsource.com/2011/09...-a-year-makes/

    where he references:

    http://code.google.com/p/googleappen...detail?id=5299

    However in the case I am seeing the ConnectionFactoryLocator itself is not Serializable nor is the ConnectionFactoryRegistry implementation class. Wouldn't this explain the exception rather than the use of dynamic proxies?

    Now that I've hit this issue, I'm curious about a couple of things in terms of finding a work around. The most obvious solution would be to make the classes Serializable, but I am not sure how many objects in their reference chains are Serializable or make sense to serialize. Otherwise, my understanding is that the ConnectionFactoryLocator is intended to be used with singleton scope. If this is the case, I'm wondering how this winds up in an HttpSession? Presumably this is being referenced by other session objects which may not really need to persist that reference. If ConnectionFactoryLocator stayed managed by only the Spring container perhaps the Serialization issue could be avoided? However, if the Spring container also uses Serialization as part of its caching strategy then the same problem remains.

    And also more of a general Spring question -- as a singleton what is the advantage of creating the bean to use a dynamic proxy versus proxy mode none? If there really is a problem in GAE with dynamic proxies could the "no proxy" approach avoid the problem without any bad side effects?

    Thank you,
    David

  • #2
    Does anyone have input on this question? Should I file an issue for ConnectionFactoryLocator not being Serializable?

    Thank you,
    David

    Comment


    • #3
      I see that you files an issue to make ConnectionFactoryLocator serializable. I'll certainly take a look at that. However, back when I did my GAE experiment with Spring Social, I recall having made ConnectionFactoryLocator serializable and it *still* not working with GAE for the same reasons that I outlined in http://code.google.com/p/googleappen...detail?id=5299.

      In fact, before I submitted that issue with Google, I performed a much simpler experiment *without* Spring Social (as referenced briefly in the issue) and it didn't work, even though everything involved was Serializable. So, it is still an issue with GAE as far as I can tell. Also, the fact that the issue has been triaged and accepted by Google seems to indicate that they agree that it is a bug on their end.

      Comment


      • #4
        Craig,

        Thank you for the response. As long as ConnectionFactoryLocator does not implement Serializable there is no possibility that Spring Social will work in GAE or in any servlet environment which occasionally writes sessions to disk. So I would appreciate your attention to this issue.

        As far as the GAE issue with dynamic proxies, what about the approach I mentioned earlier in using a "no proxy" configuration for the ConnectionFactoryLocator/ConnectionFactoryRegistry bean? After its initial creation, in most use cases I suspect that access to this object will be only through "get" operations and therefore may be safe to share among threads?


        Thank you,
        David

        Comment


        • #5
          As mentioned in several comments in https://jira.springsource.org/browse/SOCIAL-268, the problem here is still a matter of Google App Engine not properly handling serialization and deserialization of JDK proxies. Making the aforementioned classes implement Serializable won't fix anything because those types are never serialized; only the proxy is serialized.

          Although this remains a bug in GAE, there is a work around: Create a non-JDK proxy for those types and wire them instead of the actual type.

          For example, I have the following class:

          Code:
          public class ConnectionFactoryLocatorPseudoProxy implements ConnectionFactoryLocator, Serializable, BeanFactoryAware {
          	private BeanFactory beanFactory;
          	private final String targetBeanName;
          	
          	public ConnectionFactoryLocatorPseudoProxy(String targetBeanName) {
          		this.targetBeanName = targetBeanName;
          	}
          
          	@Override
          	public void setBeanFactory(BeanFactory beanFactory) {
          		this.beanFactory = beanFactory;
          	}
          
          	@Override
          	public <A> ConnectionFactory<A> getConnectionFactory(Class<A> apiType) {
          		return getTargetBean().getConnectionFactory(apiType);
          	}
          
          	@Override
          	public ConnectionFactory<?> getConnectionFactory(String providerId) {
          		return getTargetBean().getConnectionFactory(providerId);
          	}
          
          	@Override
          	public Set<String> registeredProviderIds() {
          		return getTargetBean().registeredProviderIds();
          	}
          	
          	private ConnectionFactoryLocator getTargetBean() {
          		return (ConnectionFactoryLocator) beanFactory.getBean(targetBeanName);
          	}
          }
          And I've wired it in SocialConfig.java like this:

          Code:
          @Bean
          public ConnectionFactoryLocator connectionFactoryLocator() {
          	return new ConnectionFactoryLocatorPseudoProxy("connectionFactoryLocatorTarget");
          }
          
          @Bean
          public ConnectionFactoryLocator connectionFactoryLocatorTarget() {
          	ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
          	registry.addConnectionFactory(new TwitterConnectionFactory(environment.getProperty("twitter.consumerKey"),
          			environment.getProperty("twitter.consumerSecret")));
          	registry.addConnectionFactory(new FacebookConnectionFactory(environment.getProperty("facebook.clientId"),
          			environment.getProperty("facebook.clientSecret")));
          	return registry;
          }
          Thus the proxy gets wired everywhere it's needed instead of the actual ConnectionFactoryLocator.

          Likewise, I have a similar proxy and config for the UsersConnectionRepository bean.

          Admittedly, this is a very simplistic approach and was done quickly just to prove that it would work in Google App Engine. There's a lot that could be done to make the proxy class more elegant. But it does represent a workaround for the bug in GAE.

          Comment


          • #6
            Hi Craig,

            Thank you for posting the code snippets. I was able to reuse these within my implementation and can now successfully signin new users within GAE.

            David

            Comment


            • #7
              Glad that worked for you. I hated having to resort to that, but unless GAE can properly do serialization of proxies, any other solution would be even more ugly. I'm holding up hope that Google will fix that problem and this workaround won't be necessary long-term.

              Comment


              • #8
                Hi Craig,

                Lets assume there are two nodes and sessions are serialized / deserialized to handle failover of nodes.

                If we implement this feature (non JDK proxy) in the clustered environment, will the beanfactory work when the deserialization of session happens at the another node?

                I am new to spring so having this question on beanfactory.

                Thanks
                Suresh

                Comment


                • #9
                  This is really a question for the Container forum, not the Spring Social forum. And it certainly doesn't seem related to this thread. Could you re-ask the question in the Container forum? http://forum.springsource.org/forumd...p?26-Container

                  Comment


                  • #10
                    Is this Issue solved?? I have the same problem right now

                    Code:
                    	@Bean
                    	@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
                    	public ConnectionFactoryLocator connectionFactoryLocator() {
                            }

                    Code:
                    2013-08-05 23:27:00.472
                    /signin/twitter
                    java.lang.RuntimeException: java.io.NotSerializableException: org.springframework.social.connect.support.ConnectionFactoryRegistry
                    	at com.google.apphosting.runtime.SessionManagerUtil.serialize(SessionManagerUtil.java:31)

                    Comment

                    Working...
                    X