java - 端点 GET 语句出现问题

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

使用 Google App Engine,我为 Client 创建了一个端点类(class)。当我使用简单的 GET 语句访问它时,它出错了。即使我只插入了简单数据,也会发生这种情况。

我在最后放了一些类的框架代码。我猜我需要对 private List<Assessment> assessment 这行做一些花哨的注释在 Client 内类,但我不知道该怎么做。

有谁知道如何解决这个问题,如果可能的话,我想知道为什么这个错误与设置相关,因为评估字段中没有数据。

插入数据

{
  "firstName" : "Jon",
  "lastName" : "Doe"
}

插入后,我执行这个简单的语句来选择所有 firstNamelastName 字段。

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/

相关文章:

java - java hibernate 中的Google Cloud sql数据库连接错误

python - 在 Google App Engine 上部署 Flask 应用程序时出现问题

Django Rest Framework - 单元测试图像文件上传

javascript - 意外字符 ('A'(代码 65)): was expecting a colon to separate field name and value\n

java - Android Studio 中的 Admob 插页式广告不起作用

java - JTable标题焦点查询?

java - 出现异常时重试 spring 集成 IntegrationFlow

java - 整个 Xss(堆栈空间)是否用于每个 Java 线程?

java - 未调用 Servlet 过滤器

Python,需要长整型值