GWT with JDO problem
Solution 1
Sriram Narayan says to String-encode the Key to get it to pass through GWT's RPC mechanism:
@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;
Solution 2
Once you're fed up with JDO, take a look at objectify. I've found it to be a lot nicer to work with, and it has full GWT interop without DTOs.
Solution 3
You can use the Key class in GWT code by adding these additional jar files:
http://www.resmarksystems.com/code/
- appengine-utils-client-1.0.jar
- appengine-utils-server-1.0.jar
This basically gives the GWT compiler a GWT-friendly version of the Key and other AppEngine classes. (like Text, Blob and User..)
To use:
- Add the appengine-utils-client-1.0.jar anywhere in your build path.
- Put the appengine-utils-server-1.0.jar in your WEB-INF/lib folder.
- Add the following to your GWT module:
- < inherits name="com.resmarksystems.AppEngineDataTypes"/>
Solution 4
The second tutorial you've referenced has a section on shadowing the com.google.appengine.api.datastore.Key
class, since it's not available to GWT:
Since I'm not doing anything with the Key class on the client I'm going to stub it out. This actually requires a few steps and involves the super-src feature of GWT XML module files.
You might want to take a look at the GWT documentation, which states that
The heart of GWT is a compiler that converts Java source into JavaScript
, therefore you need to have the source code available to use a given class in the client code.
Solution 5
Another option would be to implement a DTO ( Data Transfer Object ) that you are using in the client instead of using the persistent objects directly. Or, you could go to JPA instead of JDO. In the example data class in the appengine JPA docs the Id is a Long instead of that Key implementation http://code.google.com/appengine/docs/java/datastore/usingjpa.html
Related videos on Youtube
Maksim
Updated on April 17, 2022Comments
-
Maksim about 2 years
I just start playing with GWT I'm having a really hard time to make GWT + JAVA + JDO + Google AppEngine working with DataStore. I was trying to follow different tutorial but had no luck. For example I wend to these tutorials: TUT1 TUT2
I was not able to figure out how and what i need to do in order to make this work. Please look at my simple code and tell me what do i need to do so i can persist it to the datastore:
1. ADDRESS ENTITY
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. PERSON ENTITY
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>
I tried to add Key class and everything else in those tutorials but it looks like i'm missing something.
Here is my error: alt text http://vasura.s3.amazonaws.com/Picture2.png
or before i was getting this error:
Key cannot be resolved to a type
What is the best solution to make this working?
-
Maksim almost 15 yearsThat's the tutorial i tried to follow (TUT2 link on the top). Try to read my post first and then respond. Thanks tho.
-
digitaljoel almost 15 yearsSorry about the original answer, you are correct it was not helpful. I read the question, but didn't follow the links.
-
Maksim almost 15 yearsYeah, i was just able to create JPA to work but how do i pass objects from/to GWT?
-
digitaljoel almost 15 yearsYou'll want to checkout the GWT developer's guide on server communication at code.google.com/webtoolkit/doc/1.6/… Their method in the example passes a String as the parameter and the return type, but you can pass and return any object that adheres to their serialization rules which are also in that same document.
-
digitaljoel almost 15 yearsThat said, you'll want to look at rustyshelf's answer to your TUT1 link on top about where to put the types you are using for client/server communication and how to get GWT to see them.
-
Otavio almost 15 yearsThis is a common mistake since you can basically have java.lang and java.util classes on the client side of your app. In this way you wont be able to send Key or User objects to the client side for example.
-
digitaljoel almost 15 yearsthis post has some good info about passing (or not passing) persistent objects from the server to the client. From the items there, it looks like you will definitely want to use DTOs stackoverflow.com/questions/749522/…
-
dfrankow almost 15 yearsThe second tutorial is a dastardly hack. Is there any better way?
-
Richard Berger over 13 yearsFWIW The resmark solution worked great for me on GWT 2.1.0//GAE 1.3.8.