使用Google Endpoint了解JsonMappingException

时间:2013-06-07 03:43:41

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

我试图理解为什么我会收到一些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:   您刚刚尝试访问此字段的字段“评估”   分离对象时没有分离。要不要访问它   字段,或在分离对象时分离它。 (通过参考   链:   com.google.api.server.spi.response.CollectionResponse [\ “项目\”] - &GT; com.google.appengine.datanucleus.query.StreamingQueryResult [0] - &GT; com.my.app.client.Client [ \ “评估\”])

如果我删除了get / set方法

,则有效

我感到困惑的是,如果我在setAssessment(...)对象中注释掉getAssesment()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;
}

1 个答案:

答案 0 :(得分: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评论出吸气剂/制定者时它的表现会有所不同。

编辑26/12/2013:
看起来fetch类型现在正在使用最新版本的App Engine + Datanucleus正常工作。我还发现了一个非常有趣的行为:

  • 如果您使用TypedQuery<T>而不是Query,JPA将尝试加载所有T的字段(它忽略FetchType.LAZY),如果这些字段不是,您将获得JsonMappingException手动加载。
  • 如果您使用Query,则JPA只会加载标记为FetchType.EAGER的字段,因此如果您打算使用标记为延迟但未正确加载的字段,请注意异常。< / LI>