I'm developing an app with Jersey where I have many resources. Although main functionality of these resources varies, they share lots of common methods (like list, read, update and etc). The app runs on Google App Engine and uses Guice for dependency injection.
My first approach was to have a generic AbstactResource which contains all common logic, and it's respectively extended by all other resources which add their required custom methods.
public class AbstractResource<T> {
@GET
public ListPage<T> list(@QueryParam("limit") Integer limit,
@QueryParam("start") Integer start) {
// ... implementation
}
@GET
@Path("/{id}")
public T get(@PathParam("id") Long id) {
// ... implementation
}
And sample resource looks like:
public class TenantResource extends AbstractResource<Tenant> {
// custom resource related methods here
}
Everything works fine in this case. The problems appear when I add one more level of abstraction. Let's say if I want to store history and changelogs only for some of my resources. I've created one more abstract class extending AbstractResource called AudiatableResource which adds the required functionality.
public abstract class AuditableResource<T extends AuditableModel>
extends AbstractResource {
// here I override update and create methods to save changelogs
}
As you see the type parameter in this case has changed (now it extends AuditableModel).
New concrete resources will look like:
public class PropertyResource extends AuditableResource<Tenant> {
// custom resource related methods here
}
In this case everything still works, but this time I'm getting lots of warning messages on start-up:
WARNING: Return type T of method public T com.pkg.AbstractResource.get(java.lang.Long) is not resolvable to a concrete type
WARNING: Return type T of method public T com.pkg.AbstractResource.getNew() is not resolvable to a concrete type
WARNING: Return type com.pkg.data.ListPage<T> of method public com.pkg.ListPage<T> com.pkg.AbstractResource.list(java.lang.Integer,java.lang.Integer) is not resolvable to a concrete type
I really wonder if this approach is correct using Jersey and if I can just ignore this messages. It would be interesting to know how resources are organized in cases when there are large number of them.
One way to go is to separate the definition of the resources from the implementation.
The reason you get those messages at runtime is that jersey uses runtime information about types in the resource. Generic type information being erased at compile time, it cannot get the actual return type of the generic class methods. If you provide a REST "facade" to your implementation, you can make this explicit.
public class Facade {
private final PropertyResource propertyResource;
public Facade() {
propertyResource = new PropertyResource();
}
@GET
@Path("somepath")
public Tenant something() {
return propertyResource.something();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With