The new Key<?> and GWT

948 views
Skip to first unread message

Jeff Schnitzer

unread,
Mar 3, 2011, 3:51:47 AM3/3/11
to objectify...@googlegroups.com
So... all is not well in GWT-land with the new Key<?>. In short: You
cannot create Key<?> objects client-side. I don't see any way to work
around this issue.

The explanation:

In the past, a Key<?> contained the POJO entity className en lieu of
Kind. This worked because there was a 1-to-1 mapping between class
names and datastore Kinds, and Objectify could map back and forth
just-in-time.

Polymorphism breaks this 1-to-1 relationship; all the classes in a
polymorphic hierarchy have the same Kind. Thus the new Key<?>
actually wraps a datastore native Key... a much simpler and more
elegant solution. But now think about this:

Key<Car> key = new Key<Car>(Car.class, 123);

...this means that the Key<?> constructor needs to know how to
construct a datastore Key from Car.class. Thus it needs to know the
Kind of a Car... which might be Vehicle... and the only way to know
that is by examining the annotations of Car.class.

But GWT-land does not have annotations. Class.getAnnotation() is not
part of the JRE emulation.

Basically, the polymorphism feature makes it impossible to construct
Key<?> in GWT code. I have tried to think of ways around the problem,
but I'm starting to believe it's intractable. The original strategy
of putting the classname in the Key<?> won't work because there's no
way to go backwards - picture a keys-only query that must return
Key<?> objects, but doesn't have discriminator values from a fetched
Entity to determine what the correct POJO class is. We can't
regenerate the classname.

Soooo... what I'm going to do is provide super-source for Key<?> that
makes the constructors that take a Class<?> throw an
UnsupportedOperationException when called from GWT. You can't
construct a Key<?> in GWT, although you can pass them back and forth
through GWT-RPC. I considered removing the constructors entirely and
forcing Key<?> creation in a KeyFactory (similar to the low-level API)
but that feels like too much API change. Besides, I like "new
Key<Car>(Car.class, 123)" better than
"KeyFactory.<Car>create(Car.class, 123)".

Unless someone has a brilliant insight, this looks like a situation
where we have to make a decision "is Objectify a persistance framework
or a GWT framework?" and the answer must be that persistence comes
first.

Jeff

Jeff Schwartz

unread,
Mar 3, 2011, 6:37:26 AM3/3/11
to objectify...@googlegroups.com
Why can't you provide both a constructor for server side key creation and a static factory method that supports client side key creation so that Objectify can be used on both the client and on the server? Surely having the option of refactoring my GWT code to use a new factory method is far better than having to look for an alternative to Objectify.

Jeff Schwartz
--
Jeff Schwartz
http://jefftschwartz.appspot.com/
http://www.linkedin.com/in/jefftschwartz
follow me on twitter: @jefftschwartz

Jeff Schwartz

unread,
Mar 3, 2011, 6:40:33 AM3/3/11
to objectify...@googlegroups.com
Jeff, one more thing, what is the percentage of your user base who are using Objectify with GWT, do you have any idea?

Jeff Schwartz

Jeff Schwartz

unread,
Mar 3, 2011, 8:17:42 AM3/3/11
to objectify...@googlegroups.com
BTW I didn't mean to imply that I would dump Objectify because of this breaking change. I wouldn't but it would obviously require a _major_ refactoring of almost all my rpc calls. Wherever I now pass a key I'd have to pass an id and create the key on the server so I'd have to rewire both the client and the server to accommodate the change. I think if you provided a factory method as you described that would require a lot less rewiring as it would only impact the client side.

Jeff Schwartz

On Thu, Mar 3, 2011 at 6:37 AM, Jeff Schwartz <jeffts...@gmail.com> wrote:

George Moschovitis

unread,
Mar 3, 2011, 9:26:51 AM3/3/11
to objectify...@googlegroups.com

and the answer must be that persistence comes
first.

 I have to agree (even though I am a GWT user)

-g.

Jeff Schnitzer

unread,
Mar 3, 2011, 2:06:39 PM3/3/11
to objectify...@googlegroups.com
To distill the problem down to its barest essence, creating a Key<?>
now requires that you know the Kind (to construct the underlying
native Key). The only way you can know the Kind is to examine
annotations (@Subclass and @Entity(name="blah"). But annotations do
not exist in GWT - Class.getAnnotation() is not part of the JRE
emulation.

It is impossible to offer a client side mechanism that builds a Key<?>
from Class<?> - factories don't help.

However, all hope is not lost. Key<?> now has a constructor that
takes a native datastore Key. Even though Objectify can't figure out
what the Kind is for your classes, you can - if you aren't using
polymorphism, and you aren't using @Entity(name="SomethingElse"), you
can guess what the Kind will be. Furthermore, Key<?> is not a final
class - you can add your own constructor. Nothing stops you from
making a class like this:

public class GWTKey<T> extends Key<T> {
public GWTKey(Key<?> parent, Class<T> clazz, long id) {
// Note: Class<?>.getSimpleName() is not part of GWT's JRE emulation
String kind = clazz.getName().substring(clazz.lastIndexOf('.'));

// You must manage polymorphism yourself
if (kind.equals("Mammal"))
kind = "Animal";

this.raw = KeyFactory.createKey(parent == null ? null :
parent.getRaw(), kind, id);
}
}

Notice that it will be chock-full of application-specific business
logic. Ugly, but it will do the job.

One other thing worth mentioning - I hope you are thinking about the
potential hazards of generating keys client-side. Either you must
validate the key objects carefully or you are assuming that the client
is trustworthy - because anyone could create any Key<?> object and
pass it through your RPC boundary. This could conceivably be abused
to fetch invalid information or to store corrupt information in the
database. This might not be an issue for an internal app with a
trusted user base, but a public API is subject to attack.

Jeff

Jeff Schwartz

unread,
Mar 3, 2011, 2:51:28 PM3/3/11
to objectify...@googlegroups.com

Ugly is putting it mildly, seriously, & I wouldn't bother littering my client-side code with it. I'd rather bite the bullet and do a full scale refactoring job of the client and server to use RPC calls passing ids instead.

One other thing worth mentioning - I hope you are thinking about the
potential hazards of generating keys client-side.  Either you must
validate the key objects carefully or you are assuming that the client
is trustworthy - because anyone could create any Key<?> object and
pass it through your RPC boundary.  This could conceivably be abused
to fetch invalid information or to store corrupt information in the
database.  This might not be an issue for an internal app with a
trusted user base, but a public API is subject to attack.

This warning is a little over the top, Jeff, at least to me and here's why...

Trusting the user means that the user is authenticated and is authorized. A clever hacker, a site member, employing a subdomain high-jacking (replacing the real session id with their own valid session id) passes both tests because as a valid user they were able to obtain a valid session id which they then use to replace the real one. In this case and numerous other types of hijacking scenarios the user will always appear to be authenticated and authorized even though they are up to no good. Even sites sitting behind firewalls are subject to these types of attacks and many have been breached including Google.

So in the end the most any of us can really do is to follow best practices by using ssl where and when we can, validate session ids and validate the data but then there are no guarantees.

Jeff Schwartz

Jeff Schnitzer

unread,
Mar 3, 2011, 3:07:41 PM3/3/11
to objectify...@googlegroups.com
On Thu, Mar 3, 2011 at 11:51 AM, Jeff Schwartz <jeffts...@gmail.com> wrote:
>
> Ugly is putting it mildly, seriously, & I wouldn't bother littering my
> client-side code with it. I'd rather bite the bullet and do a full scale
> refactoring job of the client and server to use RPC calls passing ids
> instead.

Sorry. I wish there was a better way, but I can't think of one.

Actually, I just did. I'll bet it is possible to create a GWT
generator that creates and hides all that application-specific
business logic inside the generated Key<?> constructor. Unfortunately
my GWT-fu is not strong enough to actually do that right now, and I
don't have time to learn. Anyone else want to take a crack at it?

> This warning is a little over the top, Jeff, at least to me and here's
> why...
>
> Trusting the user means that the user is authenticated and is authorized. A
> clever hacker, a site member, employing a subdomain high-jacking (replacing
> the real session id with their own valid session id) passes both tests
> because as a valid user they were able to obtain a valid session id which
> they then use to replace the real one. In this case and numerous other types
> of hijacking scenarios the user will always appear to be authenticated and
> authorized even though they are up to no good. Even sites sitting behind
> firewalls are subject to these types of attacks and many have been breached
> including Google.

I wasn't considering subdomain hijacking. I was just thinking about
the level of data isolation that is usually required for public-facing
applications; user data must be segregated, and written data must be
protected against malicious injection. It sounds like your
application does not face the public so you can "trust" users not to
be malicious - that's great.

Jeff

Jeff Schwartz

unread,
Mar 3, 2011, 3:40:28 PM3/3/11
to objectify...@googlegroups.com
On Thu, Mar 3, 2011 at 3:07 PM, Jeff Schnitzer <je...@infohazard.org> wrote:
On Thu, Mar 3, 2011 at 11:51 AM, Jeff Schwartz <jeffts...@gmail.com> wrote:
>
> Ugly is putting it mildly, seriously, & I wouldn't bother littering my
> client-side code with it. I'd rather bite the bullet and do a full scale
> refactoring job of the client and server to use RPC calls passing ids
> instead.

Sorry.  I wish there was a better way, but I can't think of one.

Actually, I just did.  I'll bet it is possible to create a GWT
generator that creates and hides all that application-specific
business logic inside the generated Key<?> constructor.  Unfortunately
my GWT-fu is not strong enough to actually do that right now, and I
don't have time to learn.  Anyone else want to take a crack at it?

If I had the time, Jeff, I'd take a crack at it. But between looking for a ft job and developing my app there's little time left for the basics like eating and sleeping. Oh and taking a shower lol.
 
> This warning is a little over the top, Jeff, at least to me and here's
> why...
>
> Trusting the user means that the user is authenticated and is authorized. A
> clever hacker, a site member, employing a subdomain high-jacking (replacing
> the real session id with their own valid session id) passes both tests
> because as a valid user they were able to obtain a valid session id which
> they then use to replace the real one. In this case and numerous other types
> of hijacking scenarios the user will always appear to be authenticated and
> authorized even though they are up to no good. Even sites sitting behind
> firewalls are subject to these types of attacks and many have been breached
> including Google.

I wasn't considering subdomain hijacking.  I was just thinking about
the level of data isolation that is usually required for public-facing
applications; user data must be segregated, and written data must be
protected against malicious injection.  It sounds like your
application does not face the public so you can "trust" users not to
be malicious - that's great.

My app is public facing, Jeff, but it uses Google Accounts for authentication and my own datastore entities for authorization. I use innertext on the client most of the time and when I do use innerhtml it is safe. As for GQL injection, I'm using Objectify and its parameter binding methods for filtering on values when querying. So all in all I think I have taken all the steps I should take (except for perhaps using SSL) to segregate and validate user data.

I realize that you are probably as upset about this breaking change as I am and I appreciate that. I agree, persistence rules the day and I would never stand in the way of progress so I'll refactor my code when I cut over to the new version.

Thank you for your continued commitment and support of Objectify. It is a great product.

Jeff Schwartz
Jeff

Jon Stevens

unread,
Mar 3, 2011, 3:50:44 PM3/3/11
to objectify...@googlegroups.com
> Trusting the user means that the user is authenticated and is authorized. A
> clever hacker, a site member, employing a subdomain high-jacking (replacing
> the real session id with their own valid session id) passes both tests
> because as a valid user they were able to obtain a valid session id which
> they then use to replace the real one. In this case and numerous other types
> of hijacking scenarios the user will always appear to be authenticated and
> authorized even though they are up to no good. Even sites sitting behind
> firewalls are subject to these types of attacks and many have been breached
> including Google.

You are assuming that only authz'd people would be using a Key. There
is many usecases where that isn't necessary. Anonymous commenting
systems come to mind.

jon

Jeff Schwartz

unread,
Mar 3, 2011, 4:03:48 PM3/3/11
to objectify...@googlegroups.com

I wasn't assuming that at all. I was merely trying to show that even authenticated and authorized users aren't safe.

Jeff Schnitzer

unread,
Mar 3, 2011, 4:08:49 PM3/3/11
to objectify...@googlegroups.com
On Thu, Mar 3, 2011 at 12:40 PM, Jeff Schwartz <jeffts...@gmail.com> wrote:
>
> My app is public facing, Jeff, but it uses Google Accounts for
> authentication and my own datastore entities for authorization. I use
> innertext on the client most of the time and when I do use innerhtml it is
> safe. As for GQL injection, I'm using Objectify and its parameter binding
> methods for filtering on values when querying. So all in all I think I have
> taken all the steps I should take (except for perhaps using SSL) to
> segregate and validate user data.

Sorry, I guess I didn't make my attack scenario clear. Maybe this
affects your app, maybe not, but if you're creating Key<?> objects on
the client and passing them to the server, there are some attack
scenarios like:

* Say you have an RPC method getThing(Key<?>) that lets you define
what thing to grab. An authenticated, valid malicious user could call
this method making up their own Key<?>. They could request an id for
data that is associated with another user. In a polymorphic system,
they might be able to request access to other different kinds of
things without blowing up the typechecker.

* Say you have an RPC method write(MyEntity) that puts an entity in
the datastore. Say one of the member fields is a Key<?>. A malicious
user could write a MyEntity with a Key pointing to some odd part of
the database; now, when ever your app tries to load the entity pointed
at by that Key, it might throw ClassCastExceptions because it's
getting the wrong kind of data.

All I'm saying is that if you pass keys through untrusted RPC
boundaries, you need to be careful about validating them. You still
have this issue with ids, just less so. Don't trust clients, even if
they're authenticated.

> I realize that you are probably as upset about this breaking change as I am
> and I appreciate that. I agree, persistence rules the day and I would never
> stand in the way of progress so I'll refactor my code when I cut over to the
> new version.

Another option is to stay on Objectify 2.2.3 for a while. Unless you
need async get/put/delete or polymorphism, there's nothing wrong with
the old version. Who knows, I might get around to building that GWT
generator sometime in the next year.

Jeff

Jeff Schwartz

unread,
Mar 3, 2011, 4:26:47 PM3/3/11
to objectify...@googlegroups.com

All valid scenarios.

I think I just might hold off on upgrading for a while, at least until I actually need pollymorphims or sync.

Aswath Satrasala

unread,
Apr 24, 2011, 11:28:01 PM4/24/11
to objectify...@googlegroups.com
I really like the async api and currently I don't want to refactor my existing GWT functionality.I am not keen on Polymorphism feature. Hence, for now 3.0b1 will suffice for me.
However, a good migration path for the GWT Key<?> will be really desirable.

I don't like to continue on 3.0b1 for long time, as this will miss out the ofy nice api in future.
Can we have fork into Objectify plain and Ofy with Polymorphism.  Just an idea. 

Regards
-Aswath

Jeff Schnitzer

unread,
Apr 25, 2011, 1:29:19 AM4/25/11
to objectify...@googlegroups.com
While I will never object to anyone forking Objectify (and really wish
Google Code supported Git in the style of github so that anyone could
easily make forks and submit pull requests), I personally am not going
to maintain a fork.

Also, I wouldn't be so down on the polymorphism feature - it's
something that just eventually comes up in a schema. You don't care
about it until suddenly you need it.

Is your difficulty a question of persistent serialization of old keys,
or a question of creating Key<?>s in GWT client-side? If the later,
you can work around the issue by using the constructor that takes a
native Key. You just need to know how to construct that Key properly
- which really just means knowing what the Kind is called. Unless you
have some pretty magical code, the kind for class Thing is almost
always "Thing".

If the former - run two passes, one that converts Key<?> to native
datastore Key, then upgrade Ofy, then convert back to Key<?>. Or just
leave your data with native Keys. Or (if your keys don't have
parents) just use the simple Long/String. Serializing complex classes
to persistent storage is always just a little bit precarious for
exactly this reason. I don't expect Key<?> to change in a
serialization-incompatible way ever again, but I won't make any hard
promises.

Jeff

Brendan Doherty

unread,
May 21, 2011, 8:24:43 PM5/21/11
to objectify...@googlegroups.com
I could easily write a simple JSR-269 annotation processor similar to the query generator I wrote (http://code.google.com/p/objectify-query/) that would process objectify's @Entity annotations and generate an application specific GwtKey class like the class that Jeff described above. 

Let me know if anyone would be interested in this.

Jeff Schnitzer

unread,
May 21, 2011, 8:46:50 PM5/21/11
to objectify...@googlegroups.com
My gut sense is that the correct way to do this is to use GWT Generators:

http://blog.jdevelop.eu/2010/01/17/use-generators-to-create-boilerplate-code-in-gwt-20/

This would be used to create the client-side source for a class that
maps Class<?> to kind based on the annotations of all entities. The
generated could would just be:

if (clazz == Entity1.class)
return "Entity1";
else ...etc

Then the Key<?> super-source could use this to properly construct a
native datastore Key and wrap it.

Jeff

Philippe Beaudoin

unread,
May 24, 2011, 1:49:55 AM5/24/11
to objectify...@googlegroups.com
Had a quick discussion with Brendan today and came up with a potential solution based on GWT-generators that would not require runtime ifs. Here it is...

First, for each @Entity and @Subclass for which you want to create a key client-side define a key type inside the class:

@Entity
public class Animal {
    public class MyKey extends FlexKey<Animal> { }
    @Id Long id;
    String name;
}
        
@Subclass
public class Mammal extends Animal {
    public class MyKey extends FlexKey<Mammal> { }
    boolean longHair;
}
        
@Subclass
public class Cat extends Mammal {
    public class MyKey extends FlexKey<Cat> { }
    boolean hypoallergenic;
}

Where FlexKey is just a subclass of Key that can be created in two-steps (since GWT.create does not accept constructor parameters):

public class FlexKey<T> extends Key<T> {
  protected String kind;
  public FlexKey() { }
  public void create(Key<?> parent, long id) {

     this.raw = KeyFactory.createKey(parent == null ? null : parent.getRaw(), kind, id);
  }
}


Now, whenever you need a key to a Cat client-side you do something like:

Key<Cat> key = GWT.create(Cat.MyKey.class).create(null, id);

The generator then inspects Cat.MyKey to find the correct kind, going up the class hierarchy until an @Entity is found. It generates a class like:

public class Cat_MyKey_Generated extends Cat.MyKey {
  public Cat_MyKey_Generated() {
    this.kind = "Animal";
  }
}

No ifs, no complex inspection of the entire set of classes, and resilient in the face of change (to the extend Objectify polymorphism is ;)). The drawback is the extra empty nested key class per entity class, but it looks like it might be the only way given the limitations of GWT.create(). Hope this helps someone...

Cheers,

   Philippe

Brendan Doherty

unread,
May 26, 2011, 10:49:02 PM5/26/11
to objectify...@googlegroups.com
I've created an annotation processor that generates very simple factory classes that will create the key with the correct kind.  

Where previously in client or shared code you might have done...
Key<OnlineOrder> orderKey = new Key<OnlineOrder>(OnlineOrder.class, 123);
Key<OrderLine> lineKey = new Key<OrderLine>(orderKey, OrderLine.class, 456);

... use these lines instead.

Key<OnlineOrder> orderKey = OnlineOrderKeyFactory.createKey(123);
Key<OrderLine> lineKey = OrderLineKeyFactory(orderKey, 456);  
For more details, check out http://code.google.com/p/objectify-gwtkey/

You'll have to build it from source at the moment. I wont get a chance to publish it to maven for about a week.

I decided to go with an annotation processor over a GWT generator, as I needed a solution that allowed me to create Key classes in both client code and shared code.

Brendan

ps, Don't forget the client-server rule about never trust the client.  Just because your server received a Key object, it doesn't mean you can trust it.  But that would be the same if you were sending IDs instead of Keys.

Thomas Visser

unread,
May 27, 2011, 5:34:46 AM5/27/11
to objectify...@googlegroups.com
I think it is the best solution for most cases. However, I run into a problem when I want to create a key of an object that I don't know the concrete type of. I can solve that by doing some instanceof checks and then call the right factory, but I'd prefer if that instanceof logic is hidden inside a factory. Does this sound like a plausible use case and solution?

Jeff Schnitzer

unread,
May 27, 2011, 2:32:27 PM5/27/11
to objectify...@googlegroups.com
Unless I misunderstand GWT generators, I'm pretty sure that it could
be 100% transparent to the user. That is, on both the client and the
server you would construct a Key<?> like this:

new Key<Cat>(Cat.class, id);

...but on the server you would get the normal Key<?> constructor that
does Kind lookup via annotations, on the client you would get a
generated Key<?> constructor that does Kind lookup via "if (clazz ==
Mammal.class) ... else if ...".

This is just going to take some research.

Jeff

Brendan Doherty

unread,
May 28, 2011, 9:31:57 PM5/28/11
to objectify...@googlegroups.com
The way phillipe explained it to me is that gwt generators are triggered by gwt.create(). Because gwt.create() only takes the class as a parameter, you have to have a zero argument constructor on the actual class you are trying to create.

I wrote a gwt generator that worked on the example that phillipe previously posted, however you had to have that extra inner class, and it would only work on client code, not shared code.

Message has been deleted

Brendan Doherty

unread,
May 28, 2011, 9:38:15 PM5/28/11
to objectify...@googlegroups.com
I don't understand the problem you are describing. Can you explain it a bit more. Perhaps a code sample would help.

If you are saying you don't want to have to figure out the base entity that had been sub classed, you don't have to. The annotation processor automatically figures out the base kind of the subclass.

Thomas Visser

unread,
May 29, 2011, 11:54:25 AM5/29/11
to objectify...@googlegroups.com
I think this example explains it all: https://gist.github.com/997880. I don't see how this can be done using the solution above.  

Brendan Doherty

unread,
May 29, 2011, 6:43:53 PM5/29/11
to objectify...@googlegroups.com
What if Company and Person knew how to return their own keys?

interface HasReferences {
Key<? extends HasRefences> getKey();
// just an interface,
}

@Entity
public class Person implements HasReferences {
@Id private long id;
Key<? extends HasRefences> getKey() {
return PersonKeyFactory.createKey(this.id);
}
}

@Entity
public class Company implements HasReferences {
@Id private long id;
Key<? extends HasReferences> getKey()
return CompanyKeyFactory.createKey(this.id);
}
}

// somewhere in GWT:
List<HasReferences> hasReferences = getHasReferences();

for (HasReferences hr : hasReferences) {
Key<? extends HasReferences> k = hr.getKey();
}

Thomas Visser

unread,
May 31, 2011, 3:45:54 AM5/31/11
to objectify...@googlegroups.com
That's a good solution and actually how we had it implemented with objectify 2. I had hoped that through using factories, it would be possible to move the key creation to a centralized place but that is maybe too much asked.

However, until now I've had no luck with extending Brandons annotation processor to support String keys. Is it me or is debugging an annotation processor really hard?

Jeff Schnitzer

unread,
May 31, 2011, 12:44:35 PM5/31/11
to objectify...@googlegroups.com
The way I imagine this working:

Right now, Ofy's Key.java is separated between a server version and a
super-source version. This is why there is no Key(Class<?>, long)
constructor on the client.

The client version of Key.java could look like this:

public class Key<T> implements Serializable, Comparable<Key<?>> {
...
static ObjectifyClientKeyFactory keyFact =
GWT.create(ObjectifyCliebntKeyFactory.class);
...

public Key(Class<?> clazz, long id) {
String kind = keyFact.getKind(clazz);

// do the rest of the constructor now that we have the kind
}
}

Now the only trick is how to generate an ObjectifyClientKeyFactory
that looks something like this:

class ObjectifyClientKeyFactory {
static Map<Class<?>, String> kinds = new HashMap<Class<?>, String>();
static {
kinds.put(Thing.class, "Thing");
kinds.put(Animal.class, "Animal");
kinds.put(Mammal.class, "Animal");
kinds.put(Cat.class, "Animal");
}
}

The problem is that you now need the registration information within
the generator. This is somewhat tricky but doesn't seem like an
insurmountable problem... maybe even a good time to introduce
classpath scanning.

Jeff

Brendan Doherty

unread,
May 31, 2011, 5:40:29 PM5/31/11
to objectify...@googlegroups.com
I've pushed some changes to the way that the annotation processor searches for annotations, and added a lot of debugging output.  You should now see something like this when you build.  Hopefully this helps.

[INFO] diagnostic Note: com.googlecode.objectify.gwtkey.EntityProcessor started.
[INFO] diagnostic Note: Searching for @Entity annotations.
[INFO] diagnostic Note: Found com.example.shared.entity.Animal.
[INFO] diagnostic Note: Generating 'com.example.shared.entity.AnimalKeyFactory' from 'Animal'.
[INFO] diagnostic Note: Kind for 'Animal' is 'A'.
[INFO] diagnostic Note: Found com.example.shared.entity.Mineral.
[INFO] diagnostic Note: Generating 'com.example.shared.entity.MineralKeyFactory' from 'Mineral'.
[INFO] diagnostic Note: Kind for 'Mineral' is 'M'.
[INFO] diagnostic Note: Found com.example.shared.entity.Vegetable.
[INFO] diagnostic Note: Generating 'com.example.shared.entity.VegetableKeyFactory' from 'Vegetable'.
[INFO] diagnostic Note: Kind for 'Vegetable' is 'V'.
[INFO] diagnostic Note: Searching for @Subclass annotations.
[INFO] diagnostic Note: Found com.example.shared.entity.Cat.
[INFO] diagnostic Note: Generating 'com.example.shared.entity.CatKeyFactory' from 'Cat'.
[INFO] diagnostic Note: Kind for 'Cat' is 'A'.
[INFO] diagnostic Note: Found com.example.shared.entity.Tank.
[INFO] diagnostic Note: Generating 'com.example.shared.entity.TankKeyFactory' from 'Tank'.
[INFO] diagnostic Note: Kind for 'Tank' is 'M'.
[INFO] diagnostic Note: com.googlecode.objectify.gwtkey.EntityProcessor finished.

Jan-Hendrik Kuperus

unread,
Jun 15, 2011, 4:35:54 AM6/15/11
to objectify...@googlegroups.com
I noticed some behavior using these new Objectify 3 Key<?> objects with GWT that I first classified as odd. Some RPC calls that used to work pre-Objectify 3 were no longer working because they were unable to find the entity I was referring to. One of the RPC methods had this signature:

public <T extends HasLabels> SafeOperationResult<T> tagEntityWithLabel(Key<T> entityKey, LabelEntity label) throws AppSystemException;


The Key would be constructed client-side (we took care to rewrite that code to create and wrap native datastore Keys) and then it would be sent over the RPC layer. Some debugging revealed that the problem lies in our use of Datastore Namespaces. The problem lies in the fact that the GWT super-source of this raw Key has no notion of namespaces, but the server side Key does. So when it is passed over the RPC layer, it is deserialized with the default ("") namespace instead of the actual namespace active on the server side.


Is this something we could fix within Objectify, or is it something that should be handled at GWT?


For now I have resorted to creating more specific tag*WithLabel methods which simply take the object's ID and create the Key<?> server side. If anyone has any ideas as to how we could solve this I'd be very interested :)


--JH

Jeff Schnitzer

unread,
Jun 15, 2011, 5:29:27 AM6/15/11
to objectify...@googlegroups.com
Hmmm... interesting.  Looks like the appIdNamespace field needs to be serialized along with the other Key data.

One question though - how do you set the namespace client-side?  Or rather, how do you want to set it?  We could provide super-source for NamespaceManager.set() and use that value.

The way that native Keys interact with namespaces seems really awkward to me, especially when deserializing them.  But I think this will work.  More likely so tomorrow after I wake up.

Jeff

Jan-Hendrik Kuperus

unread,
Jun 15, 2011, 5:34:04 AM6/15/11
to objectify...@googlegroups.com
If we could simply use the NamespaceManager.set() method, that would certainly be preferable. Currently we don't set the namespace at all at the client side, since this was not an issue until now. (I'm guessing Objectify 2.x created the raw key server side which would then automatically get the correct namespace).

I volunteer to test any patches you would post for this problem :)

Cheers and good night

--JH

Jeff Schnitzer

unread,
Jun 15, 2011, 5:42:52 AM6/15/11
to objectify...@googlegroups.com
If you're setting the namespace in a filter around the GWT-RPC call, you should be fine.  Ofy 2.x used to perform the Key<?> -> Key mapping at the last possible second, so maybe you had some namespace-setting code that got a chance to execute.  Now the raw Key is constructed during GWT-RPC deserialization, which means namespace setting needs to happen before the servlet executes.  Of course, if you're setting the namespace depending on other RPC parameters, that won't work... but it doesn't look like you are.

It feels to me like Key/KeyFactory really should have a constructor that takes a namespace.  Dunno why that doesn't exist.  We can't really just add our own, but we can provide the NamespaceManager.set() method on the client which gives you the same effect just more awkward.  Hmmmm.

Ok closing laptop now.  Really.

Jeff

Jeff Schnitzer

unread,
Jun 17, 2011, 5:27:51 PM6/17/11
to objectify...@googlegroups.com
Was this solved with a filter?  If not, please create an issue in Ofy's issue tracker for "provide a way to set namespace in GWT client".

Jeff

Jan-Hendrik Kuperus

unread,
Jun 23, 2011, 3:02:55 AM6/23/11
to objectify...@googlegroups.com
We did solve the problem, not exactly by using a filter, but something alike. All our RPC services extend our own AbstractRpcService (which extends the GWT RemoteServiceServlet). In our abstract class, we override the processCall method to perform some additional ACL-checks *and* set the namespace.

However, in this method we used to set the namespace after calling super.processCall, which means the decoding of the request happened without a namespace. We swapped theses two operations and now the decoding works just fine. Good thing we don't need a client-side NamespaceManager.set() (that would also open up all sorts of vulnerabilities...)

So yeah, you can fix this easily with a filter if you don't override the RemoteServiceServlet. Thanks for the help :)

--JH

Aswath Satrasala

unread,
Jan 5, 2012, 7:59:03 AM1/5/12
to objectify...@googlegroups.com
Hi,
I am in the process of migrating my app to Objectify3.1. 

My application uses namespaces heavily.  I would like the GWT key to maintain the namespace during the RPC process.

I tried few things by modifying the Objectify 3.1. 
Please find attached patch file that contains the modified files, but, no luck. 

I have also created the issue in the tracker.

Please suggest

Thanks
-Aswath
www.AccountingGuru.in
namespace.patch

Aswath Satrasala

unread,
Jan 11, 2012, 6:50:16 AM1/11/12
to objectify...@googlegroups.com
There was a bug in my previous patch file.  Now, I am able to make progress on transmitting the namespace  new Key<?>.  I tested with 1-2 GWT modules in my application. 
Attached is the patch file.  Any improvements or suggestions are welcome.

If there is a need for you to create Key<?> on the client, following is the sample code
       
        NamespaceManager.set(namespace);  // you need to transmit namespace also to the client earlier during module load.
        Key<TaxCategory> keyTax = new Key<TaxCategory>(KeyFactory.createKey("TaxCategory", taxCategoryId));

-Aswath
www.AccountingGuru.in
Objectify31Namespace.patch

Nate Thompson

unread,
Oct 16, 2013, 5:39:57 PM10/16/13
to objectify...@googlegroups.com, je...@infohazard.org
I was able to handle creation of Refs on the client side by adding the following code to DeadRef_CustomFieldSerializer:

// if DeadRef created on client side populate key
if (key == null && value != null)
key = Key.create(value);

 Basically I allow the key to be null on the client side and populate it as I deserialize on the server side.  it works great on the web page I'm working on.  Is there something I'm missing?

Nate

On Thursday, March 3, 2011 1:51:47 AM UTC-7, Jeff Schnitzer wrote:
So... all is not well in GWT-land with the new Key<?>.  In short:  You
cannot create Key<?> objects client-side.  I don't see any way to work
around this issue.

The explanation:

In the past, a Key<?> contained the POJO entity className en lieu of
Kind.  This worked because there was a 1-to-1 mapping between class
names and datastore Kinds, and Objectify could map back and forth
just-in-time.

Polymorphism breaks this 1-to-1 relationship; all the classes in a
polymorphic hierarchy have the same Kind.  Thus the new Key<?>
actually wraps a datastore native Key... a much simpler and more
elegant solution.  But now think about this:

Key<Car> key = new Key<Car>(Car.class, 123);

...this means that the Key<?> constructor needs to know how to
construct a datastore Key from Car.class.  Thus it needs to know the
Kind of a Car... which might be Vehicle... and the only way to know
that is by examining the annotations of Car.class.

But GWT-land does not have annotations.  Class.getAnnotation() is not
part of the JRE emulation.

Basically, the polymorphism feature makes it impossible to construct
Key<?> in GWT code.  I have tried to think of ways around the problem,
but I'm starting to believe it's intractable.  The original strategy
of putting the classname in the Key<?> won't work because there's no
way to go backwards - picture a keys-only query that must return
Key<?> objects, but doesn't have discriminator values from a fetched
Entity to determine what the correct POJO class is.  We can't
regenerate the classname.

Soooo... what I'm going to do is provide super-source for Key<?> that
makes the constructors that take a Class<?> throw an
UnsupportedOperationException when called from GWT.  You can't
construct a Key<?> in GWT, although you can pass them back and forth
through GWT-RPC.  I considered removing the constructors entirely and
forcing Key<?> creation in a KeyFactory (similar to the low-level API)
but that feels like too much API change.  Besides, I like "new
Key<Car>(Car.class, 123)" better than
"KeyFactory.<Car>create(Car.class, 123)".

Unless someone has a brilliant insight, this looks like a situation
where we have to make a decision "is Objectify a persistance framework
or a GWT framework?" and the answer must be that persistence comes
first.

Jeff

Reply all
Reply to author
Forward
0 new messages