java - 使用 Google Endpoint 了解 JsonMappingException

标签 java google-app-engine rest google-cloud-storage google-cloud-endpoints

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

类(class)

@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: You have just attempted to access field \"assessment\" yet this field was not detached when you detached the object. Either dont access this field, or detach it when detaching the object. (through reference chain: com.google.api.server.spi.response.CollectionResponse[\"items\"]->com.google.appengine.datanucleus.query.StreamingQueryResult[0]->com.my.app.client.Client[\"assessment\"])

如果我删除 get/set 方法就可以工作

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

@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;
}

最佳答案

我遇到了同样的问题,肯定是懒加载的问题:

@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 的字段,因此如果您打算使用标记为惰性但未正确加载的字段,请注意异常情况。

关于java - 使用 Google Endpoint 了解 JsonMappingException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16975899/

相关文章:

security - 谷歌应用引擎 : Is it safe to reveal a user's user_id publicly

rest - 交付和使用 Azure REST-API SharedKey 进行 Blob 上传

java - 如何使用stripe-java或rest api获取产品的计划

java - 嵌套对象空值检查

Java NoClassDefFoundError 与 Ant

Java Swing : Error when dynamically adding JScrollpane to JPanel

java - 使用 Google App Engine 作为 Android 应用程序后端的示例

java - 什么等同于 Java World 中的 PHP Zend Framework

python - Google App Engine/Python - 更改日志格式

json - 如何在 Swift 中将给定的字典转换为包含 JSON 数组的 JSON 对象?