我试图理解为什么我得到一些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
的字段,所以如果您打算使用标记为惰性但未正确加载的字段,请注意异常。