Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloud Endpoint parameter should not be named

I want send a HashMap<String, String> from JS application to my Google App. I created a HashMapContainer class such as in : Cloud Endpoints Collection Parameter.

The Endpoint method is defined like this :

public Entity myMethod(
        @Named('param1') String param1, 
        @Nullable @Named('param2') HashMapContainer param2) {
    //...
}

When I run the API generation this error happens :

com.google.api.server.spi.config.validation.ApiConfigInvalidException: 
    Resource type 'class com.mason.server.entity.HashMapContainer' 
    in method 'endpoint.myMethod' should not be named.

Therefore, I remove the @Named annotation. The API is generated but obviously, I do not receive the parameter send by the JS application. My JavaScript is like this :

function doTransaction() {
    var req = gapi.client.myApi.endpoint.myMethod({
        'param1': 'FOO',
        'param2': {
            'value1':'foofoo',
            'value2':'barbar',
            'value3':'foobar'
        }
    });
    req.execute(function(data) {
        console.log(data);
    });
}

How I can get the param2 if I'm not allowed to use the @Named annotation ?
Maybe my JavaScript is wrong?

like image 543
Mason Avatar asked Jul 03 '13 17:07

Mason


4 Answers

Google Cloud Enpoints documentation says:

@Named: This annotation indicates the name of the parameter in the request that gets injected here. A parameter that is not annotated with @Named is injected with the whole request object.

Basically, as far as I understand, when you add @Named annotation, the parameters will be included at the end of the request URL:

http://end_point_url?parameter1=xxx&parameter2=yyy

Obviously the parameter types that support @Named annotation are only a few (int, long, String, Boolean and their correspondent arrays, I think), because you can't append a whole hashmap to the request URL!

On the other hand, if you don't use @Named, the parameter will be included (injected) within the POST data.

In order to send a parameter within the HTTP body using the Google APIs Client Library for JavaScript, you just have to include that parameter into an object called resource inside the JSON-RPC request, like this:

var req = gapi.client.myApi.endpoint.myMethod({
    'param1': 'FOO',
    'resource': {
        'param2': {
            'value1':'foofoo',
            'value2':'barbar',
            'value3':'foobar'
        }
    }
});

The API client will automatically send param1 in the URL and param2 in the POST data...

This is explained in detail in this section of the Google APIs Client Library for JavaScript documentation.

like image 73
MikO Avatar answered Nov 17 '22 00:11

MikO


Using HashMap would get all the parameters passed to the Api Method, what i will advise is you use HaspMap<String,Object> as param2 map type, then this notifies us that inside this hashmap we can have our param2 as key of the hashmap. Then we can type cast the value of the param key to HashMap then we can loop through it like as if is the normal initial hashMap passed initially.

HashMap <String,String> mapR = (HashMap <String,String>) param2.get("param2");

        for(Map.Entry<String,String> x:mapR.entrySet()){
            log.log(Level.INFO,x.getKey()+","+x.getVaue());

        }
like image 22
Theophilus Omoregbee Avatar answered Nov 17 '22 00:11

Theophilus Omoregbee


The example in This doc shows the annotations used in a different order from what your code shows.

public Resource get(@Named("id") @Nullable int id) { … }

So according to this, your

@Nullable @Named('param2') HashMapContainer param2) {

should become

@Named('param2') @Nullable HashMapContainer param2) {

I tested it out both ways - only the latter seems to work for me.

like image 22
Dingredient Avatar answered Nov 17 '22 01:11

Dingredient


From the day I have asked this question, I found "another way" to use Google Cloud Endpoints. By following the documentation it's really simple to figure out how we can send an HashMap (Object in fact) from a JavaScript script.

Definition Endpoints/annotations#named

The @Named annotation is required for all non-entity type parameters passed to server-side methods. This annotation indicates the name of the parameter in the request that gets injected here. A parameter that is not annotated with @Named is injected with the whole request object.


JavaScript

We send a JS object through the REST API.

function doSomething() {
    var req = gapi.client.myApi.myMethod({
        'param1': 'FOO',
        'value1': 'foofoo',
        'value2': 'barbar',
        'value3': 'foobar'
    });
    req.execute(function(data) {
        console.log(data);
    });
}


Java API

And we receive all non-annotated parameters in the Java Map. They are sent in the HTTP request body (like describe in the documentation).

public Entity myMethod(
    @Named('param1') String param1, 
    Map<String, Object> param2) {

    System.out.println(param1); // FOO
    System.out.println(String.valueOf(param2.get("value1"))); // foofoo
    System.out.println(String.valueOf(param2.get("value2"))); // barbar
    System.out.println(String.valueOf(param2.get("value3"))); // foobar

    //...
}

Note the name "param2" does not matter for the client side, it could be named "resources".

This example is not the best practice but the simplest way to send parameters in the request and data into the body. You can improve it using your own class (instead of the Java Map interface) and add @ApiTransformer if needed. If you are using an entity as parameter, ensure of the annotations order (@named must be the first one).

like image 1
Mason Avatar answered Nov 17 '22 02:11

Mason