Objectify后端和客户端之间的Key / Ref往返[没有GWT]

时间:2014-06-08 04:07:45

标签: java rest android-studio google-cloud-endpoints objectify

这里和整个网络上有很多文章,但这些文章都针对不同的Objectify版本,似乎不是出于其中一个原因。

我有一个实体,它引用另一个实体(例如,一个帐户实体引用一个用户实体):

@Cache
@Entity
public final class Account {

    @Id Long id;
    @Index private Ref<User> user;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public User getUser() {
        return user.get();
    }
    public void setUser(User user) {
        this.user = Ref.create(user);
    }

}

我正在尝试这样做:

  1. 从客户端,通过REST / Google Cloud Endpoints获取帐户实体。
  2. 修改资源。
  3. 在服务器上更新它。
  4. 如上所述Objectify loads object behind Ref<?> even when @Load is not specified代码总是返回引用的用户,我不想要。

    正如@svpino建议的那样,一个选项是“让你的@ApiMethod返回一个不同的Account对象而没有用户属性(因此如果你不需要它,就会避免提取用户)。”只要我不想更新资源,这就可以工作。如果我需要更新,则需要保留Key / Ref(即使我在客户端上不需要它)。

    我可以看到的一种可能方法是使用Key而不是Ref并呈现一个Web安全字符串,然后在UPDATE期间重新创建用户。

    private Key<User> user;
    
    public String getUser() {
        return user.toString();
    }
    public void setUser(String user) {
        this.user = Key.create(user);
    }
    

    字符串看起来像“Key(User(5723348596162560))”,但似乎没有重构(至少我在这里得到一个例外,还没有追踪它)。

    另一种方法是编写一个@ApiTransformer,它也没有解决问题。

    杰夫@StickFigure在过去几年中多次发布,问题似乎仍未解决。

    Objectify 5.0.2的当前状态是什么?当客户端不需要密钥时,在往返之间保留密钥的建议是什么?

3 个答案:

答案 0 :(得分:0)

您需要使用@ApiResourceProperty(ignored = AnnotationBoolean.TRUE)

注释要忽略的属性

Google文档说明了@ApiResourceProperty的以下内容:

  

@ApiResourceProperty提供了更多的资源控制   属性在API中公开。您可以在属性获取器上使用它   或者setter从API资源中省略该属性。你也可以使用   它在场上本身,如果该场是私人的,则在场上暴露它   API。您还可以使用此批注更改属性的名称   在API资源中。

我建议您访问此链接阅读更多内容 https://developers.google.com/appengine/docs/java/endpoints/annotations#apiresourceproperty

因此,在您的情况下,您的类在修改后应该如下所示。

@Cache
@Entity
public final class Account 
{
    @Id Long id;    
    @Index private Ref<User> user;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    public User getUser() {
        return user.get();
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    public void setUser(User user) {
        this.user = Ref.create(user);
    }
}

答案 1 :(得分:0)

以下代码将实体对象序列化为Web安全字符串,以便可以通过REST传输。当实体被发送回服务器时,Ref&lt;&gt;重组。这样,当对象到客户端进行往返时,服务器端引用不会丢失。这种方式引用的对象不会传输到客户端并返回,但可以&#34;工作&#34;作为Ref&lt;&gt;在客户端。

@Index private Ref<User> user;

// for serialization
public String getUser() {
    return user.getKey().getString(); // .toWebSafeString() will be added in future version of objectify and .toWebSafeString() will do the same as .getString()
}
public void setUser(String webSafeString) {
    Key<User> key = Key.create(webSafeString);
    this.user = Ref.create(key);
}

有两个单独的函数(我不承认,我承认)用于在服务器上加载实际对象以及首先创建引用:

// for load and create reference
public User loadUser() {
    return user.get();
}
public void referenceUser(User user) {
    this.user = Ref.create(user);
}

我希望这能为每个人解决问题。这还没有经过彻底的测试,所以仍然欢迎评论。

我已经运行了一项测试来比较使用Key&lt;&gt;和参考&lt;&gt;对我而言,即使使用Ref&lt;&gt;只有在调用loadEntity()/。get()时才重构实体。所以Ref&lt;&gt;如果可能更好,因为@Load注释将起作用。也许客观化的人可以证实这一点。

答案 2 :(得分:0)

您可以创建一个扩展Ref<User>的类,并使用@ApiTransformer在后端和客户端之间传输该类

@ApiTransformer(UserRefTransformer.class)
public class UserRef extends LiveRef<User>
{
}

public class UserRefTransformer implements Transformer<UserRef, User>
{
    // Your transformation code goes here
}