How to know strong name of GWT serialization policy at the time of host page generation? - gwt

There is an excellent article describing a way to embed GWT RPC payload into the host page. A key element is missing there is how to know Strong Name of RPC serialization policy at run time.
Strong Name is computed at the compile time, put into the client and obfurscated. Strong name is sent to the server with RPC request as described here. What would you suggest to make this parameter available at the time of host page generation?

I have integrated GWT with spring with a custom SerializationPolicyProvider where I always had to rename <strong name>.gwt.rpc file and hard code the name in my custom SerializationPolicyProvider class. I got work around by looking at GWT docs. Strong Name is MD5 hash with length of 32. Each time RPC call is made to Spring based Controller's method: public String processCall(String payload), I parse the payload using following code to get strong name:
String strongName = null;
if(payload!=null){
StringTokenizer tokens = new StringTokenizer(payload,String.valueOf(AbstractSerializationStream.RPC_SEPARATOR_CHAR));
while(tokens.hasMoreTokens()){
String s = tokens.nextToken();
if(s.length() == 32){
strongName = s;
break;
}
}
}
Then in your SerializationPolicyProvider impl class use following:
to get SerializationPolicy:
return SerializationPolicyLoader.loadFromStream(servletContext.getResourceAsStream(moduleBaseURL+"/"+strongName+"gwt.rpc");

One solution seems to be using compiler -gen option. Get _Proxy.java from compiler output and extract SERIALIZATION_POLICY from it.

Related

Controller return type and httpStatus best practice and production/consumption on method in REST WS

I commence in REST and I have some questions:
What type must the controller return? Typically, I'm asking if my Rest #Controller must return Item object as it is or encapsulate it in ResponseEntity in order to specify http-status-code.
What http status code to use in a GET method on a particular item ("/items/2") if the given item does not exists: HttpMediaStatus.OK(200) and null return or HttpStatus.NO_CONTENT(204) and null return ?
Second part: I saw it was possible to specify #Produces and #Consumes on WS method but what the use of that? My application and my methods work so, why specify MediaType.APPLICATION_JSON_VALUE? Doesn't Spring/SpringBoot automatically convert Item or ResponseEntity into json?
Context: using Spring Boot, hibernate, REST webservice.
Thank you.
Many questions in one, I'll provide short answers with a bunch of link to relevant articles and the reference documentation.
What type must the controller return?
Depends on your annotation and the RESTful-ness of your service. There are three annotations you can use for controllers: #Controller, #RestController and #RepositoryRestController.
Controller is the base annotation to mark your class as a controller. The return type of the controller endpoint methods can be many things, I invite you to read this dedicated post to get a grasp of it.
When developing a pure-REST service, you will focus on using RestController and RepositoryRestController.
RestControlleris Controller + ResponseBody. It binds the return value of the endpoint method to the web response body:
#RestController
public ItemController {
#RequestMapping("/items/{id}")
public Item getItem(#PathVariable("id") String id) {
Item item = ...
return item;
}
}
With this, when you hit http:/.../api/items/foo, Spring does its magic, automatically converting the item to a ResponseEntity with a relevant 40X status code and some default HTTP headers.
At some point, you will need more control over the status code and headers, while still benefiting from Spring Data REST's settings. That's when you will use RepositoryRestController with a ResponseEntity<Item> as return type, see the example the Spring Data REST reference.
What http status code to use in a GET method on a particular item if the given item does not exists?
Bluntly said: use HttpStatus.NOT_FOUND. You're looking for a resource that does not exist, there's something wrong.
That being said, it is completely up to you to decide how to handle missing resources in your project. If your workflow justifies it, a missing resource could be something completely acceptable that indeed returns a 20X response, though you may expect users of your API to get confused if you haven't warned them or provided some documentation (we are creatures of habits and conventions). But I'd still start with a 404 status code.
(...) #Produces and #Consumes on WS method but what the use of that? My application and my methods work so, why specify MediaType.APPLICATION_JSON_VALUE? Doesn't Spring/SpringBoot automatically convert Item or ResponseEntity into json?
#Consumes and #Produces are respectively matched against content-type and accept headers from the request. It's a mean of restricting the input accepted and the output provided by your endpoint method.
Since we're talking about a REST service, communications between clients of the API and the service are expected to be JSON-formatted. Thanks to Spring HATEOAS, the answer are actually formatted with the application/hal+json content-type.
In that scenario, you can indeed not bother with those two annotations. You will need them if you develop a service that accepts different content-types (application/text, application/json, application/xml...) and provides, for instance, HTML views to users of your website and JSON or XML response to automated clients of your service.
For real life examples:
Facebook provides the Graph API for applications to read to/write from its graph, while users happily (?) surf on web pages
Google does the same with the Google Maps API

Why can't I get HAL support to work in grails 2.3.8?

I am following the directions in the docs, here:
http://grails.org/doc/2.3.8/guide/webServices.html#hypermedia
Why won't grails produce HAL-formatted output, as shown in the documentation?
I have a domain object which I have mapped with the #Resource annotation:
#Resource(uri='/documentCatalogs', formats = ['json', 'xml'], readOnly = true)
class DocumentCatalog {
String entityType
String actionCode
...
}
...and in my conf/spring/resources.groovy, I have configured the HAL JSON renderer beans:
import com.cscinfo.platform.api.formslibrary.DocumentCatalog
import grails.rest.render.hal.HalJsonCollectionRenderer
import grails.rest.render.hal.HalJsonRenderer
// Place your Spring DSL code here
beans = {
halDocumentCatalogRenderer(HalJsonRenderer, DocumentCatalog)
halDocumentCatalogCollectionRenderer(HalJsonCollectionRenderer, DocumentCatalog)
}
Using the debugger, I confirmed that the initialize() method on HalJsonRenderer is called and that it is constructed with the correct targetType.
I send a rest call using Postman:
http://localhost:8080/formslibrary/documentCatalogs/3
Accept application/hal+json
And I get back a response which is regular JSON and doesn't contain any links:
{
"class": "com.cscinfo.platform.api.formslibrary.DocumentCatalog",
"id": 3,
"actionCode": "WITH",
"entityType": "LLP",
...
}
What did I miss? Is there some plugin or configuration setting I have to enable for this behavior? Is there some additional mapping property somewhere that's not documented?
Figured it out! There are multiple aspects of the fix...
I had to add "hal" as one of the listed formats in the #Resource annotation:
#Resource(uri='/documentCatalogs', formats = ['json', 'xml', 'hal'])
Some hunting around in the debugger revealed that Grails will blithely ignore the Accept header, based on the UserAgent string that is sent from the client. (In my case, since I'm using Postman, it was the Google Chrome UA string.)
One workaround for the Accept header issue is to add ".hal" to the end of the URL:
http://localhost:8080/formslibrary/documentCatalogs/3.hal
This isn't a very good solution IMO, since the HAL URLs generated by the renderer don't end in ".hal" by default.
A better solution is to fix Grails' handling of the accept header by updating the config. In Config.groovy, you will see a line that says:
grails.mime.disable.accept.header.userAgents = ['Gecko', 'WebKit', 'Presto', 'Trident']
Change it to:
grails.mime.disable.accept.header.userAgents = ['None']
This forces Grails to honor the Accept header, regardless of the user agent.
Hope this helps somebody else who's hitting the same issue.
P.S. It's really helpful to put a breakpoint in the ResponseMimeTypesApi#getMimeTypesFormatAware(...) method.

Performing Explicit Route Mapping based upon Web Api v2 Attributes

I'm upgrading a custom solution where I can dynamically register and unregister Web Api controllers to use the new attribute routing mechanism. However, it seems to recent update to RTM break my solution.
My solution exposes a couple of Web Api controllers for administration purposes. These are registered using the new HttpConfigurationExtensions.MapHttpAttributeRoutes method call.
The solution also allows Web Api controllers to be hosted in third-party assemblies and registered dynamically. At this stage, calling HttpConfigurationExtensions.MapHttAttributeRoutes a second time once the third-party controller is loaded would raise an exception. Therefore, my solution uses reflection to inspect the RoutePrefix and Route attributes and register corresponding routes on the HttpConfiguration object.
Unfortunately, calling the Web Api results in the following error:
"No HTTP resource was found that matches the request URI".
Here is a simple controller that I want to use:
[RoutePrefix("api/ze")]
public sealed class ZeController : ApiController
{
[HttpGet]
[Route("one")]
public string GetOne()
{
return "One";
}
[HttpGet]
[Route("two")]
public string GetTwo()
{
return "Two";
}
[HttpPost]
[Route("one")]
public string SetOne(string value)
{
return String.Empty;
}
}
Here is the first solution I tried:
configuration.Routes.MapHttpRoute("ZeApi", "api/ze/{action}");
Here is the second solution I tried:
var type = typeof(ZeController);
var routeMembers = type.GetMethods().Where(m => m.IsPublic);
foreach (MethodInfo method in routeMembers)
{
var routeAttribute = method.GetCustomAttributes(false).OfType<RouteAttribute>().FirstOrDefault();
if (routeAttribute != null)
{
string controllerName = type.Name.Substring(0, type.Name.LastIndexOf("Controller"));
string routeTemplate = string.Join("/", "api/Ze", routeAttribute.Template);
configuration.Routes.MapHttpRoute(method.Name, routeTemplate);
}
}
I also have tried a third solution, whereby I create custom classes that implement IHttpRoute and trying to register them with the configuration to no avail.
Is it possible to use legacy-style route mapping based upon the information contained in the new routing attributes ?
Update
I have installed my controller in a Web Application in order to troubleshoot the routing selection process with the Web Api Route Debugger. Here is the result of the screenshot:
As you can see, the correct action seems to be selected, but I still get a 404 error.
Update2
After further analysis, and per Kiran Challa's comment below, it seems that the design of Web Api prevents mixing attribute routing and conventional routing, and that what I want to do is not possible using this approach.
I have created a custom attribute [RouteEx] that serves the same purpose of the Web Api [Route] attribute, and now my code works perfectly.
I guess, since this is not possible using the conventional attribute routing, none of the answers on this question could legitimately be consisered valid. So I'm not nominating an answer just yet.
You shouldn't be required to use reflection and inspect the attribute-routing based attributes yourself. Attribute routing uses existing Web API features to get list of controllers to scan through.
Question: Before the switch to attribute routing, how were you loading these assemblies having the
controllers?
If you were doing this by IAssembliesResolver service, then this solution should work even with attribute routing and you should not be needing to do anything extra.
Regarding your Update: are you calling MapHttpAttributeRoutes?

Complex (non string) return type for Jersey REST method

I'm having trouble setting something up that I'm pretty sure /should/ be easy, so I thought I'd throw it to the crowd. I can't seem to find what I'm looking for elsewhere on the web or on SE.
I am simplifying my project of course, but basically I have a JAX-WS annontated Jersey resource class that looks something like this:
#Path("myresource")
public class MyResource {
#Autowired
MyComplexObjectDAO daoInstance;
#Path("findObject/{id}")
#GET
public MyComplexObject findObject( #PathParam(value="id") String id ) {
return daoInstance.findObject( id );
}
#Path("saveObject")
#PUT
public MyComplexObject saveObject( MyComplexObject objectToSave ) {
MyComplexObject savedObject = daoInstance.saveObject( objectToSave );
return savedObject;
}
}
So you can see I'm autowiring a DAO object using spring, and then I use the DAO methods in the REST handlers.
The 'findObject' call seems to work fine - so far it works exactly as I expect it to.
The 'saveObject' call is not working the way I want and that's what I need some advice on.
You can see that I'm trying to directly take an instance of my complex object as a parameter to the REST method. Additionally I would like to return an instance of the complex object after it's been saved.
I put together some 'client' code for testing this out.
#Test
public void saveTest() {
WebResource wsClient = createWebServiceClient();
MyComplexObject unsavedInstance = createMyComplexObject();
MyComplexObject savedInstance =
wsClient
.path("saveObject")
.accept(MediaType.APPLICATION_XML)
.put(MyComplexObject.class, unsavedInstance);
assertNotNull(savedIntent);
}
Which is returning the following error:
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:8081/rest/myresource/save returned a response status of 400 Bad Request
I don't see why this isn't working and I think I've tried just about everything I can think of. Any help or direction would be very much appreciated.
Thanks so much!
I see that you call the accept() method in your test client (which means that a "Accept:" header is added to the request, indicating the server what type of representation you would like). However, you don't call the type() method to add a "Content-type:" header and inform the server that you are sending XML data. See http://jersey.java.net/nonav/documentation/latest/client-api.html#d4e644 for examples.
Side remark: your URLs are not RESTful - you should avoid verbs in your path:
So, instead of:
/api/findObject/{id}
/api/saveObject
You should use:
/api/objects/{id}
/api/objects
Last note: to create an object on calling /api/objects, you should do a POST and not a PUT to adhere to REST best practices and widely adopted patterns.
switching to the 'concrete class' solution I alluded to in my earlier comment is what fixed things up for me.

ServiceStack Routing with ravendb ids

I've an entity with an ID of
public string ID {get;set;}
activities/1
(which comes from RavenDB).
I'm registering the following routes in my ServiceStack AppHost
Routes
.Add<Activity>("/activities")
.Add<Activity("/activities/{id}");
I'm using a backbone app to POST and PUT to my REST Service.
What happens out-of-the-box:
id property is serialized into the json as "activities/1"
id property is encoded into route as "activities%2F1"
ServiceStack gives precedence to the URL based id property, so my string gets the encoded value which is no use to RavenDb directly.
The options I'm aware of:
Change backbone to post to "/activities" and let the JSON Serialiser kick in
Change RavenDb ID generation to use hyphens rather than slashes
Make my Id property parse for the encoded %2F on set and convert to a slash
Both have disadvantages in that I either lose RESTfulness in my API, which is undesirable, or I don't follow RavenDb conventions, which are usually sensible out-of-the-fox. Also, I've a personal preference for having slashes.
So I'm wondering if there are any other options in servicestack that I could use to sort this issue that involve less compromise? Either Serialiser customisation or wildcard routing are in my head....
I have the same problem with ASP.Net WebAPI, so I don't think this is so much a ServiceStack issue, but just a general concern with dealing with Raven style id's on a REST URL.
For example, let's say I query GET: /api/users and return a result like:
[{
Id:"users/1",
Name:"John"
},
{
Id:"users/2",
Name:"Mary"
}]
Now I want to get a specific user. If I follow pure REST approach, the Id would be gathered from this document, and then I would pass it in the id part of the url. The problem here is that this ends up looking like GET: /api/users/users/1 which is not just confusing, but the slash gets in the way of how WebAPI (and ServiceStack) route url parameters to action methods.
The compromise I made was to treat the id as an integer from the URL's perspective only. So the client calls GET: /api/users/1, and I define my method as public User Get(int id).
The cool part is that Raven's session.Load(id) has overloads that take either the full string form, or the integer form, so you don't have to translate most of the time.
If you DO find yourself needing to translate the id, you can use this extension method:
public static string GetStringIdFor<T>(this IDocumentSession session, int id)
{
var c = session.Advanced.DocumentStore.Conventions;
return c.FindFullDocumentKeyFromNonStringIdentifier(id, typeof (T), false);
}
Calling it is simple as session.GetStringIdFor<User>(id). I usually only have to translate manually if I'm doing something with the id other than immediately loading a document.
I understand that by translating the ids like this, that I'm breaking some REST purist conventions, but I think this is reasonable given the circumstances. I'd be interested in any alternative approaches anyone comes up with.
I had this problem when trying out Durandal JS with RavenDB.
My workaround was to change the URL very slightly to get it to work. So in your example:
GET /api/users/users/1
Became
GET /api/users/?id=users/1
From jQuery, this becomes:
var vm = {};
vm.users = [];
$.get("/api/users/?" + $.param( { id: "users/1" })
.done(function(data) {
vm.users = data;
});