Tutorial :GWT with JDO problem


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:


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 */  }  


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?


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 {
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
String id;


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.


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.


You can use the Key class in GWT code by adding these additional jar files:


  • 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"/>


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


Could it be that you forgot to create the implementation for the RPCCallsService? I can't see it from the list of files that you have.

You should have a file called RPCCallsServiceImpl.java in RPCCalls/src/com/example/rpccalls/server/, it is the implementation file for the interface RPCCallsService.java.

It will look something like this:

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();    }    }  

Hopefully this help you to solve the problem. Cheers :)

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »