GWT с проблемой JDO
Я только начинаю играть с GWT. Мне очень трудно заставить GWT + JAVA + JDO + Google AppEngine работать с DataStore. Я пытался следовать другому учебнику, но безуспешно. Например, я подхожу к этим урокам: TUT1 TUT2
Я не смог понять, как и что мне нужно сделать, чтобы сделать эту работу. Пожалуйста, посмотрите на мой простой код и скажите, что мне нужно сделать, чтобы я мог сохранить его в хранилище данных:
1. Адрес объекта
package com.example.rpccalls.client;
import java.io.Serializable;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
public class Address implements Serializable{
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private int addressID;
@Persistent private String address1;
@Persistent private String address2;
@Persistent private String city;
@Persistent private String state;
@Persistent private String zip;
public Address(){}
public Address(String a1, String a2, String city, String state, String zip){
this.address1 = a1;
this.address2 = a2;
this.city = city;
this.state = state;
this.zip = zip;
}
/* Setters and Getters */
}
2. ЛИЧНОСТЬ ЛИЦА
package com.example.rpccalls.client;
import java.io.Serializable;
import java.util.ArrayList;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;
@PersistenceCapable
public class Person implements Serializable{
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
@Persistent private String name;
@Persistent private int age;
@Persistent private char gender;
@Persistent ArrayList<Address> addresses;
public Person(){}
public Person(String name, int age, char gender){
this.name = name;
this.age = age;
this.gender = gender;
}
/* Getters and Setters */
}
3. RPCCalls
package com.example.rpccalls.client;
import java.util.ArrayList;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
public class RPCCalls implements EntryPoint {
private static final String SERVER_ERROR = "An error occurred while attempting to contact the server. Please check your network connection and try again.";
private final RPCCallsServiceAsync rpccallService = GWT.create(RPCCallsService.class);
TextBox nameTxt = new TextBox();
Button btnSave = getBtnSave();
public void onModuleLoad() {
RootPanel.get("inputName").add(nameTxt);
RootPanel.get("btnSave").add(btnSave);
}
private Button getBtnSave(){
Button btnSave = new Button("SAVE");
btnSave.addClickHandler(
new ClickHandler(){
public void onClick(ClickEvent event){
saveData2DB(nameTxt.getText());
}
}
);
return btnSave;
}
void saveData2DB(String name){
AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
Window.alert("WOOOHOOO, ERROR: " + SERVER_ERROR);
// TODO: Do something with errors.
}
public void onSuccess(String result) {
Window.alert("Server is saying: ' " + result + "'");
}
};
ArrayList<Address> aa = new ArrayList<Address>();
aa.add(new Address("123 sasdf","", "Some City", "AZ", "93923-2321"));
aa.add(new Address("23432 asdf", "Appt 34", "Another City", "AZ", "43434-4432"));
Person p = new Person();
p.setName(name);
p.setAge(23);
p.setGender('m');
p.setAddresses(aa);
// !!!!!!!!!!!!!!!!!! SERVER CALL !!!!!!!!!!!!!!!!!!
rpccallService.saveName(p, callback);
// !!!!!!!!!!!!!!!!!! SERVER CALL !!!!!!!!!!!!!!!!!!
}
}
4. RPCCallsService
package com.example.rpccalls.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath("calls")
public interface RPCCallsService extends RemoteService {
String saveName(Person p);
}
5. RPCCallsServiceAsync
package com.example.rpccalls.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface RPCCallsServiceAsync {
void saveName(Person p, AsyncCallback<String> callback);
}
6. ** RPCCalls.gwt.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.4//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.6.4/distro-source/core/src/gwt-module.dtd">
<module rename-to='rpccalls'>
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.user.theme.standard.Standard'/>
<entry-point class='com.example.rpccalls.client.RPCCalls'/>
</module>
Я пытался добавить класс Key и все остальное в этих уроках, но, похоже, я что-то упустил.
Вот моя ошибка: http://vasura.s3.amazonaws.com/Picture2.png
или до того, как я получил эту ошибку:
Ключ не может быть разрешен для типа
Как лучше всего это сделать?
6 ответов
Шрирам Нараян говорит String-закодировать ключ, чтобы он прошел через механизм RPC GWT:
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class SomeDomainClass implements Serializable {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
String id;
Во втором уроке, на который вы ссылаетесь, есть раздел о затенении com.google.appengine.api.datastore.Key
класс, так как он не доступен для GWT:
Поскольку я ничего не делаю с классом Key на клиенте, я собираюсь заглушить это. Это на самом деле требует нескольких шагов и включает в себя функцию супер-src файлов модуля XML GWT.
Возможно, вы захотите взглянуть на документацию GWT, в которой говорится, что
Сердцем GWT является компилятор, который преобразует исходный код Java в JavaScript
поэтому вам необходимо иметь исходный код для использования данного класса в клиентском коде.
Как только вы устали от JDO, взгляните на objectify. Я обнаружил, что с ним гораздо приятнее работать, и он имеет полное взаимодействие с GWT без DTO.
Вы можете использовать класс Key в коде GWT, добавив следующие дополнительные файлы jar:
http://www.resmarksystems.com/code/
- AppEngine-Utils-клиент-1.0.jar
- AppEngine-Utils-сервера 1.0.jar
Это в основном дает GWT-компилятору GWT-дружественную версию Key и других классов AppEngine. (как текст, блоб и пользователь..)
Использовать:
- Добавьте appengine-utils-client-1.0.jar в любом месте вашего пути сборки.
- Поместите appengine-utils-server-1.0.jar в вашу папку WEB-INF/lib.
- Добавьте следующее в ваш модуль GWT:
- <наследует имя = "com.resmarksystems.AppEngineDataTypes" />
Другой вариант - реализовать DTO (объект передачи данных), который вы используете в клиенте, а не напрямую использовать постоянные объекты. Или вы можете пойти в JPA вместо JDO. В примере класса данных в документах appengine JPA идентификатор является длинным вместо реализации этого ключа http://code.google.com/appengine/docs/java/datastore/usingjpa.html
Может быть, вы забыли создать реализацию для RPCCallsService? Я не вижу его в списке файлов, которые у вас есть.
У вас должен быть файл RPCCallsServiceImpl.java в RPCCalls/src/com/example/rpccalls/server/, это файл реализации для интерфейса RPCCallsService.java.
Это будет выглядеть примерно так:
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.example.rpccalls.client.RPCCallsService;
public class RPCCallsServiceImpl extends RemoteServiceServlet implements RPCCallsService {
// Factory to get persistence manager object later
private static final PersistenceManagerFactory PMF = JDOHelper.getPersistenceManagerFactory("transactional-optional");
public String saveName(Person p) {
// Data Store need persistence manager object for writing to it
PersistenceManager pm = PMF.getPersistenceManager();
// Recommended way to save an object to the data store
try {
pm.makePersistent(p);
} finally {
pm.close();
}
// You want it to return string
return p.getName();
}
}
Надеюсь, это поможет вам решить проблему. Ура:)