GWT with JDO problem

11,684

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

Share:
11,684

Related videos on Youtube

Maksim
Author by

Maksim

Updated on April 17, 2022

Comments

  • Maksim
    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
    Maksim almost 15 years
    That's the tutorial i tried to follow (TUT2 link on the top). Try to read my post first and then respond. Thanks tho.
  • digitaljoel
    digitaljoel almost 15 years
    Sorry about the original answer, you are correct it was not helpful. I read the question, but didn't follow the links.
  • Maksim
    Maksim almost 15 years
    Yeah, i was just able to create JPA to work but how do i pass objects from/to GWT?
  • digitaljoel
    digitaljoel almost 15 years
    You'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
    digitaljoel almost 15 years
    That 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
    Otavio almost 15 years
    This 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
    digitaljoel almost 15 years
    this 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
    dfrankow almost 15 years
    The second tutorial is a dastardly hack. Is there any better way?
  • Richard Berger
    Richard Berger over 13 years
    FWIW The resmark solution worked great for me on GWT 2.1.0//GAE 1.3.8.