使用 Google App Engine,我为 Client
创建了一个端点类(class)。当我使用简单的 GET 语句访问它时,它出错了。即使我只插入了简单数据,也会发生这种情况。
我在最后放了一些类的框架代码。我猜我需要对 private List<Assessment> assessment
这行做一些花哨的注释在 Client
内类,但我不知道该怎么做。
有谁知道如何解决这个问题,如果可能的话,我想知道为什么这个错误与设置相关,因为评估字段中没有数据。
插入数据
{
"firstName" : "Jon",
"lastName" : "Doe"
}
插入后,我执行这个简单的语句来选择所有 firstName 和 lastName 字段。
GET http://localhost:8888/_ah/api/clientendpoint/v1/client?fields=items(firstName%2Cid%2ClastName)
这是我得到返回错误的地方
错误
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\"])
更新:我通过 Eclipse Google API 插件生成了端点。我把它放在最后,对应于 GET 语句。
我进一步追查了一下,可能只是我对返回对象的创建方式缺乏了解。
错误出现在
com.my.app.client.Client.jdoGetassessment(Client.java) com.my.app.client.Client.getAssessment(Client.java:247)
但是jdoGetAssessment()
我的代码中不存在,所以我猜这是在 Google App Engine 中生成的。 getAssessment()
由定义。
public List<Assessment> getAssessment() {
return assessment;
}
这似乎触发了错误消息,但我仍然不明白为什么在没有数据的情况下触发它。
客户端
@Entity
public class Client {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key id;
private String firstName;
private String lastName;
@ElementCollection
private List<Assessment> assessment;
public Key getId() {
return id;
}
public void setId(Key id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public List<Assessment> getAssessment() {
return assessment;
}
public void setAssessment(List<Assessment> assessment) {
this.assessment = assessment;
}
}
评估
@Embeddable
public class Assessment {
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
生成的ClientEndpoint.java
@Api(name = "clientendpoint", namespace = @ApiNamespace(ownerDomain = "myapp.com", ownerName = "myapp.com", packagePath = "mypackage.client"))
public class ClientEndpoint {
/**
* This method lists all the entities inserted in datastore.
* It uses HTTP GET method and paging support.
*`
* @return A CollectionResponse class containing the list of all entities
* persisted and a cursor to the next page.
*/
@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();
// Tight loop for fetching all entities from datastore and accomodate
// for lazy fetch.
for (Client obj : execute)
;
} finally {
mgr.close();
}
return CollectionResponse.<Client> builder().setItems(execute)
.setNextPageToken(cursorString).build();
}
/**
* This method gets the entity having primary key id. It uses HTTP GET method.
*
* @param id the primary key of the java bean.
* @return The entity with primary key id.
*/
@ApiMethod(name = "getClient")
public Client getClient(@Named("id") Long id) {
EntityManager mgr = getEntityManager();
Client client = null;
try {
client = mgr.find(Client.class, id);
} finally {
mgr.close();
}
return client;
}
/**
* This inserts a new entity into App Engine datastore. If the entity already
* exists in the datastore, an exception is thrown.
* It uses HTTP POST method.
*
* @param client the entity to be inserted.
* @return The inserted entity.
*/
@ApiMethod(name = "insertClient")
public Client insertClient(Client client) {
EntityManager mgr = getEntityManager();
try {
if (containsClient(client)) {
throw new EntityExistsException("Object already exists");
}
mgr.persist(client);
} finally {
mgr.close();
}
return client;
}
/**
* This method is used for updating an existing entity. If the entity does not
* exist in the datastore, an exception is thrown.
* It uses HTTP PUT method.
*
* @param client the entity to be updated.
* @return The updated entity.
*/
@ApiMethod(name = "updateClient")
public Client updateClient(Client client) {
EntityManager mgr = getEntityManager();
try {
if (!containsClient(client)) {
throw new EntityNotFoundException("Object does not exist");
}
mgr.persist(client);
} finally {
mgr.close();
}
return client;
}
/**
* This method removes the entity with primary key id.
* It uses HTTP DELETE method.
*
* @param id the primary key of the entity to be deleted.
* @return The deleted entity.
*/
@ApiMethod(name = "removeClient")
public Client removeClient(@Named("id") Long id) {
EntityManager mgr = getEntityManager();
Client client = null;
try {
client = mgr.find(Client.class, id);
mgr.remove(client);
} finally {
mgr.close();
}
return client;
}
private boolean containsClient(Client client) {
if (client.getId() == null)
return false;
EntityManager mgr = getEntityManager();
boolean contains = true;
try {
Client item = mgr.find(Client.class, client.getId());
if (item == null) {
contains = false;
}
} finally {
mgr.close();
}
return contains;
}
private static EntityManager getEntityManager() {
return EMF.get().createEntityManager();
}
}
最佳答案
问题很可能是 JDO 延迟加载 — 您正在请求对象,而 JDO 不会获取它们的属性,直到您尝试使用它们,此时与数据存储的连接已经消失。您可以在自动生成的示例中看到一个代码示例来阻止延迟加载:
// Tight loop for fetching all entities from datastore and accomodate
// for lazy fetch.
for (Client obj : execute)
;
这会在返回之前加载列表中的所有 Client
对象。但是,Client
上的 List
属性也是延迟加载的,因此您需要为每个 Client
对象的 评估重复此过程
属性。
编辑:删除了使用 FetchType.EAGER
的建议,因为它在 App Engine 上不起作用。
关于java - 端点 GET 语句出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16827643/