Failed to contact Google Datastore with Android app in Android Studio

I am trying to create an Android application that interacts with the Google App Engine to download and save objects in google storage. I think I have the correct setup, but I don’t know if I can download my application to check it, it just freezes forever and then gives me this error:

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

However, if I change the version number, a new version will appear in my console online even after receiving this message. I read all the google documentation in Datastore and couldn't figure out what was wrong. I had this problem for a month and could not find a solution. I read somewhere that if the application contains an error, it will not load, so I will include all my code. I also don’t know what I’m doing, I’m not even sure that I am on the right path, why this does not work, so if you noticed something stupid, please tell me. Thank you in advance, you will become my hero and my god, if you can fix it for me.

Here is my end point:

 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; } } 

Here is my custom object:

 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} 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} 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} last name to */ public void setLastName(String lastName){ this.lastName = lastName; } @ApiResourceProperty(ignored = AnnotationBoolean.TRUE) /** * Adds a friend to the {@code User} list of friends * * @param user User to add */ public void addFriendRef(User user){ friendRefs.add(Ref.create(user)); } /** * Returns the {@code User} 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} 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} 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} 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} status to a given {@code String} * * @param status {@code String} to set an {@code Users} status to */ public void setStatus(String status){ this.status = status; } /** * Returns the {@code User} status as a {@code String} * * @return {@code String} status */ public String getStatus(){ return status; } /** * Returns the {@code User} location as a {@code String} * * @return {@code String} location */ public String getLocation(){ return location; } /** * Sets the {@code User} location to a given {@code String} * * @param location {@code String} to set an {@code Users} location to */ public void setLocation(String location){ this.location = location; } @ApiResourceProperty(ignored = AnnotationBoolean.TRUE) /** * Adds a repeating {@code Event} to the {@code User} schedule * * @param event {@code Event} to add to the {@code User} schedule */ public void addRepeatingEvent(Event event){ repeatingEventRefs.add(Ref.create(event)); } @ApiResourceProperty(ignored = AnnotationBoolean.TRUE) /** * Adds a non repeating {@code Event} to the user schedule * * @param event Event to add to the the user schedule */ public void addNonRepeatingEvent(Event event){ nonRepeatingEventRefs.add(Ref.create(event)); } /** * Returns a {@code List<Event>} of repeating {@code Event}s from the user schedule * * @return List<Event> repeatingEvents from user schedule */ public List<Event> getRepeatingEvents(){ return repeatingEvents; } /** * Returns a list of nonRepeatingEvents from the user schedule * * @return List<Event> repeatingEvents from user schedule */ public List<Event> getNonRepeatingEvents(){ return nonRepeatingEvents; } } 

and my Event object:

 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}; } } 

and my 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(); } } 

Here is my appengine-web.xml, I replaced my my_id application for obvious reasons:

 <?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> 

Here is my 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> 

Finally, here is the AsyncTask that I use to communicate with the data store from my Android application, I again replaced my application identifier my_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(); } } 
+5
source share
1 answer

This helps to take a look at the full error message, which advises:

See your deployment troubleshooting documentation for more information: https://developers.google.com/appengine/docs/java/endpoints/test_deploy#troubleshooting_a_deployment_failure

The docs advise checking your logs for " / _ ah / spi / BackendService.getApiConfigs " as a first step. If I try to expand the Endpoints continent based on the sample, I see the following in my journals:

 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) ... 

This error only occurs when calling ObjectifyService.register(class) , hmm ...

Something in your User class that will cause infinite recursion when Objectify tries to register the class and raises a StackOverflowError:

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

Instead of defining the list itself, you can fix this by specifying the Ref<User> list, as done elsewhere in the class (it may have been a typo):

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

In addition, another problem is caused by the fact that the Event class is missing @Id, which can be fixed this way:

 @Entity public class Event { @Id private Long id; ... 

After making these changes, I can deploy the Endpoints application without any errors.

+2
source

All Articles