【问题标题】:Failed to create an instance of Service via deferred binding通过延迟绑定创建服务实例失败
【发布时间】:2011-03-22 05:49:55
【问题描述】:

我一直在尝试使用mvp4g framework 构建一个 GWT / Google App Engine 网络应用。

我不断收到关于无法通过延迟绑定创建我的服务实例的错误。

我的 Acebankroll.gwt.xml 文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='acebankroll'>
    <inherits name='com.google.gwt.user.User'/>
    <inherits name="com.google.gwt.i18n.I18N"/>
    <inherits name='com.google.gwt.user.theme.standard.Standard'/>  
    <inherits name='com.mvp4g.Mvp4gModule'/>
    <entry-point class='com.softamo.acebankroll.client.AceBankroll'/>
     <source path='client'/>  
</module>

我的入口模块看起来像:

public class AceBankroll implements EntryPoint {
    public void onModuleLoad() {
        Mvp4gModule module = (Mvp4gModule)GWT.create( Mvp4gModule.class );
        module.createAndStartModule();
        RootPanel.get().add((Widget)module.getStartView());
    }
}

错误跟踪

我发布完整的错误跟踪作为答案。

常见问题解答和试用

我已阅读下一个常见错误列表可能会导致此错误:

  • ServiceAsync 接口具有带返回值的方法。这是错误,所有方法都需要返回void。

  • Service 接口不扩展 RemoteService 接口。

  • ServiceAsync 接口中的方法错过了 AsyncCallback 的最后一个参数。

  • ExampleService 和 ExampleServiceAsync 这两个接口上的方法不完全匹配(返回值和 AsyncCallback 参数除外)

我检查了以上所有情况,没有发现问题。

如何在演示者中插入服务?

这是一个 sn-p,说明了我如何在演示者类中注入服务。

protected MainServiceAsync service = null;
@InjectService
public void setService( MainServiceAsync service ) {
    this.service = service;
}

你有需要的库吗?

是的,我的 lib 目录中有 commons-configuration-1.6.jar、commons-lang-2.4.jar 和 mvp4g-1.1.0.jar。

你的项目编译了吗?

是的,它确实可以编译。我使用带有 GWT/Google App Engine 插件的 Eclipse。接下来我发布我的 .classpath

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
    <classpathentry kind="src" path="src"/>
    <classpathentry kind="src" output="test-classes" path="test"/>
    <classpathentry kind="con" path="com.google.appengine.eclipse.core.GAE_CONTAINER"/>
    <classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER"/>
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
    <classpathentry kind="lib" path="lib/commons-configuration-1.6.jar"/>
    <classpathentry kind="lib" path="lib/commons-lang-2.4.jar"/>
    <classpathentry kind="lib" path="lib/mvp4g-1.1.0.jar"/>
    <classpathentry kind="lib" path="test/lib/emma.jar"/>
    <classpathentry kind="lib" path="test/lib/junit-4.5.jar"/>
    <classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/testing/appengine-testing.jar"/>
    <classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/impl/appengine-api.jar"/>
    <classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/impl/appengine-api-labs.jar"/>
    <classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/impl/appengine-api-stubs.jar"/>
    <classpathentry kind="lib" path="C:/Users/sdelamo/Programms/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.1_1.3.1.v201002101412/appengine-java-sdk-1.3.1/lib/impl/appengine-local-runtime.jar"/>
    <classpathentry kind="output" path="war/WEB-INF/classes"/>
</classpath>

你的 Bean 可以序列化吗?

是的,它们是可序列化的。他们实现了下一个接口:

public interface BasicBean extends Serializable  {
    public String getId();      
    public void copy(BasicBean ob); 
}

它们都有一个空参数构造函数。其中一些有两个构造函数。一个不带参数,一个带参数。

其中一些实现了这个接口

public interface NameObject extends BasicBean, BaseOwnedObject, Comparable<NameObject>   { 
    public String getName();
    public void setName(String name);       
    public abstract int compareTo(NameObject ob);
}

Comparable 会导致问题吗?

您的服务代码是什么样的?

我发布我的服务代码:

主要服务

@RemoteServiceRelativePath( "main" )
public interface MainService extends RemoteService {
    public List<UserBean> getUsers();    
    public void deleteUser(UserBean user);    
    public void createUser(UserBean user);    
    public void updateUser( UserBean user );        
    public String authenticate(String username, String password);       
    public boolean isSessionIdStillLegal(String sessionId);     
    public void signOut();      
    public boolean userAlreadyExists(String email);     
    public UserBean getByEmail(String email);       
    public void confirmUser(String email);          
    public UserBean getUserById(String id);
}

MainServiceAsync

public interface MainServiceAsync {
    public void getUsers(AsyncCallback<List<UserBean>> callback);    
    public void deleteUser(UserBean user, AsyncCallback<Void> callback);    
    public void createUser(UserBean user, AsyncCallback<Void> callback);    
    public void updateUser( UserBean user, AsyncCallback<Void> callback);       
    public void authenticate(String username, String password, AsyncCallback<String> callback);     
    public void isSessionIdStillLegal(String sessionId, AsyncCallback<Boolean> callback);       
    public void signOut(AsyncCallback<Void> callback);      
    public void userAlreadyExists(String email, AsyncCallback<Boolean> callback);       
    public void getByEmail(String email, AsyncCallback<UserBean> callback );            
    public void confirmUser(String email, AsyncCallback<Void> callback );           
    public void getUserById(String id, AsyncCallback<UserBean> callback);
}

基础豆

import java.io.Serializable;    
public interface BasicBean extends Serializable  {
    public String getId();      
    public void copy(BasicBean ob); 
}

用户 Bean

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class UserBean implements BasicBean {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    protected Long ident;       
    @Persistent
    private String name = null;     
    @Persistent
    private String email = null;        
    @Persistent
    private boolean confirmed = false;      
    @Persistent
    private String password = null;
    
    public UserBean() { }
    
    public String getId() {
        if( ident == null ) return null;
        return ident.toString();
    }
    public void setId(String id) {
        this.ident = Long.parseLong(id);
    }           
    public String getEmail( ) { return email; }
    public void setEmail(String email) { this. email = email; }     
    public String getName() { return name; }
    public void setName(String name) { this. name = name; }     
    public String getPassword() { return password; }    
    public void setPassword(String password) {  this.password = password;}      
    public boolean isConfirmed() { return confirmed;}
    public void setConfirmed(boolean confirmed) {this.confirmed = confirmed;}       
    public void copy(BasicBean ob) {
         UserBean user = (UserBean) ob;
        this.name = user.name;
        this.email = user.email;
        this.password = user.password;      
    }
}

接下来我发布 web.xml 的摘录
注意。我还有 7 项其他服务。我正在使用 MVP4G 的模块功能。我为 web.xml 中的每个模块定义了其他 servlet

<servlet>
    <servlet-name>mainServlet</servlet-name>
    <servlet-class>com.softamo.acebankroll.server.MainServiceImpl</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>mainServlet</servlet-name>
    <url-pattern>/acebankroll/main</url-pattern>
</servlet-mapping>

服务器

BaseServiceImpl

public abstract class BaseServiceImpl extends RemoteServiceServlet {
    protected Map users = new HashMap();
    protected static final MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
    protected static final Logger log = Logger.getLogger(BaseServiceImpl.class.getName());    
    protected String getSessionId() {
        return getThreadLocalRequest().getSession().getId();
    }    
    protected String getCurrentUserId() {
        String id = getSessionId();
        UserBean user = (UserBean) users.get(id);
        if(user!=null) 
            return user.getId();
        return null;
    }    
    protected void saveBaseObject(BasicBean ob) {
        PersistenceManager pm = JdoUtil.getPm();
        String sessionId = getSessionId();      
        UserBean user = (UserBean) users.get(sessionId);
        if(user!=null) {
            String user_id = user.getId();
            ((BaseOwnedObject)ob).setUserId(user_id);
            pm.makePersistent(ob);
        }           
    }    
    protected void deleteBaseObject(Class classname, String id) {
        PersistenceManager pm = JdoUtil.getPm();                
        pm.deletePersistent( pm.getObjectById(classname, Long.parseLong(id) ));     
    }    
    protected List getAll(Class class_name) {
        PersistenceManager pm = JdoUtil.getPm();
        pm.setDetachAllOnCommit(true);

        Query q = pm.newQuery(class_name);          
        if(q==null) 
            return new ArrayList<BasicBean>();
        q.setFilter("userId == userIdParam");
        q.declareParameters("String userIdParam");          
        String userId = getCurrentUserId();
        return (List) q.execute(userId);
    }    
    public boolean isSessionIdStillLegal(String sessionId) {
        return (users.containsKey(sessionId))? true : false;
    }    
    public void signOut() {
        String id = getSessionId();
        synchronized(this) {
            users.remove(id);
        }
    }    
    public BasicBean getObjectById(Class classname, String id) {
        BasicBean result = null;
        PersistenceManager pm = JdoUtil.getPm();
        pm.setDetachAllOnCommit(true);
        result = pm.getObjectById(classname, Long.parseLong(id) );
        return result;
    }
}

MainServiceImpl

public class MainServiceImpl extends BaseServiceImpl implements MainService {       
    public MainServiceImpl() {}     
    public String authenticate(String username, String password) {
        PersistenceManager pm = JdoUtil.getPm();

        UserBean user = getByEmail(username);
        if(user==null || !user.isConfirmed())
            return null;
        String hashFromDB = user.getPassword();
        boolean valid = BCrypt.checkpw(password, hashFromDB);
        if(valid) { 
            String id = getSessionId();
            synchronized( this ) {
                users.put(id, user) ;
            }
            return id;  
        }
        return null;
    }    
    public void deleteUser(UserBean user) {
        deleteBaseObject(UserBean.class, user.getId());
    }
    public List<UserBean> getUsers() {
        PersistenceManager pm = JdoUtil.getPm();
        pm.setDetachAllOnCommit(true);
        Query q = pm.newQuery(UserBean.class);          
        if(q==null) 
            return new ArrayList<UserBean>();           
        return (List) q.execute();      
    }    
    public boolean userAlreadyExists(String email) {
        return (getByEmail(email)!=null) ? true : false;        
    }    
    public void updateUser(UserBean object) {
        saveBaseObject(object);
    }    
    public void confirmUser(String email) {
        PersistenceManager pm = JdoUtil.getPm();        
        UserBean user = getByEmail(email);
        if(user!=null) {
            user.setConfirmed(true);
            pm.makePersistent(user);
        }   
    }    
    public void createUser(UserBean user) {
        PersistenceManager pm = JdoUtil.getPm();
        String sessionId = getSessionId();
        // Only store it if it does not exists
        if( (getByEmail(user.getEmail()))==null) {
            String hash = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt());
            user.setPassword(hash);
            pm.makePersistent(user);
            synchronized( this ) {
                users.put(sessionId, user);              
            }           
        }       
    }    
    public UserBean getByEmail(String email) {
        return new MyAccountServiceImpl().getByEmail(email);
    }    
    public UserBean getUserById(String id) {
        return new MyAccountServiceImpl().getUserById(id);
    }
}

解决方案

显然,我的 Bean 类中的 Google App Engine Annotations 导致了问题。从客户端代码中删除注释解决了这个问题。如果我在服务器端有带有 JDO 表示法的类,我所知道的。也就是说,bean 是普通的数据传输对象,在服务器端被克隆到带有 JDO 注释的对象中。

我真的很累。我不知道该尝试什么。非常感谢任何帮助!

【问题讨论】:

    标签: google-app-engine gwt mvp


    【解决方案1】:

    如果您的服务方法包含 POJO,它们可能会给您带来问题,它们必须具有零参数构造函数或未定义构造函数。他们还必须实现 IsSerializable 或 Serializable。

    您可以尝试手动创建服务:

    MainServiceAsync service = GWT.create(MainService.class);
    

    也许发布 MainService 类。

    已编辑:

    这是延迟绑定失败的 treelogger 的输出,当您执行 gwt 编译时,它会输出到控制台。如果您在托管模式下运行,您还可以在 devmode 控制台中看到此输出。始终检查第一个错误,因为其他大部分时间都是由第一个错误引起的。

    Compiling module se.pathed.defa.DefaultGwtProject
       Scanning for additional dependencies: file:/C:/Users/Patrik/workspace/skola-workspace/DefaultGwtProject/src/se/pathed/defa/client/DefaultGwtProject.java
          Computing all possible rebind results for 'se.pathed.defa.client.GreetingService'
             Rebinding se.pathed.defa.client.GreetingService
                Invoking com.google.gwt.dev.javac.StandardGeneratorContext@16c6a55
                   Generating client proxy for remote service interface 'se.pathed.defa.client.GreetingService'
                      [ERROR] se.pathed.defa.shared.UserBean is not default instantiable (it must have a zero-argument constructor or no constructors at all) and has no custom serializer. (reached via se.pathed.defa.shared.UserBean)
                      [ERROR] se.pathed.defa.shared.UserBean has no available instantiable subtypes. (reached via se.pathed.defa.shared.UserBean)
                         [ERROR]    subtype se.pathed.defa.shared.UserBean is not default instantiable (it must have a zero-argument constructor or no constructors at all) and has no custom serializer. (reached via se.pathed.defa.shared.UserBean)
       [ERROR] Errors in 'file:/C:/Users/Patrik/workspace/skola-workspace/DefaultGwtProject/src/se/pathed/defa/client/DefaultGwtProject.java'
          [ERROR] Line 37:  Failed to resolve 'se.pathed.defa.client.GreetingService' via deferred binding
       Scanning for additional dependencies: jar:file:/C:/eclipse/plugins/com.google.gwt.eclipse.sdkbundle.2.0.3_2.0.3.v201002191036/gwt-2.0.3/gwt-user.jar!/com/google/gwt/core/client/impl/SchedulerImpl.java
          [WARN] The following resources will not be created because they were never committed (did you forget to call commit()?)
             [WARN] C:\Users\Patrik\AppData\Local\Temp\gwtc301646733929273376.tmp\se.pathed.defa.DefaultGwtProject\compiler\se.pathed.defa.client.GreetingService.rpc.log
          [WARN] For the following type(s), generated source was never committed (did you forget to call commit()?)
             [WARN] se.pathed.defa.client.GreetingService_Proxy
       [ERROR] Cannot proceed due to previous errors
    

    【讨论】:

    • 如果我手动创建服务。它以同样的方式失败
    • 我所有的 Bean 都是可序列化的。我添加了更多代码。我希望它能澄清事情
    • 堆栈跟踪表明 gwt 编译器无法创建您的 MainService,因此错误在客户端。 Gwt 使用它的 treelogger 报告编译中的错误以及您应该检查的地方。您应该在堆栈跟踪之前找到 treelogger 的输出。
    • 在哪里可以找到 treelogger 的输出?我在下面的答案中发布了更多信息。
    • 您发布的错误跟踪中的第一行似乎来自树记录器,其中记录了堆栈跟踪。在此之前检查错误。
    【解决方案2】:

    如果您的客户端包中的任何内容具有未列入白名单的导入,则可能会发生这种情况。例如,我之所以打这个,是因为我的自动导入将一个 apache commons lang 类导入到我的客户端代码中。

    必须查看它们的导入,以确保客户端代码中没有异常。

    GWT 项目的结构如下:

    com.app.client com.app.server

    你不能在客户端拥有任何不兼容 GWT 的东西。

    【讨论】:

      猜你喜欢
      • 2012-05-12
      • 2013-02-23
      • 2013-08-06
      • 2013-08-09
      • 2014-12-17
      • 1970-01-01
      • 2021-01-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多