Google Cloud Endpoints Tutorial – Part 2

Welcome to Part 2 of the Google Cloud Endpoints Tutorial.

The full series:

  • Part 1 : We looked at writing a Google Cloud Endpoints class manually by using the various annotations and Exception classes that are available. We create a Quotes API that provided a JSON + REST based interface to manage Quotes (add, modify, delete and retrieve quotes).
  • Part 2 : We generated the Google Cloud Endpoints class from a JDO Annotated Entity class by using the Code Generation tools provided in the library.
  • Part 3 : Generated the Cloud Endpoints Client Library for Android and wrote an Android application that invokes the Endpoints API.
  • Part 4: We wrote a JavaScript client for our Endpoints API.
  • Part 5: Securing our API
  • Part 6: Calling a Secured API from a JavaScript client.
  • Part 7 : Calling a Secured API from an Android client.

I have also published a list of Cloud Endpoints Tips:

  1. Check Endpoint Deployment Status
  2. Throw the Right Exception Classes
  3. Understand Injected Types
  4. Understand @API and @APIMethod Annotations
  5. Using Cursor and Limit parameters
  6. The @APIResourceProperty Annotation

In this episode

In this part of the series, the end goal for us is the same i.e. to generate the Quotes API. However, we shall let the Cloud Endpoints classes do the magic for us by helping us generate the API Endpoint class, instead of us writing it by hand.

What do you need ?

  • Basic understanding of Java Web Development, which includes Servlets, JSP, WAR file structure, etc.
  • You have a working development environment for Google App Engine. This includes the Google Eclipse plugin.
  • You do not need to be an expert at JDO or JPA. We shall be using some JDO annotations for our Entity class to allow it to declare itself as being available for persistence and what attributes of the class is a key and should be persisted. Just follow the tutorial along the way and you will be just fine.

My Development Environment

This remains the same, no changes at all. My development environment is given below:

  • Eclipse Juno
  • Google Eclipse plugin with App Engine SDK 1.8.7
  • Mac machine (but Windows will do too!)

Attention-> Cloud Endpoints became GA (General Availability) in Release 1.8.7 of the App Engine SDK. The latest release as of App Engine at the time of writing is 1.8.8.

Create App Engine Project

The first thing we will do here is to generate a new App Engine project. Let us not disturb anything that we did with the project from their previous part of this tutorial series.

Assuming that you are using Eclipse, do the following:

  • Select File -> New -> Project. Select Google and Web Application Project. Click on Next.
  • In the Project name, choose a suitable name. I have named my Project : MyAPIProject2. For the package name, I have provided com.mindstorm.famousquotes. Deselect the GWT option. Leave the other options as default. Click on Finish.

This will generate the App Engine project for you.

The Entity Class – Quote.java

The next thing we are going to do is write our Quote class. This class is similar to the one that we saw in the previous episode. I have stripped it down further by removing the hashcode/equals/etc methods from the class to keep our focus clear.

The Quote entity still has 3 main attributes : id, author and the message.

What you will find different here is that the class is JDO Enabled. Take a look at the full source code for the JDO enabled Quote entity class and we will discuss further.

Let us discuss the main points:

  • We mark our Quote class for Persistence via the @PersistenceCapable annotation. This is done right at the top of the class declaration.
  • Each attribute of the class that we would like to persist is marked with a @Persistent Annotation. If you do not want to persist any specific attribute mark it with @NonPersistent. But in our case, this does not arise.
  • We need to specify which attribute is the Identifier Key i.e. which can be used to uniquely identify a specific record in the datastore. In our Quote class, the Id attribute will always have a unique value for each record, hence we give it an additional annotation @PrimaryKey.
  • Notice that for the Id attribute, we have also provided an additional attribute for the @Persistent annotation. We have specified that a valueStrategy and the value of which says that the underlying JDO implementation will take care of providing it a unique ID. What this means is that when we want to persist a Quote object, we will simply have to construct the Quote object and populate its author and message attributes. The Id value will be filled up appropriately for us at the time of persistence.

Make sure that you have saved this class, before moving on to the next step.

Generating the Quote Endpoints class

Now that we have our Quote JDO Entity class in place, we are going to tell the Endpoints library to help generate the Endpoint API class, with the full JDO implementation such that we do not have to worry about writing the code that deals with the Datastore API, that App Engine provides.

Let us generate the API Endpoints class now. To do that, do the following:

  • Right-click on the Quote class in your Eclipse IDE and select Google -> Generate Cloud Endpoint Class as shown below:Screen Shot 2014-01-12 at 4.11.59 PMThis will generate a couple of Java classes for you in the same package that your Quote Java class is present in.
  • The 2 files generated are PMF.Java and QuoteEndpoint.java. The QuoteEndpoint.java is of particular importance to us and it contains the Endpoints class.
  • Take a look at QuoteEndpoint.java. If you have followed Part 1 of the tutorial, you will notice that the method signatures if not the method implementations look familiar. They contain the usual methods for inserting, updating, deleting and fetching Quotes, almost similar looking to the ones that we wrote by hand.

At this point in time, you could actually just Build your project and Run the Web application and the API will be available to you if you navigate to the _ah/api/explorer endpoint in your local browser. You can try out the method for the QuoteEndpoint and not worry about what happens behind the scenes but you will only get so far, hence we will get into the details of what the code is doing and in fact, even correct a problem or two with the generated code.

Lets move on.

Dissecting the generated Quote Endpoints class

If you look at the QuoteEndpoint.java class that has got generated, you will find the following methods that it generated.

Screen Shot 2014-01-12 at 4.21.42 PM

The Green circle indicates public methods, which means that the methods will be exposed by the API Endpoint. A couple of methods are private methods here and are used by the other methods.

The getPersistenceManager() private method is used to get an instance of the PersistenceManager implementation. The second Java file (PMF.java) that was generated for you, contains the details for getting the instance. This is standard boilerplate code for getting a handle to the Persistence Manager in the JDO/JPA world.

OK. Over to the API Endpoint methods now. These are all the public methods in the class. Just a side note that if you plan to enhance the functionality and need to write your own methods but do not want to expose them as API methods, do remember to mark them as private.

The entire source code for the QuoteEndpoint.java file is shown below. In fact I did modify the code slightly to make it work for me in the way that I wanted and I will discuss that in the next section (Modifying the Source Code)

The main points to note are:

  • Note the @API annotation used at the top to identify that this is an API class. The namespace stuff is used when we generate our client libraries and we will look at that in the next tutorial or two but for now, don’t worry too much – though you will be able to understand that it uses your package names from the project.
  • Each of the methods should be understandable now to you based on our learning from the previous part. Each of the public methods that need to be present in the API are annotated with the @APIMethod annotation. A name attribute specifies the name of the method.
  • Pay attention to a new annotation used for parameters passed to the public API methods. The annotation is @Nullable and it means that it is not a mandatory parameter to be passed.
  • The method implementations are not difficult to understand. Each of the method implementations simply gets a handle to the persistence manager, then performs appropriate DB operations for get, update, insert , delete and then closes the persistence manager object, so that the operation can be committed by the Datastore implementation.

Important point :
The method signatures that you see here are generally regarded as Best Practices for a REST API. You can always debate for example, if you want to pass a Quote object to the insert method or you want to pass individual parameters i.e. author and message.

The point is that nothing stops you from following a style that suits you. So there is a lot of flexibility that is available here from an interface point of view. You decide if the method names need to be different, if you would like to use POST instead of GET, if you want individual parameters instead of the whole Quote object and so on. Just refer to the full Annotation documentation and understand them better.

Modifying the Source Code

Just to demonstrate that things are flexible and that you might not find the Google code at times, appropriate to your functionality – I modified the generated code a bit.

Refer to the insert method shown below. The parameter to be passed is the whole Quote object and while inserting a new record, remember that we had discussed that we will only pass the author and the message attributes. We will keep the Id field empty or not provide it since we would like the Id generation strategy to be automatically handled by the JDO implementation.

@ApiMethod(name = “insertQuote”)
public Quote insertQuote(Quote quote) {
PersistenceManager mgr = getPersistenceManager();
try {
   if (quote.getId() != null) {
          if (containsQuote(quote)) {
throw new EntityExistsException(“Object already exists”);
}
   }
  mgr.makePersistent(quote);
} finally {  mgr.close(); }
return quote;
}

The original code did not have the check that I have added in bold and as a result, the API implementation was crashing if I provided a new Quote object to be added without providing the Id (which I did not want to provide in any case).

In the next section, you will observe that I do not pass the Id value when using the insertMethod.

Testing out the API

You can test out the API in the same fashion i.e. via the API Explorer, which is also available locally.

We will keep our testing limited to a call or two, since I am assuming that you are comfortable with it now.

To Test the API, do the following:

  • Run the Web application.
  • Assuming that it is running on port 8888, go to http://localhost:8888/_ah/api/explorer. Make sure you are connected to the Internet.
  • Click on the Quote Endpoint and you will find a list of methods. Specifically, let us click on the insertQuote method.
  • This brings up the screen as shown below:Screen Shot 2014-01-12 at 10.39.25 AMNotice that we are populating only the author and the message attributes. We are not providing the id, since we want that to be system generated and unique and the underlying JDO implementation handles that for us.
  • Click on the Execute button and it should insert the record successfully for you. The sample run from my system is shown below:
    Screen Shot 2014-01-12 at 10.39.42 AM
  • You can try out the other API methods if you want. They should work well.

Datastore Viewer

Since the code generated works with the Datastore, every successful INSERT of a Quote record will end up as a record inside the App Engine Datastore. You can validate this within your local development environment too.

Before you check the Datastore, make sure that:

  • You have started the Web application
  • Used the API Explorer http://localhost:8888/_ah/api/explorer and invoked the insertQuote method a few times and checked if the successful execution has happened.
  • Then visit http://localhost:8888/_ah/admin i.e. the normal Administration console URL in your browser. If you visit the Datastore link, you should see an entity Quote available and you could take a look at the different records. An example screenshot from my environment is shown below:Screen Shot 2014-01-12 at 10.40.04 AM

Some comments

  • Cloud Endpoints generates for us a Endpoint Java class. This should not be taken as the final class that we should not or cannot modify. You had learnt in the first part of the tutorial about the different annotations and method parameters. You are free to change any of the generated class code to suit your API style and requirements.
  • The code that is currently generated for a JDO/JPA Entity class works with the App Engine Datastore service. So if you are not planning to use this infrastructure service in your application, then you will need to modify the Endpoint class accordingly.
  • The generated code is by no means production ready and you should build in your own validations and Exception classes as needed. For e.g. it is good practice to make sure that all the request parameters contain valid values before you go ahead with any of the operations. In the code that we modified, we simply put in an additional check to see if the ID is provided, etc. But I would even go further and make sure that valid values for Author and Message are provided. Only then would I go ahead and do any persistent operations , else I would just reject the call there itself with the appropriate Exception.

Download Full Source Code

I suggest that you begin with a full download of the project source code.

Go ahead & download the code from :

https://github.com/rominirani/MyAPIProject2

Hope you liked this episode. In the next part (Part 3) of this series, we shall see how to generate client libraries (particularly for Android) and consume it from our Android application.

Till then, have a good time generating Cloud Endpoints classes.

About these ads

56 thoughts on “Google Cloud Endpoints Tutorial – Part 2

  1. FWIW you don’t need plain “@Persistent” on String fields, or indeed the vast majority of fields, only needed if the type is not a commonly used type, or you want to specify other attributes with the annotation. You also don’t need “identityType = IdentityType.APPLICATION” since you’ve annotated a field as @PrimaryKey so have to use application identity.

  2. When creating the Google web project using the wizard, you could add to your tutorial to uncheck the “Generate project sample code”. It’s not obvious and lead to confusion.

    Generating the project using the wizard and deselecting the GWT still add this debug configuration Attribute argument:
    -codeServerPort 9997 –port=8888 com.mindstorm.famousquotes.MyAPIProject2__part2 “J:\workspace15\MyAPIProject2 -part2\war”

    For some reason the GWT codeServerPort is not removed. Deleting the debug configuration fixes the problem and it look like this

    –port=8888 “J:\workspace15\MyAPIProject2 -part2\war”

  3. Hi Ramin,

    First of all, thank you very much for your great tutorials. I have two questions and wonder if you could please help.

    1) The Google cloud endpoints library generated comes with the standard sets of CRUD APIs, for e.g. list all quotes with ‘listQuote’ API. What if I want to add predicates to listQuote and select certain quotes filtered by the predicates? How do I do it?
    2) Similarly, instead of updating the entire Quote row with the standard cloud endpoints API ‘updateQuote’, can I update the Author column only?

    Thank you in advance for your help,

    1. I believe both of the points that you have mentioned are possible. All you need to know if modify the Datastore API related code to do what you want i.e. filtering and updating certain attributes for the Datastore entity only.

  4. Lovely tutorial, You’re very clear in explanation. Just a question about the auto-generated code: what is the cursorString parameter inside the list method?

    if (cursorString != null && cursorString != “”) {
    cursor = Cursor.fromWebSafeString(cursorString);
    HashMap extensionMap = new HashMap();
    extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
    query.setExtensions(extensionMap);
    }

      1. Thank you so much! :-) It really makes things clear as you said :-) I have a new question but i’ll ask it in a new post below because it’s not correlated with this one.

  5. I have in my DataStore 2 Entities more specifically the Entity1 with a @Unowned Relationship to Entity2 (in my case i used a java.util.List of entity2 objects). When i create the Endpoint showing the Entity1 i can only see simple fields (String, Integer…). How can i create a more complex List, or better, how can i fix this issue in order to see all the fields of my Entity Class? Thank you so much

    1. 1. Are you saying that you are able to see only simple fields of Entity1 in the API Explorer ? If yes, something looks missing since if there are other entities specified in the JDO Entity object, they do show up.

      2. Please check if you have not forgotten to regenerate the EndPoints after you have changed the Entity definition ?

      3. For e.g. try to create one Entity1 and inside of that put
      @Persistent
      List<Entity2> items;

      Save Entity1 and regenerate the Endpoints class. I believe it should show up.

      1. 1. Yes only in the API Explorer, because i can see them in the Datastore.

        2.I’ve never generate the Endpoints before concluding to write Enitity1 and Entity2.

        3.All my fields are Tagged with @Persistent, the List fields as well. Like this:
        @Persistent
        @Unowned
        private List fileld2 = null;

        @Persistent
        @Unowned
        private List field3 = null;

        The Endpoints class is generated with the usual method: list, get, insert, update, remove. Nothing else. But theoretically, calling the list method i would get the entire Entity with all the fields, but they don’t show up :-(

      2. Sorry for frustrating you, but i tried to build more than one simple projects, but the problem still remain. I supposed was the incompatibility with @Unowned TAG , but it wasn’t. It still not work. :-( Any other suggestion? Thank you so much in advance

      3. Hi Stefano – I am not sure what the problem could be here. At a high level it looks like some mismatch between using JDO Annotations and how it is being addressed while generating/executing the cloud endpoints code. I am sorry – but I don’t have any specific solution or alternatives at this point. If you find the solution, please do share.

  6. I don’t think i’m doing wrong because i followed also your fantastic tutorials and the only thing i’ve added in my code is the relationship with an other Entity. If and only if you want and have some “spare time” i can upload my project with or without the auto-generted Endpoint and you could check by yourself if something is wrong. Let me know rominirani ;-) and thank you so much for support.

    1. Hi Stefano – please upload your simplified project code to a url, where I can download from. I am very much interested in understanding what is happening in your scenario. You can email me the link to r o m i n DOT k DOT i r a n i AT GMAIL.COM

  7. Dear Romin,
    I have a quick question regarding the API explorer. In your example, while testing API for “insertQuote” I see that you have a request body to fill in but for my case the request body is empty. This is making me unable to test the API. Any idea what is missing here?

  8. Hi Romin,

    First of all, thanks a lot for your website ! It’s a bit my bible about Google Cloud Endpoints.
    I have a problem with two entities, Parent and Child. I am just beginning to develop on android and App Engine, and I dont know where I can find informations about relashionships between Parent and Child entitie… I read that (https://developers.google.com/appengine/docs/java/datastore/jdo/relationships) but I can’t get an attribute of my parent entitie from my child entitie…
    Did you have by chance, another example website of relationships between Parent and Child entities ? :-)

    Thank in advance,

    Bye Bye from France ;-)

      1. Hi Romin,

        Thank you for your quick response and your helpful links.
        We can use objectify library from Android App ? How ? Because when you generate your cloud endpoint class, I don’t know if it is compatible with Objectify…

        I use Objectify with GAE servlet, but with endpoints like android… What do you think about that ?

        Thanks a loooooott ! :)

      2. 1. Objectify is for GAE, so it is for use on the Server side. I thought you were mentioning about persisting the data on the server, hence I recommended that.
        2. The Cloud Endpoint class that is generated does not generate Objectify code for you. Hence you will have to put that code yourself into the Java class and annotate the same with Endpoint Java annotations to make it an Endpoint class.

  9. Hello,
    I’m getting this error while trying to insert quote,

    500 Internal Server Error

    – Show headers –

    {
    “error”: {
    “message”: “javax.jdo.JDOFatalUserException: A property named javax.jdo.PersistenceManagerFactoryClass must be specified, or a jar file with a META-INF/services/javax.jdo.PersistenceManagerFactory entry must be in the classpath, or a property named javax.jdo.option.PersistenceUnitName must be specified.”,
    “code”: 503,
    “errors”: [
    {
    “domain”: “global”,
    “reason”: “backendError”,
    “message”: “javax.jdo.JDOFatalUserException: A property named javax.jdo.PersistenceManagerFactoryClass must be specified, or a jar file with a META-INF/services/javax.jdo.PersistenceManagerFactory entry must be in the classpath, or a property named javax.jdo.option.PersistenceUnitName must be specified.”
    }
    ]
    }
    }

    1. It seems that either some of the JDO specific property files / xml configuration files / JAR files are not in their right places in your project. Check out the following 2 links to see if it helps:
      1. http://stackoverflow.com/questions/14329405/javax-jdo-jdofataluserexception-maven-datanucleus-jetty-com-mysql-jdbc-dr
      2. http://stackoverflow.com/questions/10350621/error-while-making-object-persistent

      Maybe just do a rebuild or if better , try with a new project and migrate your code to that.

  10. Hi Romin,

    Hoping that everything goes well for you. Thank you again for your response and your work..
    I searched on the web, and I found this fantastic tuto about Objectify with Google Cloud Endpoint: http://blog.xebia.fr/2014/06/23/google-app-engine-cloud-endpoint-creer-notre-api-v2-et-lutiliser-avec-angularjs/ (That is in French, but very understandable) That help me a lot ! :)

    Hoping to meet you one day in France,
    Take care of you ;)

    Phil

    1. Thanks for the link – very useful.

      In fact, if you use Android Studio instead of Eclipse, you will find that the Cloud Endpoints code that it generates is with Objectify Code. So you could take a look at that too.

  11. Hi Rominirani, Thank you very much for this awesome write up. I’m very new to Cloud endpoints and GAE. A quick question. How do I convert this api backend to run on my google account’s project URL instead of localhost:8888. I believe I need to include my project ID or Web Client ID somewhere. Please clarify. Thanks.

    1. You will need to deploy your app to App Engine. The steps are signing up for App Engine, create a project there first, which will give you the Project ID. Then this project ID is to be placed in the appengine-web.xml file present in the WEB-INF folder. Once done, deploy your project from the IDE or command line.

  12. Hi Rominirani, Thank you for this great tutorials. It helps me a lot!!!

    A quick question. I keep getting error when i try insert method.

    503 Service Unavailable

    – Show headers –

    {
    “error”: {
    “message”: “org.datanucleus.api.jdo.exceptions.ClassNotPersistenceCapableException: The class \”com.inb348.restfultest.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.\nNestedThrowables:\norg.datanucleus.exceptions.ClassNotPersistableException: The class \”com.inb348.restfultest.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”,
    “code”: 503,
    “errors”: [
    {
    “domain”: “global”,
    “reason”: “backendError”,
    “message”: “org.datanucleus.api.jdo.exceptions.ClassNotPersistenceCapableException: The class \”com.inb348.restfultest.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.\nNestedThrowables:\norg.datanucleus.exceptions.ClassNotPersistableException: The class \”com.inb348.restfultest.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”
    }
    ]
    }
    }

    Would you tell me what is the problem plz?

    1. There is something going wrong with the DataNucleus Enhancer plugin in your Eclipse setup. When the project is built, Eclipse invokes the DataNucleus plugin to enhance your classes that have got annotated with the JDO/JPA annotations. Ideally, you should see a message in your Eclipse console that the Enhancer ran successfully and the the enhanced classes have been generated. Try cleaning the project and/or refer to some forums for this problem. I can’t specifically pin point what could be the root cause.

  13. Hi,
    Thanks for this tutorial. I give it a try with your Quote successfully. The on problem is the id which is not auto generated. When I miss it, I get this error :

    {
    “error”: {
    “message”: “javax.jdo.JDOFatalInternalException: The key value passed to construct a SingleFieldIdentity of type \”class javax.jdo.identity.LongIdentity\” for class \”class com.test.api.Quote\” is null.\nNestedThrowables:\norg.datanucleus.exceptions.NucleusException: The key value passed to construct a SingleFieldIdentity of type \”class javax.jdo.identity.LongIdentity\” for class \”class com.test.api.Quote\” is null.”,
    “code”: 503,
    “errors”: [
    {
    “domain”: “global”,
    “reason”: “backendError”,
    “message”: “javax.jdo.JDOFatalInternalException: The key value passed to construct a SingleFieldIdentity of type \”class javax.jdo.identity.LongIdentity\” for class \”class com.test.api.Quote\” is null.\nNestedThrowables:\norg.datanucleus.exceptions.NucleusException: The key value passed to construct a SingleFieldIdentity of type \”class javax.jdo.identity.LongIdentity\” for class \”class com.test.api.Quote\” is null.”
    }
    ]
    }
    }

    1. Sure. You will need to generate your ID otherwise you will get this error since a unique identifier is needed before you can persist the same. One option would be to modify the Persistence code such that if you do not pass one, you can autogenerate one on your one. So you can do a setXXX on the ID before you persist the object.

  14. Hi,

    Thanks a lot for this tutorial.
    I am trying to add a new ApiMethod for listing all the entities filtered by a property value.
    I created the method and added query.setFilter(), query.setOrdering() methods to extract only the required entities.

    Now the challenge is, I get an error symbol in the project folder. I could not see any errors in any of the sub folders and the java files.

    i have mailed you the screenshot showing the error and the modified QuoteEndpoint.java file.

    Could you please advise me to overcome this issue? If you need further information please ask.

    Thanks,
    Karthick.

  15. Hi Romin,

    I have found solution for my above question.

    I found the below error from the problems view. (Windows -> Show View -> Problems)

    “There was a problem generating the API metadata for your Cloud Endpoints classes: com.google.api.server.spi.config.validation.DuplicateRestPathException: quoteendpoint.com.mindstorm.famousquotes.QuoteEndpoint: Multiple methods with same rest path “GET quote”: “listQuote2″ and “listQuote” MyAPIProject2 Unknown Google App Engine Cloud Endpoints Problem Marker”

    So I gave two different paths for the ApiMethods just like below,

    @ApiMethod(name = “listQuote”, path=”list”)
    @ApiMethod(name = “listQuote2″, path=”list2″)

    And the challenge is solved now. Thanks alot for the tutorial. I just follow this single tutorial to build my app! Thanks very much :)

    Thanks,
    Karthick

  16. Hi Rominirani

    Thanks very much for your tutorial.

    I have found it really useful. I am having the same problems as Reo Lee with my DataNucleus plugin. I get this same error message. Is this a problem with GWT? Or can the endpoint be used with GWT? If so I am not sure how to adjust the change the class path to fix this? Any ideas. Thanks very much

    “message”: “org.datanucleus.api.jdo.exceptions.ClassNotPersistenceCapableException: The class \”exampleProjecttext.testpackege.client.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.\nNestedThrowables:\norg.datanucleus.exceptions.ClassNotPersistableException: The class \”exampleProjecttext.testpackege.client.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”,
    “code”: 503,
    “errors”: [
    {
    “domain”: “global”,
    “reason”: “backendError”,
    “message”: “org.datanucleus.api.jdo.exceptions.ClassNotPersistenceCapableException: The class \”exampleProjecttext.testpackege.client.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.\nNestedThrowables:\norg.datanucleus.exceptions.ClassNotPersistableException: The class \”exampleProjecttext.testpackege.client.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”
    }
    ]
    }
    }

    1. I am not too sure about GWT since I have never used it. However, one thing you can do is to make sure that the sample project, you simply deselect GWT while generating the project from scratch.

      Having said that, I think it could be something with your settings or environment. Do take a look at Stack Overflow and other sites, the problem seems to be there for some users. I am sorry – I cannot be of more help here.

      1. Thanks very much for the reply. I have given up on the GWT idea as that just is not working at all… However, I now tried to create a new GAE web application and as soon as it is created the datanucleus build gives errors. Is there a way to refresh the whole system to start from scratch? I have absolutely no clue what half of the forums are referring to (hence why your tutorial was so BRILLIANT! It was understandable :) ).

        I am just getting more of the class has not been enhanced errors. In terms of environments what should I be looking for? I have tried to delete eclipse and re-install the GAE plugin but that did nothing. Thanks very much again for your help.

      2. Never mind. I have managed to successfully import your example project. So there must be some sort of configuration problem. I’ll have to search for that at a later stage. Thanks again

  17. Thank you for this article. However I’m having some issues, I’m using Windows 8 with Eclipse Luna and when I try to run the app locally after annotating and generating the endpoint class, the console says “The class “com.example.myapiproject2.Quote” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”

    And when I go on the url http://localhost:8888/_ah/api/explorer and try the insert method, an error occurs saying quite the same thing about the class not persistable…

    I have fully read and followed your tutorial so I don’t understand what is going on.

    Can you help me please?

    1. Something has gone wrong with your Project, linking of the JDO libraries and some Eclipse settings for preprocessing of JDO Annotations. Try it in a fresh project. There are some links on Stack Overflow that cover this issue and I suggest looking there.

  18. This article is great, thanks.
    I was wondering, is it possible to add Objectify annotations in the entity before creating the Endpoint class?
    I would like to use @Cache to enable the use of Memcache with the Datastore.

    1. I haven’t particularly tried it but here is what I would suggest.
      a) If you want to use Objectify, you definitely can and stick to its APIs for doing CRUD Operations. This has nothing to do with Cloud Endpoints.
      b) Now, write your Cloud Endpoints layer on your own. So in other words, you don’t generate the persistence code from the Endpoint generator. Just write your Endpoints layer and put the code inside that references your Objectify layer.

  19. Thank you rominirani for this explanation. I don’t understand why but after doing this:
    1)Create an web application project
    2)create and annotate an entity
    3)generate endpoint class
    4)create a project on the google console and report the app id on the appengine-web.xml
    5)deploy

    I get 404 not found errors whereas it works perfectly on my local post. Eclipse keeps on saying the deployment was successful as well as the google console. Can you tell me if there is some step that I’m missing?

    Thank you

    1. Since you are saying that the Application deployed successfully, please check the following:

      1) Did the Endpoints get deployed correctly. Check out this tip that I had provided in another blog post:

      2) Are you receiving the Endpoint Error when you are trying to access the API Explorer on your deployed application. For e.g. http://.appspot.com/_ah/api/explorer ? Are you sure there is no typo or something ?

  20. Thank you very much for answering.
    1)I checked your post and I got quite the same message than yours: “https://1-dot-app_id.appspot.com/_ah/api/myentityendpoint@v1 Saved”

    2)When I visit my url (http://app_id.appspot.com/_ah/api/explorer) I see the API explorer dashboard with nothing on it (while when running locally I could see my API)

    In my logs there is only 1 warning about favicon: “2014-11-22 15:48:04.722 /myapiproject 404 57ms 0kb Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36 module=default version=1
    W 2014-11-22 15:48:04.721 No handlers matched this URL.”

    I don’t know if this is useful.

    1. The favicon message is fine. It is just a while that is not available and does not matter.

      I am bit confused why you are able to see the things work locally and not seeing it in the live app engine instance ? It is stupid of me to ask but I am assuming that you are connected to the internet since it does hit the internet for evaluating your API i.e. the API Explorer.

      I am currently not having a clue but try maybe another app id, redeploy fresh into that ?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s