Understanding a JsonMappingException with Google Endpoint



我试图理解为什么我得到一些get调用错误,而不是其他与谷歌应用程序引擎实体。

@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",
  }
 ]
}
<<p> 不工作/strong>

但是如果我只得到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["")-> com.google.appengine.datanucleus.query.StreamingQueryResult [0] -> com.my.app.client.Client["评估])

如果我删除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应用引擎代码的好例子,除了文档中的简单例子。有人知道好的例子吗?

相关终端代码

/**
 *
 * 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:
看起来fetch类型现在使用最新版本的App Engine + Datanucleus可以正常工作。我还发现了一个非常有趣的行为:

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

最新更新