【发布时间】: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