Java Google AppEngine上的FacebookXmlRestClient NotSerializableException

Java Google AppEngine上的FacebookXmlRestClient NotSerializableException,java,google-app-engine,facebook,facebook-java-api,Java,Google App Engine,Facebook,Facebook Java Api,我试着效仿这个例子,但当我 我试图保存到会话的客户端对象。该代码被托管在谷歌appengine平台上 java.lang.RuntimeException: java.io.NotSerializableException: com.google.code.facebookapi.FacebookXmlRestClient at com.google.apphosting.runtime.jetty.SessionManager.serialize(SessionManager.java

我试着效仿这个例子,但当我 我试图保存到会话的客户端对象。该代码被托管在谷歌appengine平台上

java.lang.RuntimeException: java.io.NotSerializableException: com.google.code.facebookapi.FacebookXmlRestClient
    at com.google.apphosting.runtime.jetty.SessionManager.serialize(SessionManager.java:387)
    at com.google.apphosting.runtime.jetty.SessionManager.createEntityForSession(SessionManager.java:364)
    at com.google.apphosting.runtime.jetty.SessionManager$AppEngineSession.save(SessionManager.java:164)
    at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:41)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    .....
    at com.google.net.async.Connection.handleReadEvent(Connection.java:474)
    at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:831)
    at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207)
    at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:103)
    at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251)
    at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:418)
    at java.lang.Thread.run(Thread.java:636)
Caused by: java.io.NotSerializableException: com.google.code.facebookapi.FacebookXmlRestClient
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1173)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:343)
    at java.util.HashMap.writeObject(HashMap.java:1018)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at  sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
我更新了过滤器代码,以使用映射来保存会话和关联的客户端对象,但我仍然可以获得有效的登录。有人能发现这段代码的问题吗,或者解释一下 com.google.code.facebookapi.ExtensibleClient是否可以正确使用

import com.google.code.facebookapi.FacebookException;
import com.google.code.facebookapi.FacebookWebappHelper;
import com.google.code.facebookapi.FacebookXmlRestClient;
import com.google.code.facebookapi.IFacebookRestClient;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.w3c.dom.Document;

public class FacebookFilter implements Filter {

        private static final Logger logger = Logger.getLogger(FacebookFilter.class.getName());

        private String api_key;
        private String secret;
        private static Map map = new HashMap();

        public void init(FilterConfig filterConfig) throws ServletException {
                api_key = filterConfig.getInitParameter("facebook_api_key");
                secret = filterConfig.getInitParameter("facebook_secret_key");
                if(api_key == null || secret == null) {
                        throw new ServletException("Cannot initialise Facebook User Filter because the " +
                                                           "facebook_api_key or facebook_secret context init " +
                                                           "params have not been set. Check that they're there " +
                                                           "in your servlet context descriptor.");
                } else {
                        logger.info("Using facebook API key: " + api_key);
                }
        }

        public void destroy() {
        }

        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
                try {
                        HttpServletRequest request = (HttpServletRequest)req;
                        HttpServletResponse response = (HttpServletResponse)res;

                        HttpSession session = request.getSession(true);
                        IFacebookRestClient<Document> userClient = getUserClient(session);
                        if(userClient == null) {
                            logger.info("User session doesn't have a Facebook API client setup yet. Creating one and storing it in the user's session.");
                            userClient = new FacebookXmlRestClient(api_key, secret);
                            logger.info("add new session to map "+map.size()+" "+session.getId()+" "+userClient.toString());
                            map.put(session,userClient);
                        }

                        logger.fine("Creating a FacebookWebappHelper, which copies fb_ request param data into the userClient");
                        FacebookWebappHelper<Document> facebook = new FacebookWebappHelper<Document>(request, response, api_key, secret, userClient);
                        String nextPage = request.getRequestURI();
                        nextPage = nextPage.substring(nextPage.indexOf("/", 1) + 1); //cut out the first /, the context path and the 2nd /
                        logger.fine(nextPage);
                        boolean redirectOccurred = facebook.requireLogin(nextPage);
                        if(redirectOccurred) {
                                return;
                        }
                        redirectOccurred = facebook.requireFrame(nextPage);
                        if(redirectOccurred) {
                                return;
                        }

                        long facebookUserID;
                        try {
                            facebookUserID = userClient.users_getLoggedInUser();
                            logger.info("facebookUserID "+facebookUserID+" "+session.getId());

                        } catch(FacebookException ex) {
                            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error while fetching user's facebook ID");
                            logger.warning("Error while getting cached (supplied by request params) value " +
                                             "of the user's facebook ID or while fetching it from the Facebook service " +
                                             "if the cached value was not present for some reason. Cached value = {} "+ userClient.getCacheUserId());
                            return;
                        }
                        chain.doFilter(request, response);
                }
        }

    public static FacebookXmlRestClient getUserClient(HttpSession session) {
            if(map.containsKey(session))
            {
                logger.info("return match "+session.getId());
                return (FacebookXmlRestClient) map.get(session);
            }       
            else
            {
                logger.warning("getUserClient() null "+session.getId());
                return null;
            }

    }
}
import com.google.code.facebookapi.FacebookException;
导入com.google.code.facebookapi.FacebookWebappHelper;
导入com.google.code.facebookapi.FacebookXmlRestClient;
导入com.google.code.facebookapi.IFacebookRestClient;
导入java.util.HashMap;
导入java.util.Map;
导入java.util.logging.Logger;
导入org.w3c.dom.Document;
公共类FacebookFilter实现过滤器{
私有静态最终记录器Logger=Logger.getLogger(FacebookFilter.class.getName());
私有字符串api_密钥;
私人字符串秘密;
private static Map=new HashMap();
public void init(FilterConfig FilterConfig)抛出ServletException{
api_key=filterConfig.getInitParameter(“facebook_api_key”);
secret=filterConfig.getInitParameter(“facebook_secret_key”);
如果(api_key==null || secret==null){
抛出新的ServletException(“无法初始化Facebook用户筛选器,因为”+
“facebook\u api\u密钥或facebook\u秘密上下文初始化”+
“尚未设置参数。请检查它们是否存在”+
“在servlet上下文描述符中。”);
}否则{
info(“使用facebook API键:“+API_键”);
}
}
公共空间销毁(){
}
public void doFilter(ServletRequest-req、ServletResponse-res、FilterChain-chain)抛出IOException、ServletException{
试一试{
HttpServletRequest请求=(HttpServletRequest)请求;
HttpServletResponse=(HttpServletResponse)res;
HttpSession session=request.getSession(true);
IFacebookRestClient userClient=getUserClient(会话);
if(userClient==null){
info(“用户会话还没有Facebook API客户端设置。创建一个并将其存储在用户会话中。”);
userClient=新的FacebookXmlRestClient(api_密钥,机密);
logger.info(“将新会话添加到映射”+map.size()+“”+session.getId()+“”+userClient.toString());
put(会话,用户客户端);
}
fine(“创建一个FacebookWebappHelper,它将fb_uu请求参数数据复制到userClient中”);
FacebookWebappHelper facebook=新的FacebookWebappHelper(请求、响应、api_密钥、机密、用户客户端);
字符串nextPage=request.getRequestURI();
nextPage=nextPage.substring(nextPage.indexOf(“/”,1)+1);//切掉第一个/、上下文路径和第二个/
好的(下一页);
boolean redirectOccurse=facebook.requireLogin(下一页);
如果(发生重定向){
回来
}
重定向发生=facebook.requireFrame(下一页);
如果(发生重定向){
回来
}
长facebookUserID;
试一试{
facebookUserID=userClient.users_getLoggedInUser();
logger.info(“facebookUserID”+facebookUserID+“”+session.getId());
}捕获(FacebookException ex){
senderro(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,“获取用户facebook ID时出错”);
logger.warning(“获取缓存(由请求参数提供)值时出错”+
“用户的facebook ID或从facebook服务获取时”+
“如果缓存值由于某种原因不存在。缓存值={}”+userClient.getCacheUserId());
回来
}
链式过滤器(请求、响应);
}
}
公共静态FacebookXmlRestClient getUserClient(HttpSession会话){
if(地图容器(会话))
{
info(“return match”+session.getId());
return(FacebookXmlRestClient)map.get(session);
}       
其他的
{
警告(“getUserClient()null”+session.getId());
返回null;
}
}
}

您放入
HttpSession
的任何对象都需要标记为
可序列化
。(GAE使用数据存储来存储会话数据)

只是想知道,与其使用HttpSession作为映射中的键,不如尝试使用会话id?例如:

map.put(session.getId(),userClient);

我没有将userClient设置为http会话或请求对象的属性或参数(以避免可序列化问题),而是将其添加到普通映射中。当您尝试将其放入映射时,是否会出现相同的错误消息?您是否尝试了我的建议(使用会话ID)?