5

我试图了解为什么我在某些 GET 调用中收到错误,而在其他 Google App Engine 实体中却没有。

班上

@Entity
public class Client {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key id;
    private String firstName;
    private String lastName;

    @Basic(fetch = FetchType.EAGER)
    @ElementCollection
    private List<Assessment> assessment;

    public List<Assessment> getAssessment() {
        return assessment;
    }

    public void setAssessment(List<Assessment> assessment) {
        this.assessment = assessment;
    }
}

作品

如果我使用list请求,它工作正常。

GET http://localhost:8888/_ah/api/clientendpoint/v1/client

结果如预期

{
 "items": [
  {
   "id": {
    "kind": "Client",
    "appId": "no_app_id",
    "id": "12",
    "complete": true
   },
   "firstName": "Jane",
   "lastName": "Doe"
  },
  {
   "id": {
    "kind": "Client",
    "appId": "no_app_id",
    "id": "13",
    "complete": true
   },
   "firstName": "Jon",
   "lastName": "Doe",
  }
 ]
}

不工作

但是如果我只得到 1 条记录,例如 select id 12,则会产生错误

GET http://localhost:8888/_ah/api/clientendpoint/v1/client/12

com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException:您刚刚尝试访问字段“assessment”,但在您分离对象时未分离此字段。要么不要访问此字段,要么在分离对象时将其分离。(通过引用链:com.google.api.server.spi.response.CollectionResponse[\"items\"]->com.google.appengine.datanucleus.query.StreamingQueryResult[0]->com.my.app.client .客户[\"评估\"])

如果我删除 get / set 方法,则有效

我感到困惑的是,如果我注释掉对象内部的setAssessment(...)andgetAssesment()方法Client,它工作正常。

@Entity
public class Client {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key id;
    private String firstName;
    private String lastName;

    @Basic(fetch = FetchType.EAGER)
    @ElementCollection
    private List<Assessment> assessment;

    //public List<Assessment> getAssessment() {
    //    return assessment;
    //}

    //public void setAssessment(List<Assessment> assessment) {
    //    this.assessment = assessment;
    //}
}

它工作正常

GET http://localhost:8888/_ah/api/clientendpoint/v1/client/12

结果

{
 "id": {
  "kind": "Client",
  "appId": "no_app_id",
  "id": "12",
  "complete": true
 },
 "firstName": "Jane",
 "lastName": "Doe"
}

我的问题是

  • 为什么当我注释掉 get/set 时它会起作用
  • 我该如何正确解决这个问题?
  • 除了文档中的简单示例之外,我在为 Java App Engine 代码找到好的代码示例时遇到了麻烦。有人知道任何好的例子吗?

相关端点代码

/**
 *
 * This method works fine
 *
 */
@SuppressWarnings({ "unchecked", "unused" })
@ApiMethod(name = "listClient")
public CollectionResponse<Client> listClient(
        @Nullable @Named("cursor") String cursorString,
        @Nullable @Named("limit") Integer limit) {

    EntityManager mgr = null;
    Cursor cursor = null;
    List<Client> execute = null;

    try {
        mgr = getEntityManager();
        Query query = mgr.createQuery("select from Client as Client");
        if (cursorString != null && cursorString != "") {
            cursor = Cursor.fromWebSafeString(cursorString);
            query.setHint(JPACursorHelper.CURSOR_HINT, cursor);
        }

        if (limit != null) {
            query.setFirstResult(0);
            query.setMaxResults(limit);
        }

        execute = (List<Client>) query.getResultList();
        cursor = JPACursorHelper.getCursor(execute);
        if (cursor != null)
            cursorString = cursor.toWebSafeString();

    } finally {
        mgr.close();
    }

    return CollectionResponse.<Client> builder().setItems(execute)
            .setNextPageToken(cursorString).build();
}

/**
 *
 * This method errors out
 *
 */
@ApiMethod(name = "getClient")
public Client getClient(@Named("id") Long id) {
    EntityManager mgr = getEntityManager();
    Client client = null;
    client = mgr.find(Client.class, id);
    mgr.close();
    return client;
}
4

1 回答 1

4

我遇到了同样的问题,这绝对是一个延迟加载的问题:

@ApiMethod(name = "getClient")
public Client getClient(@Named("id") Long id) {
    EntityManager mgr = getEntityManager();
    Client client = mgr.find(Client.class, id);
    if (client != null)
        client.getAssessment();  // Forces it to load your objects
    mgr.close();
    return client;
}

不幸的是,我找不到更清洁的方法来解决这个问题,所以如果您有更好的选择,请告诉我!最后一件事:我也很想知道为什么当 Kirk 注释掉 getter/setter 时它的行为会有所不同。

编辑 26/12/2013:
使用最新版本的 App Engine + Datanucleus 似乎获取类型现在可以正常工作。我还发现了一个非常有趣的行为:

  • 如果您使用TypedQuery<T>而不是Query,JPA 将尝试加载 T 的所有字段(它会忽略FetchType.LAZY),如果未手动加载这些字段,您将收到 JsonMappingException。
  • 如果您使用Query,JPA 将仅加载标记为 的字段FetchType.EAGER,因此如果您打算使用标记为惰性但未正确加载的字段,请注意异常。
于 2013-06-10T18:15:48.967 回答