Google Cloud Endpoints客户端库生成重复实体

时间:2014-04-14 14:15:49

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

当我为我的终端生成客户端库时,我发现了一种奇怪的行为。

在我的appengine项目中,我有两个端点类来处理两个实体的操作:

实体组的GroupEndpoint

实体联系的ContactEndpoint

组实体有一个联系人列表,因为有时当调用GroupEndpoint的API方法时,我必须更新其联系人。

问题是当我生成客户端库时,Contact实体是在两个不同的命名空间中生成的(每个端点一个),这非常令人困惑,因为我最终得到了相同的类(完全相同)两次。 / p>

以下是一个例子:

Group.java

package backend;

import java.util.List;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable
public class Group {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent
    private List<Contact> contactList;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List<Contact> getContactList() {
        return contactList;
    }

    public void setContactList(List<Contact> contactList) {
        this.contactList = contactList;
    }
}

GroupEndpoint.java(示例的虚拟代码)

package backend;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.response.CollectionResponse;

import javax.annotation.Nullable;
import javax.inject.Named;

@Api(name = "groupendpoint")
public class GroupEndpoint {

    @ApiMethod(name = "listContact")
    public CollectionResponse<Group> listGroup(
            @Nullable @Named("cursor") String cursorString,
            @Nullable @Named("limit") Integer limit) {
        return null;
    }
}

Contact.java

package backend;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable
public class Contact {

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;
}

ContactEndpoint.java(示例的虚拟代码)

package backend;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import com.google.api.server.spi.response.CollectionResponse;

import javax.annotation.Nullable;
import javax.inject.Named;

@Api(name = "contactendpoint")
public class ContactEndpoint {

    @ApiMethod(name = "listContact")
    public CollectionResponse<Contact> listContact(
            @Nullable @Named("cursor") String cursorString,
            @Nullable @Named("limit") Integer limit) {
        return null;
    }
}

的build.gradle

// Currently, the appengine gradle plugin's appengine devappserver launch doesn't interact well with Intellij/AndroidStudio's
// Gradle integration.  As a temporary solution, please launch from the command line.
// ./gradlew modulename:appengineRun
// If you would like more information on the gradle-appengine-plugin please refer to the github page
// https://github.com/GoogleCloudPlatform/gradle-appengine-plugin

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.appengine:gradle-appengine-plugin:1.9.1'
    }
}

repositories {
    mavenCentral();
}

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'

sourceCompatibility = 1.7
targetCompatibility = 1.7

dependencies {
  appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.1'
  compile 'javax.servlet:servlet-api:2.5'
    compile 'com.google.appengine:appengine-endpoints:1.9.1'
    compile 'com.google.appengine:appengine-endpoints-deps:1.9.1'
    compile 'javax.servlet:servlet-api:2.5'
    compile 'org.datanucleus:datanucleus-core:3.2.13'
    compile 'org.datanucleus:datanucleus-api-jpa:3.2.3'
    compile 'javax.jdo:jdo-api:3.0.1'
    compile 'org.datanucleus:datanucleus-api-jdo:3.2.8'
    compile 'org.datanucleus:datanucleus-jdo-query:3.0.2'
    compile 'com.google.appengine.orm:datanucleus-appengine:2.1.2'
    compile 'org.apache.geronimo.specs:geronimo-jpa_2.0_spec:1.1'
    compile 'com.ganyo:gcm-server:1.0.2'
    compile 'net.sf.javaprinciples.persistence:persistence-api:4.0.0'
}

appengine {
  downloadSdk = true
  appcfg {
    oauth2 = true
  }
}

当我生成客户端库时,它会在我的构建目录中创建groupendpoint-v1-java.zip和contactendpoint-v1-java.zip。如果我提取这些文件,我会看到每个zip文件都有一个Contact类。

对于groupendpoint-v1-java.zip:

/*
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
/*
 * This code was generated by https://code.google.com/p/google-apis-client-generator/
 * (build: 2014-04-15 19:10:39 UTC)
 * on 2014-04-22 at 12:22:19 UTC 
 * Modify at your own risk.
 */

package com.appspot.myapplicationid.groupendpoint.model;

/**
 * Model definition for Contact.
 *
 * <p> This is the Java data model class that specifies how to parse/serialize into the JSON that is
 * transmitted over HTTP when working with the groupendpoint. For a detailed explanation see:
 * <a href="http://code.google.com/p/google-http-java-client/wiki/JSON">http://code.google.com/p/google-http-java-client/wiki/JSON</a>
 * </p>
 *
 * @author Google, Inc.
 */
@SuppressWarnings("javadoc")
public final class Contact extends com.google.api.client.json.GenericJson {

  @Override
  public Contact set(String fieldName, Object value) {
    return (Contact) super.set(fieldName, value);
  }

  @Override
  public Contact clone() {
    return (Contact) super.clone();
  }

}

对于contactendpoint-v1-java.zip:

/*
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
/*
 * This code was generated by https://code.google.com/p/google-apis-client-generator/
 * (build: 2014-04-15 19:10:39 UTC)
 * on 2014-04-22 at 12:22:21 UTC 
 * Modify at your own risk.
 */

package com.appspot.myapplicationid.contactendpoint.model;

/**
 * Model definition for Contact.
 *
 * <p> This is the Java data model class that specifies how to parse/serialize into the JSON that is
 * transmitted over HTTP when working with the contactendpoint. For a detailed explanation see:
 * <a href="http://code.google.com/p/google-http-java-client/wiki/JSON">http://code.google.com/p/google-http-java-client/wiki/JSON</a>
 * </p>
 *
 * @author Google, Inc.
 */
@SuppressWarnings("javadoc")
public final class Contact extends com.google.api.client.json.GenericJson {

  @Override
  public Contact set(String fieldName, Object value) {
    return (Contact) super.set(fieldName, value);
  }

  @Override
  public Contact clone() {
    return (Contact) super.clone();
  }

}

请注意,唯一的区别是它们属于不同的命名空间。当我使用客户端库时,这非常令人困惑。

我该如何避免这种行为?

感谢。

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题,我找到了解决这个问题的方法。它可能有一些优点和限制,但我会在这里介绍它们。

您拥有不同的模型(在客户端),因为它们位于不同的库中。例如,您的联系人列表将位于libcontactendpoint和另一个libgroupendpoint中,因为您的Contact类都在其中使用。

为了在客户端只有一个代表您的实体的类,您需要将它保留在一个端点(在Client项目中)。因此,一种方法是使用@Api注释。此注释用于所有端点类。因此,如果您的班级 GroupEndpoint 具有 @Api(name =“groupendpoint”),则会创建一个libgroupendpoint。如果要在同一端点中同时使用Contact和Group,而不需要重复,则端点类必须指向相同的API。 解决方案:

package backend;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.response.CollectionResponse;

import javax.annotation.Nullable;
import javax.inject.Named;

//Changing api name
@Api(name = "generalendpoint")
public class GroupEndpoint {

    @ApiMethod(name = "listContact")
    public CollectionResponse<Group> listGroup(
            @Nullable @Named("cursor") String cursorString,
            @Nullable @Named("limit") Integer limit) {
        return null;
    }
}

ContactEndpoint还有 generalendpoint (您可以使用任何名称相同的名称)。

package backend;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import com.google.api.server.spi.response.CollectionResponse;

import javax.annotation.Nullable;
import javax.inject.Named;

@Api(name = "generalendpoint")
public class ContactEndpoint {

    @ApiMethod(name = "listContact")
    public CollectionResponse<Contact> listContact(
            @Nullable @Named("cursor") String cursorString,
            @Nullable @Named("limit") Integer limit) {
        return null;
    }
}

现在,你不会有这个问题。但是,请记住现在,在客户端,而不是使用Groupendpoint或Contactendpoint来执行操作并调用这些端点方法,现在必须使用Generalenpoint。

缺点:

  1. 在生成云端点库之后,指向相同@Api的类的所有方法都将在同一个类中
  2. 指向相同@Api(但Java中的不同类)的类中的方法不能具有相同的名称@ApiMethod(name =“nameOfMethod”)
  3. 1不是那么重要,因为你不编辑你的库,只需调用方法。在您的应用引擎项目中的类中创建方法时,需要注意第二个。