无法在Android Studio中将Google Datastore与Android应用程序进行通信

5

我正在尝试创建一个与Google App Engine交互以在google datastore中加载和保存实体的Android应用程序。 我认为我的配置是正确的,但我不知道是否可以上传我的应用程序进行测试。 它一直无响应,然后给我这个错误:

SEVERE: Endpoints configuration not updated.  The app returned an error when the Google Cloud Endpoints server attempted to communicate with it.

然而,如果我更改版本号,则新版本即使收到此消息后也会出现在我的在线控制台中。我已经阅读了Google关于Datastore的所有文档,但无法找出问题所在。我遇到这个问题已经一个月了,一直没有找到解决办法。我在某个地方读到,如果应用程序包含错误,则不会上传,因此我将包含所有代码。我也不知道我在做什么,甚至不确定我是否在正确的轨道上工作,所以如果您注意到任何愚蠢的事情,请告诉我。非常感谢您提前的帮助,如果您能为我修复这个问题,您将是我的英雄和上帝。

这是我的端点:

package com.polo.backend.endpoints;

/**
* Created by sagesmith on 4/16/16.
*
* Is used to interact with the server
*/

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.ConflictException;
import com.google.api.server.spi.response.NotFoundException;

import com.googlecode.objectify.Ref; 

import com.polo.backend.services.ObjcfyService;
import com.polo.backend.entities.Event;
import com.polo.backend.entities.User;

import java.util.List;

import javax.inject.Named;

 /**
  *
  */
  @Api(
    name = "userEndpoint",
    version = "v1",
    namespace = @ApiNamespace(
            ownerDomain = "backend.polo.com",
            ownerName = "backend.polo.com",
            packagePath = ""
    )
)
public class UserEndpoint {
    /**
     * Registers the two entities used in this class
     */
     public UserEndpoint(){
        ObjcfyService.register(User.class);
        ObjcfyService.register(Event.class);
     }

     @ApiMethod(name = "insertUser")
     /**
      * Inserts a new {@code User} into the data store
      */
     public void insertUser(User user) throws ConflictException, NotFoundException{
         if(getUser(user.getUsername()) != null){
             throw new ConflictException("Object already exists");
         }
     }

     /**
      *
      * @param user
      * @throws NotFoundException
      */
      @ApiMethod(name = "updateUser")
      public void updateUser(User user) throws NotFoundException{
          if(getUser(user.getUsername()) != null) {
              ObjcfyService.objectify().save().entity(user).now();
          }
      }

      /**
       *
       * @param username
       * @throws NotFoundException
       */
       @ApiMethod(name = "removeUser")
       public void removeUser(@Named("username") String username) throws NotFoundException{
           User record = getUser(username);
           if(record != null){
               ObjcfyService.objectify().delete().entity(record).now();
           }

       }

       /**
        *
        * @param username
        * @return
        * @throws NotFoundException
        */
        @ApiMethod(name = "getUser")
        public User getUser(@Named("username") String username) throws NotFoundException{
            User user = ObjcfyService.objectify().load().type(User.class).id(username).now();
            if(user != null) {
                List<Ref<User>> friendRefs = user.getFriendRefs();
                List<Ref<Event>> repeatingEventRefs = user.getRepeatingEventRefs();
                List<Ref<Event>> nonRepeatingEventRefs = user.getNonRepeatingEventRefs();

                for (Ref<User> friendRef : friendRefs) {
                    user.addFriend(friendRef.get());
                }

                for (Ref<Event> repeatingEventRef : repeatingEventRefs) {
                    user.addRepeatingEvent(repeatingEventRef.get());
                }

                for (Ref<Event> nonRepeatingEventRef : nonRepeatingEventRefs) {
                    user.addNonRepeatingEvent(nonRepeatingEventRef.get());
                }
            } else{
                throw new NotFoundException("User not found");
        }

        return user;
    }
}

这是我的用户实体:

package com.polo.backend.entities;

/**
 * Created by sagesmith on 4/16/16.
 */

import com.google.api.server.spi.config.AnnotationBoolean;
import com.google.api.server.spi.config.ApiResourceProperty;
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.annotation.Load;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nullable;

@Entity
public class User {
    @Id private String username = null;
    @Index private String firstName = null;
    @Index private String lastName = null;
    @Nullable private String status = null;
    @Nullable private String location = null;
    @Load @Nullable private List<Ref<User>> friendRefs = new ArrayList<>();
    @Load @Nullable private List<Ref<Event>> nonRepeatingEventRefs = new ArrayList<>();
    @Load @Nullable private List<Ref<Event>> repeatingEventRefs = new ArrayList<>();
    @Nullable public List<User> friends = new ArrayList<>();
    @Nullable public List<Event> nonRepeatingEvents = new ArrayList<>();
    @Nullable public List<Event> repeatingEvents = new ArrayList<>();

    /**
     *Returns the first name from the {@code User}
     *
     * @return the first name of the {@code User} as a {@code String}
     */
    public String getFirstName(){
        return firstName;
    }

    /**
     * Returns the last name from the {@code User}
     *
     * @return the last name of the {@code User} as a {@code String}
     */
    public String getLastName(){
        return lastName;
    }

    /**
     * Return the username from the user
     *
     * @return the username of the user as a String
     */
    public String getUsername(){
        return username;
    }

    /**
     * Sets the username of the {@code User}
     *
     * @param username Username to set the {@code User}'s username to
     */
    public void setUsername(String username){
        this.username = username;
    }

    /**
     * Sets the firstName of the {@code User}
     *
     * @param firstName First name to set the {@code User}'s first name to
     */
    public void setFirstName(String firstName){
        this.firstName = firstName;
    }

    /**
     * Sets the lastName of the {@code User}
     *
     * @param lastName Last name to set the {@code User}'s last name to
     */
    public void setLastName(String lastName){
       this.lastName = lastName;
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    /**
     * Adds  a friend to the {@code User}'s list of friends
     *
     * @param user User to add
     */
    public void addFriendRef(User user){
        friendRefs.add(Ref.create(user));
    }

    /**
     * Returns the {@code User}'s friends
     *
     * @return {@code List<Users>} the friends of the {@code User}
     */
    public List<User> getFriends(){
        return friends;
    }

    /**
     * Adds a friend to the users {@code List} of friends
     *
     * @param user {@code User} to add as a friend
     */
    public void addFriend(User user){
        friends.add(user);
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    /**
     * Returns a {@code List<Ref<User>>} of references to the {@code User}'s friends
     *
     * @return {@code List<Ref<User>>}
     */
    public List<Ref<User>> getFriendRefs(){
        return friendRefs;
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    /**
     * Returns a {@code List<Ref<Event>>} of references to the {@code User}'s repeating
     * {@code Event}s
     *
     * @return {@code List<Ref<Event>>}
     */
    public List<Ref<Event>> getRepeatingEventRefs(){
        return repeatingEventRefs;
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    /**
     * Returns a {@code List<Ref<Event>>} of references to the {@code User}'s non repeating
     * {@code Event}s
     *
     * @return {@code List<Ref<Event>>}
     */
    public List<Ref<Event>> getNonRepeatingEventRefs(){
        return nonRepeatingEventRefs;
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    /**
     * Sets the {@code User}'s status to a given {@code String}
     *
     * @param status {@code String} to set an {@code Users}'s status to
     */
    public void setStatus(String status){
        this.status = status;
    }

    /**
     * Returns the {@code User}'s status as a {@code String}
     *
     * @return {@code String} status
     */
    public String getStatus(){
        return status;
    }

    /**
     * Returns the {@code User}'s location as a {@code String}
     *
     * @return {@code String} location
     */
    public String getLocation(){
        return location;
    }

    /**
     * Sets the {@code User}'s location to a given {@code String}
     *
     * @param location {@code String} to set an {@code Users}'s location to
     */
    public void setLocation(String location){
        this.location = location;
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    /**
     * Adds a repeating {@code Event} to the {@code User}'s schedule
     *
     * @param event {@code Event} to add to the {@code User}'s schedule
     */
    public void addRepeatingEvent(Event event){
        repeatingEventRefs.add(Ref.create(event));
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
    /**
     * Adds a non repeating {@code Event} to the user's schedule
     *
     * @param event Event to add to the the user's schedule
     */
    public void addNonRepeatingEvent(Event event){
        nonRepeatingEventRefs.add(Ref.create(event));
    }

    /**
     * Returns a {@code List<Event>} of repeating {@code Event}s from the user's schedule
     *
     * @return List<Event> repeatingEvents from user's schedule
     */
    public List<Event> getRepeatingEvents(){
        return repeatingEvents;
    }

    /**
     * Returns a list of nonRepeatingEvents from the user's schedule
     *
     * @return List<Event> repeatingEvents from user's schedule
     */
    public List<Event> getNonRepeatingEvents(){
        return nonRepeatingEvents;
    }
}

以及我的事件实体:

package com.polo.backend.entities;

import com.googlecode.objectify.annotation.Entity;
/**
 * Created by sagesmith on 5/3/16.
 */
@Entity
public class Event {
    private Integer startIndex;
    private Integer endIndex;
    private Byte[] color;

    public Event(Integer startIndex, Integer endIndex, Byte red, Byte green, Byte blue){
        this.startIndex = startIndex;
        this.endIndex = endIndex;
        color = new Byte[]{red, green, blue};
    }
}

我的ObjectifyService:

package com.polo.backend.services;

/**
 * Created by sagesmith on 4/16/16.
 */
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;

public class ObjcfyService {
    public static void register(Class<?> eClass){
        ObjectifyService.register(eClass);
    }

    public static Objectify objectify(){
        return ObjectifyService.ofy();
    }

    public static ObjectifyFactory objectifyFactory(){
        return ObjectifyService.factory();
    }
}

这是我的appengine-web.xml文件,我已经用my_id替换了我的appid,出于明显的原因:

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>my_id</application>
    <version>1</version>
    <threadsafe>true</threadsafe>

    <system-properties>
    <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
</system-properties>

这是我的web.xml文件。
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <servlet>
        <servlet-name>SystemServiceServlet</servlet-name>
        <servlet-class>com.google.api.server.spi.SystemServiceServlet</servlet-class>
        <init-param>
            <param-name>services</param-name>
            <param-value>com.polo.backend.endpoints.UserEndpoint</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>SystemServiceServlet</servlet-name>
        <url-pattern>/_ah/spi/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

这是我在Android应用程序中使用的与数据存储通信的AsyncTask,我再次用my_id替换了我的应用程序ID:

package com.polo.client;

import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.extensions.android.json.AndroidJsonFactory;

import com.polo.StaticAssets;
import com.polo.activity.Home;
import com.polo.backend.userEndpoint.UserEndpoint;
import com.polo.backend.userEndpoint.model.User;

import java.io.IOException;
/**
 * Created by sagesmith on 4/17/16.
 */
public class UserAsyncTask extends AsyncTask<Void, Void, User>{
    private static UserEndpoint userApiService = null;
    private Home context;
    private String username;

    /**
     *
     * @param context
     */
    public UserAsyncTask(Home context){
        this.context = context;
        username = StaticAssets.getUserName(context);
    }

    /**
     *
     * @param params
     * @return
     */
    @Override
    protected User doInBackground(Void... params){
        if(userApiService == null){
            UserEndpoint.Builder builder = new UserEndpoint.Builder(
                AndroidHttp.newCompatibleTransport(),
                new AndroidJsonFactory(),
                null
            )
            .setRootUrl("https://my_id.appspot.com/_ah/api/");

            userApiService = builder.build();
        }

        User user = null;

        try{
            user = userApiService.getUser(username).execute();
        } catch (IOException e){
            Log.e("User not found", e.getMessage());
        }

        return user;
    }

    /**
     *
     * @param result
     */
    @Override
    protected void onPostExecute(User result) {
        if(result!=null)
            Toast.makeText(context, result.getFirstName(), Toast.LENGTH_LONG).show();
    }
}

我问了一位同事,他认为这与Java中的app.yaml等效物有关。 - Sage Smith
1个回答

2

建议查看完整错误信息,其中建议:

有关更多信息,请参见部署故障排除文档: https://developers.google.com/appengine/docs/java/endpoints/test_deploy#troubleshooting_a_deployment_failure

文档建议首先检查日志中的 '/_ah/spi/BackendService.getApiConfigs'。如果我尝试根据示例部署端点后端,则可以在我的日志中看到以下内容:

javax.servlet.ServletContext log: unavailable
java.lang.reflect.InvocationTargetException
    at com.google.appengine.runtime.Request.process-b693af604777a85a(Request.java)
    ...
Caused by: java.lang.StackOverflowError
    ...
    com.googlecode.objectify.impl.translate.ClassTranslatorFactory.create(ClassTranslatorFactory.java:49)
    ...

这个错误只会在调用ObjectifyService.register(class)时发生,嗯...

你的User类中有些东西会导致无限递归,当Objectify尝试注册该类时会导致StackOverflowError:

@Nullable public List<User> friends = new ArrayList<>();

不需要再定义一个列表本身,可以通过在类中的其他位置定义一个Ref<User>列表来解决这个问题(也许上面是个笔误):

@Nullable public List<Ref<User>> friends = new ArrayList<>();

此外,另一个问题是由于 Event 类缺少 @Id 而引起的,可以通过以下方式修复:
@Entity
public class Event {
  @Id private Long id;
  ...

在进行这些更改后,我可以无错误地部署Endpoints应用程序。


是的,这就是我的问题@Entity public class Person { @Id Long id; Ref<Person> referredBy; // was just Person referredBy; }感谢您的帖子 - Marc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接