Не удалось создать экземпляр службы через отложенную привязку
Я пытаюсь создать веб-приложение GWT/Google App Engine с помощью mvp4g framework.
Я продолжаю получать сообщение об ошибке Невозможно создать экземпляр моей службы через отложенную привязку.
Файл My 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.
-
Сервисные интерфейсы не расширяют интерфейс RemoteService.
-
Методы интерфейсов ServiceAsync пропускают последний аргумент AsyncCallback.
-
Методы двух сопряженных, ExampleService и ExampleServiceAsync не соответствуют точно (кроме возвращаемого значения и аргумента AsyncCallback)
Я проверил все вышеперечисленные условия и не нашел проблемы.
Как вы вставляете свои услуги в докладчиков?
Вот фрагмент, иллюстрирующий, как я ввожу службу в классы-участники.
protected MainServiceAsync service = null;
@InjectService
public void setService( MainServiceAsync service ) {
this.service = service;
}
У вас есть необходимые библиотеки?
Да, у меня есть commons-configuration-1.6.jar, commons-lang-2.4.jar и mvp4g-1.1.0.jar в моем каталоге lib.
Выполняется ли ваш проект?
Да, он компилируется. Я использую Eclipse с плагином GWT/Google App Engine. Затем я отправляю свой .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 Serializable?
Да, они сериализуемы. Они реализуют следующий интерфейс:
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);
}
Возможны ли проблемы со сравнимыми?
Как выглядит ваш код обслуживания?
Я отправляю свой служебный код:
MainService
@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);
}
Основной Bean
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-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);
}
}
РЕШЕНИЕ
По всей видимости, аннотации Google App Engine в моих классах Bean вызывают проблему. Удаление аннотации из кода на стороне клиента решило проблему. Что я знаю, если у меня есть классы с обозначением JDO на стороне сервера. Это означает, что beans - это простой объект передачи данных, который клонируется в объект с аннотациями JDO на стороне сервера.
Я буквально сложена. Я не знаю, что попробовать. Любая помощь действительно ценится!
Ответы
Ответ 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 [email protected]
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
Ответ 2
Это может произойти, если что-либо, что есть в вашем клиентском пакете, имеет импорт, который не является белым. Например, я ударил это, потому что мой autoimport импортировал класс apache commons lang в мой клиентский код.
Можно было бы посмотреть на их импорт, чтобы убедиться, что в клиентском коде ничего странного нет.
Проекты GWT структурированы следующим образом:
com.app.client
com.app.server
вы не можете иметь ничего, что не совместимо с GWT на клиенте.