versioning rest service by creating abstract class? - java

I have a REST service with version v1 running fine in production. Now I need to make version v2 url as the response format is changed so we don't want to affect our current customers who are using v1 url. We will be returning some other object back with version v2 url instead of using ClientResponse object.
Below is my current design in which version is provided in #Path annotation. This was done by somebody else who left our team.
#Component
#Scope("request")
#Path("/abc/hello/v1")
public class ClientService {
// ... some variables
#GET
#Path("/json/line")
#Produces(MediaType.APPLICATION_JSON)
public ClientResponse getLineData(#Context UriInfo uriInfo) {
}
}
What is the best way to design version v2 url here? Should I just make a new class and have #Path as #Path("/abc/hello/v2") like this and copy paste everything in it? Or should I create some abstract class and have ClientServiceV1 extend that abstract class and then have ClientServiceV2 extend that abstract class as well? How should I proceed?

My strategy for versioning REST API is to not let JAX-RS runtime automatically determine what REST resources to load and instead explicitly state them in the java.ws.rs.Application implementation.
My java.ws.rs.Application implementation is where I do the versioning and I state it there the base API URI
#javax.ws.rs.ApplicationPath("v1")
public class MyAppV1 extends java.ws.rs.Application {
Set<Class<?>> getClasses() {
return new java.util.HashSet<>(java.util.Arrays.asList(
ClientService.class,
OtherService.class));
}
}
And then create another one for "v2" where I start adding my components there.
The intent of it is I can have multiple versions present and I can deprecate the old ones and eventually remove them as needed. It also allows me to reuse the existing services.
However, if your existing services are suffixed with "v1" then you may want to either duplicate the code or make it point to the new version depending on your needs.

Related

How is Errai able to serialize/deserialize model entities

I'm trying to use Errai rest capabilities in my GWT app,
I took a look at the following guide:
http://errai-blog.blogspot.it/2011/10/jax-rs-in-gwt-with-errai.html
In particular, it says:
We simply put this interface somewhere in our client packages (e.g.
client.shared) where the GWT compiler can find it. To create a request
all that needs to be done is to invoke RestClient.create()
I think there's a plot hole here, how is Errai able to know how serialize/deserialize model classes ?
Can you help understanfing this ?
thanks
According to RestClient Class's create() method
public static <T, R> T create(final Class<T> remoteService, final RemoteCallback<R> callback, Integer... successCodes) {
return create(remoteService, null, callback, null, successCodes);
}
In example which you've provided; when using create() method Errai gets the CustomerService Class as remoteService, After many operations;
Errai parses and implements this CustomerService Interface with using their errai-codegen library which uses Java Reflection API.
When parsing simply;
First it looks for JAX-RS annotated methods and defines them as
JaxrsResourceMethod
Then it looks into parameters of that method if there is any parameter that annontated with JAX-RS annotations.
If it finds annontated parameters in JaxrsResourceMethod, it keeps that parameter with it's annotation type
If it finds not annontated parameter in JaxrsResourceMethod it defines as a entityParameter
Errai holds these annotated parameter and entityParameters in JaxrsResourceMethodParameters by their method. When building request it uses parameters by their rule.
Let me explain these rules with using an example you've provided.
Customer customer = new Customer("new name", "new last name", "new postal code");
RestClient.create(CustomerService.class, callback).updateCustomer(240193, customer);
Errai will create url like
example.com/cusomers/240193
Because #PathParam("id") annotation rule is adding parameter to the url and according to Errai's entityParameter rule customer will be marshalled when sending data with PUT.
#PUT
#Path("/{id}")
#Consumes("application/json")
#Produces("application/json")
public Customer updateCustomer(#PathParam("id") long id, Customer customer); //- See more at: http://errai-blog.blogspot.com.tr/2011/10/jax-rs-in-gwt-with-errai.html#sthash.2GTQtIg8.dpuf
One more additional note if you check here there is an exception in setEntityParameter method;
Only one non-annotated entity parameter allowed per method:
This means you cant define methods with more than 1 non-annotated parameter in Class which you sent in Errai.

Will JAX-RS/Jersey resource paths honor inheritance?

Say I want the following URLs exposed by my JAX-RS/Jersey app:
http://myapp.example.com/app/fizz
http://myapp.example.com/app/buzz
http://myapp.example.com/app/foo
http://myapp.example.com/app/bar
Say I want /app to be a parent base resource, and /app/* to be "child" resources. Will the following accomplish the URL strategy I'm looking for (?):
#Path('/app')
#Produces(MediaType.APPLICATION_JSON)
public abstract class AppResource {
// Whatever...
}
#Path('/fizz') // <--- right here, will FizzResource live at /app/fizz?
#Produces(MediaType.APPLICATION_JSON)
public class FizzResource extends AppResource {
// Whatever...
}
Will the FizzResource be exposed at /app/fizz or just /fizz?
Will the FizzResource be exposed at /app/fizz or just /fizz?
Short answer
FizzResource will be exposed at /fizz.
Long answer
Quoting the JSR 339 (section 3.6 about Annotation Inheritance):
If a subclass or implementation method has any JAX-RS annotations then
all of the annotations on the superclass or interface method are
ignored.
The specification also says:
For consistency with other Java EE specifications, it is recommended to always repeat annotations instead of relying on annotation inheritance.
Creating sub-resources
The JAX-RS/Jersey documentation explains how to create sub-resources:
#Path may be used on classes and such classes are referred to as root resource classes.
#Path may also be used on methods of root resource classes. This enables common functionality for a number of resources to be grouped together and potentially reused.
The first way #Path may be used is on resource methods and such methods are referred to as sub-resource methods.
So, do the following to create sub-resources:
#Path("/app")
public class YourHandler {
#Produces(MediaType.APPLICATION_JSON)
public String yourHandlerForApp() {
// This method is be exposed at /app
}
#Path("/fizz")
#Produces(MediaType.APPLICATION_JSON)
public String yourHandlerForAppSlashFizz() {
// This method is be exposed at /app/fizz
}
}
I don't think the answers given are the best for the original problem statement.
He wants to have his subresources in separate classes. That's understandable and admirable because to not do that would mean putting all his endpoints in the same class, which would be huge.
If all endpoints on this port start with /app then I think the best way to do that is to configure your filter to put it in your #ApplicationPath.
If it's not the case that all endpoints start with the same prefix, then you will have to use this style of JAX-RS subresources where you specify a #Path but not an HTTP method annotation (#GET, etc.) and return an instance of the resource you want to delegate to:
#Path("/app")
public class AppResource {
#Context UriInfo uriInfo;
#Path("fizz")
public FizzResource getItemContentResource() {
return new FizzResource ();
}
}
#Produces(MediaType.APPLICATION_JSON)
public class FizzResource extends AppResource {
// Whatever...
}
This method of doing resources is provided in the JAX-RS documentation.
You can also have all your subresources declare their Paths as
#Path(BASE_URL + "/fizz")
Where BASE_URL is a static string, but I would try to avoid that because the use of a not-exactly constant parameter to #Path seems to cause every JAX-RS IDE plugin I've seen problems. They aren't able to compute the actual path, so they give up. So you might lose the ability to have a "JAX-RS View" that allows you to visualize/navigate your JAX-RS resources by the Paths.
What you want is
#Path("/app")
public class YourHandler {
#Path('/')
#Produces(MediaType.APPLICATION_JSON)
public String yourHandlerForApp() {
// Whatever...
}
#Path('/fizz') // <--- right here, will FizzResource live at /app/fizz?
#Produces(MediaType.APPLICATION_JSON)
public String yourHandlerForAppSlashFizz() {
// Whatever...
}
}

Multiple #Path's in JAX-RS

Background: I asked another question (here: Performance degradation after moving to jersey 2) about jersey performance. I also opened an issue in jersey Jira. Apparently, there is a known performance problem with sub-resources in jersey 2.
My data model based on entity A, with several sub-entities. However, the ID of the sub entities is unique, and the server allows to access them directly. For example,
/server/As/{a_id}/Bs/{b_id} == /server/Bs/{b_id}
We're using sub-resources for that, so the same resource (B) is both a spring component and a member of A resource. All the resources are spring beans, so both Bs are the same instance.
Now I'm trying to workaround this problem by not using sub-resources at all. I found out that #Path does not support multiple paths. Is there any idea how to solve it?
I tried the following, does it make sense? Can you offer alternatives? I'm asking because I'll have to do the same trick many times (for entities C, D, E etc. and maybe additional level of resources)
First, I removed B reference from A resource class, then:
public abstract class AbstractB {
#GET
#Path({b_id})
#Produce(MediaType.APPLICATION_JSON)
public Response getB(#PathParam("b_id") String bId) {
...
}
...
}
#Component
#Path ("As/{a_id}/Bs")
public class B extends AbstractB{/* empty */}
#Component
#Path ("Bs")
public class AsB extends AbstractB{/* empty */}
Edit: (by peeskillet) - Link to issue

jax-rs : For a same #Path method returning Json, how to serialize differently per device type

In short:
I'd like to return different JSONs, with say less attributes, when a request comes from a phone than when it comes from a desktop pc.
I want to build a REST service.
The service will serve data based on JPA entities.
The service is declared with #Path.
Depending on the User-Agent header, I want to serve a richer JSON for desktop than for mobile devices. Selection to be done serverside.
Is there a better way than to build a second serializer and use a condition (if(request useragent ) to call them (in every method) and be forced to return some String instead of any Object (making #Produces annotation unused).
Thank you
One way it to add a PathParam or QueryParam to the Path to tell the device type in the request, so the service can be able to understand the type of device, from which the request is and create the appropriate JSON.
Please check the most voted SO answer to find out whether the request is from mobile or desktop and add the parameter accordingly
You can use jax-rs resource selector, which will use different sub-resource depending on user-agent string.
#Path("api")
public UserResource getResourceByUserAgent() {
//the if statement will be more sophisticated obviously :-)
if(userAgent.contains("GT-I9505") {
return new HighEndUserResource();
} else {
return new LowEndUserResource();
}
}
interface UserResource {User doSomeProcessing()}
class HighEndUserResource implements UserResource {
#Path("process")
public User doSomeProcessing() {
//serve
}
}
class LowEndUserResource implements UserResource {
#Path("process")
public User doSomeProcessing() {
//serve content for low end
}
}
By invoking "/api/process" resource the response will depend on userAgent. You can also easily extend the solution for other devices, and implement MiddleEndUserResource for example.
You can read more information about sub-resources here:

Should a dto implement an associated interface?

Should a bean dto always have an associated interface ?
Below dto is used by jackson to send json over the wire :
public class Bean {
private String date;
public Bean(String date)
{
this.link = date;
}
public String getDate() {
return date;
}
}
Should this class always implement an interface to match its structure ?
I wouldn't unless you're using an API or Framework that requires an interface or are writing an API yourself.
Older versions of J2EE (before it became Java EE) required interfaces for enterprise beans, and some other frameworks use an interface to generate a proxy; however that has mostly been replaced by the runtime generation of synthetic proxies. If you start with a well defined class, you can later add an interface you discover a need for one.
Currently one of my tasks is maintaining an existing web application. Essentially everything in it has the Interface + Class pattern, but for no real reason as its all self contained. The extra files for the interfaces just clutter up the workspace and make tracking down the source of the actual code take a couple seconds longer in each case (can't just highlight and press F3 in Eclipse).

Categories