Objectify with Cloud Endpoints
Asked Answered
I

4

16

I am using appengine cloud endpoints and objectify. I have previously deployed these endpoints before and now I am updating them and it is not working with Objectify. I have moved to a new machine and running latest appengine 1.8.6. Have tried putting objectify in the classpath and that did not work. I know this can work, what am I missing??

When running endpoints.sh:

Error: Parameterized type
   com.googlecode.objectify.Key<MyClass> not supported.

UPDATE: I went back to my old computer and ran endpoints.sh on same endpoint and it worked fine. Old machine has 1.8.3. I am using objectify 3.1.

UPDATE 2: Updated my old machine to 1.8.6 and get same error as other machine. Leaves 2 possibilities: 1) Endpoints no longer support objectify 3.1 or 2) Endpoints have a bug in most recent version

Most likely #1...I've been meaning to update to 4.0 anyways...

Interradial answered 31/10, 2013 at 13:7 Comment(0)
E
18

Because of the popularity of Objectify, a workaround was added in prior releases to support the Key type, until a more general solution was available. Because the new solution is available, the workaround has been removed. There are two ways you can now approach the issue with the property.

  1. Add an @ApiResourceProperty annotation that causes the key to be omitted from your object during serialization. Use this approach if you want a simple solution and don't need access to the key in your clients.
  2. Add an @ApiTransformer annotation that provides a compatible mechanism to serialize/deserialize the field. Use this approach if need access to the key (or a representation of it) in your clients. As this requires writing a transformer class, it is more work than the first option.
Eatable answered 31/10, 2013 at 21:8 Comment(10)
Hi Dan, unrelated, I've stumbled upon this question about limitations with Google Cloud Endpoints, I wonder whether they're still in place, an answer would be good #19786839Ragged
@Sti do you mean re-adding an explicit handler for Objectify Keys? I don't think so. The general solution solves both the Objectify case and any others.Eatable
Well, we need access to the object's ID in our iOS-endpoint. Your first solution completely ignores this field. As far as we can see, the second solution converts the entire object, not just "the field" as you say. Is there a way to convert only the Key property so the endpoint can access it?Handbook
Could you talk about the pros and cons of each of the two solutions?Claim
@Claim I've added a few sentences on that. PTALEatable
@DanHolevoet Thanks. Looks like I need option 2 since I am accessing Keys (User Ids) on the client.Claim
I implemented a transformer for the class that was throwing the error. I still get the same error. I am actually somewhat confused. Doesn't the class get serialized to JSON over the wire? What does providing another method of serialization do and how does it is supposed to solve the problem that the OP described? ThanksClaim
@Claim Yes, the class is serialized to JSON over the wire. The transformer assists in the JSON serialization process by describing a transformation for fields that are otherwise not serializable. In the case of Objectify keys, framework-specific knowledge is required to perform the serialization, which is why we had a workaround in place prior to the general solution. If you're having an issue with the behavior of your transformer, I think it's sufficiently different enough from this question to ask separately in a new topic.Eatable
Could you please post the code for the Transformer?Cot
@DanHolevoet This solution does not work. Transformers do not work with parameterized types, so unless you want to have Key, not Key<MyClass> in your objects, you're out of luck.Thibaut
W
6

I came up with the following solution for my project:

@Entity
public class Car {

    @Id Long id;

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    Key<Driver> driver;

    public Key<Driver> getDriver() {
        return driver;
    }

    public void setDriver(Key<Driver> driver) {
        this.driver = driver;
    }

    public Long getDriverId() {
        return driver == null ? null : driver.getId();
    }

    public void setDriverId(Long driverId) {
        driver = Key.create(Driver.class, driverId);
    }
}

@Entity
public class Driver {
    @Id Long id;
}

I know, it's a little bit boilerplate, but hey - it works and adds some handy shortcut methods.

Wilkens answered 27/9, 2014 at 10:38 Comment(1)
You can move @ApiResourceProperty to the field to save on some clutterEudiometer
P
0

At first, I did not understand the answer given by Flori, and how useful it really is. Because others may benefit, I will give a short explanation.

As explained earlier, you can use @ApiTransformer to define a transformer for your class. This would transform an unserializable field, like those of type Key<myClass> into something else, like a Long.

It turns out that when a class is processed by GCE, methods called get{fieldName} and set{FieldName} are automatically used to transform the field {fieldName}. I have not been able to find this anywhere in Google's documentation.

Here is how I use it for the Key{Machine} property in my Exercise class:

public class Exercise {
  @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
  public Key<Machine> machine;
  // ... more properties

  public Long getMachineId() {
    return this.machine.getId();
  }

  public void setMachineId(Long machineId) {
    this.machine = new Key<Machine>(Machine.class, machineId);
  }

  // ...
}
Pusan answered 23/8, 2015 at 16:28 Comment(0)
K
0

Others already mentioned how to approach this with @ApiResourceProperty and @ApiTransformer. But I do need the key available in client-side, and I don't wanna transform the whole entity for every one. I tried replacing the Objectify Key with com.google.appengine.api.datastore.Key, and it looks like it worked just fine as well in my case, since the problem here is mainly due to that endpoint does not support parameterized types.

Kat answered 10/3, 2016 at 5:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.