I'm trying to implement a RESTful interface for my Play! framework models using a generic wrapper.
I want to use a generic method to call and return each model's respective "find" methods.
private static <T extends GenericModel> void getModel(T model, Params params){
if (params._contains("id")){
renderJSON(model.findById(params.get("id", Long.class)));
}
else{
renderJSON(model.findAll());
}
}
The above method is called as follows, in my controller's GET method according to which model is requested through a particular route:
getModel(new User(), params);
Since the find() methods are actually static methods of the GenericModels class, it should entirely be possible. However, since Play generates the code for each defined model I get this error:
UnsupportedOperationException occured : Please annotate your JPA model with #javax.persistence.Entity annotation.
At least, I think that's why. Is there no way around this? Am I forced to tediously implement the same GET, PUT, UPDATE, DELETE methods for each class?
I think "model.findById" calls the GenericModel.findById static function which is not implemented and generates the exception. It doesn't call the static function enhanced by JPAPlugin at runtime.
I'm not sure it will work but you should try to call directly JPQL function, something like:
private static <T extends GenericModel> void getModel(Class<T> clazz, Params params){
if (params._contains("id")){
renderJSON(JPQL.instance.findById(clazz.getSimpleName(), params.get("id", Long.class)));
}
else{
renderJSON(model.findAll());
}
and call it like the following:
getModel(new User(), User.class, params);
Related
I created a base Spring controller for my latest web app project that I inherit from for all my basic CRUD controllers, called CrudController:
class CrudController<T, K extends Serializable>
T is the Entity type, and K is the key used for that type (pretty much the parameters needed for Spring's CrudRepository). I create a rest controller by extending it, like so:
#RestController
#RequestMapping(path = "/hats")
public class HatController extends CrudController<Hat, Integer> {
}
Everything works great, except for the method that gets the list of items, /hats. With this method, I get a 405 Method Not Allowed. When I look at the logging that was done during startup, I can see that RequestMappingHandlerMapping did not map {[/hats],methods=[GET]} but it did map the other four methods in the controller. Here is the code for the method that isn't being mapped:
#RequestMapping(method = RequestMethod.GET)
public HttpEntity<?> getAll() {
Iterable<T> result = controllerRepository.findAll();
return new ResponseEntity<Object>(result, HttpStatus.OK);
}
After much experimentation, I have discovered that if I add a parameter to the getAll method that is one of the class parameter types, the method will get mapped. Check this very similar code out:
#RequestMapping(method = RequestMethod.GET)
public HttpEntity<?> getAll(K dontuse) {
Iterable<T> result = controllerRepository.findAll();
return new ResponseEntity<Object>(result, HttpStatus.OK);
}
With that small code change, the /find call works fine. I can keep my dummy parameter in there and everything will work, but it smells.
Any ideas? A simplified project that replicates the issue can be found here:
Simple Project
There's currently a bug in Java, see bug reports here and here, where Class#getDeclaredMethods() returns a bridge Method for each inherited method from a superclass declared as package-private. Based on the javadoc, it shouldn't do that.
This confuses Spring MVC's inspection of #Controller annotated classes and handler methods. Going into detail in this answer won't be very useful, but you can look at the code that handles it here.
The simplest solution is to declare your CrudRepository class as public.
public class CrudController<T, K extends Serializable>
I have a utility class for interacting with the Datastore (GAE's in-built Datastore in my case) and it has methods like:
//Class GaeDataUtil
public static <T> Optional<Key<T>> saveEntity(T entity)
(Optional is from the Guava library and Key<T> from Objectify, although I doubt any of this makes a difference.)
I want my (minimal) hierarchy of entities to have a .save() method. So that for:
public class User extends RootEntity
where RootEntity provides:
public Optional<Key<T>> save() {
//Skipping the error-handling.
return GaeDataUtil.saveEntity(this);
}
I can write:
User myUser = new User();
// set some properties
Optional<Key<User>> optKey = myUser.save();
But of course that doesn't work because a call to myUser.save() returns Optional<Key<RootEntity>> not Optional<Key<User>> as I want.
I can avoid this issue by typecasting in User.save() (and Account.save() and Project.save() etc. etc.) and suppressing warnings, but even if there are only (say) 10 entity classes extending RootEntity, that's still a fair bit of boilerplate code to write just to typecast. Also, I think that much of the benefit of having a class hierarchy is lost if I have to write code (however minimal) for every derived class (there will be other, similar methods too).
Is there a better solution to this?
Update: using Java 7.
You will just need to type cast it to the Generic type T in the RootEntity.save() method.
public <T> Optional<Key<T>> save() {
//Skipping the error-handling.
return (Optional<Key<T>> GaeDataUtil.saveEntity(this); // This line will generate a warning.
}
And then when you write,
Optional<Key<User>> optKey = myUser.save();
It will automatically be inferred correctly because of Target Type Inference.
One solution is to parameterize RootEntity something like this:
class RootEntity<Subclass extends RootEntity> {
public Optional<Key<Subclass>> save() {...}
}
Then define your subclass like:
class User extends RootEntity<User> {...}
I've used this pattern before. If there is a slicker solution, I'll be eager to see it. :)
This is what finally worked:
public <T extends RootEntity> Optional<Key<T>> save1() {
#SuppressWarnings("unchecked")
Key<T> key = (Key<T>) ofy().save().entity(this).now();
return Optional.fromNullable(key);
}
Doing this in two steps works (get the Key, then wrap it up in an Optional) --- it let's the Target Type Inference work correctly. Doing it in a single step doesn't:
public <T extends RootEntity> Optional<Key<T>> save2() {
return (Optional<Key<T>>) Optional.fromNullable(ofy().save().entity(this).now());
}
This second form as suggested by #Codebender shows an error (Cannot cast from Optional<Key<RootEntity>> to Optional<Key<T>>), not a warning in Eclipse.
However, the basic idea by #Codebender of using Target Type Inference was sound.
I'm implementing a RESTful service application for TomEE Plus 1.7.1 with Jettison as default json provider. I have several facade classes for my entitiy classes to provide CRUD functionalities for each of them. Service facades have been generated by netbeans.
This is the POST method:
#POST
public void create(Course entity) {
super.create(entity);
}
While using this method (to create a new instance in the database) I got following error:
No message body reader has been found for request class Object, ContentType : application/json.
After several hours of trying, I got it to work: I only had to add another parameter to the method, like that:
#POST
public void create(#Context Context uriInfo, Course entity) {
super.create(entity);
}
I don't understand why I had to add this Context parameter. I don't need the context variable, so actually I would like to remove it...
Does anybody know the reason?
Okay, I think I found the solution:
All my rest services have been implemented as facade classes. The abstract facade (super class of all services) has several methods like:
public void create(T entity) { getEntityManager().persist(entity); }
public void edit(T entity) {getEntityManager().merge(entity);}
These methods are used by the facade classes:
public void create(Course entity) {
super.create(entity);
}
public void edit(#PathParam("id") Integer id, Course entity) {
super.edit(entity);
}
(for better viewing I've removed the annotations here)
The difference between these two methods is, that the edit method has a second parameter "id" and so does not override the edit() method of the super class. But the create() method does only have a single parameter which causes override of the super class method "create()". I don't know why, but cxf is now creating two endpoints:
POST http://localhost:8080/webprog/api/course/ -> void create(Course)
POST http://localhost:8080/webprog/api/course/ -> void create(Object)
This is also the reason why I got it working with a secon parameter: The create() method is not getting overriden anymore.
So what i did now, is simply renaming the method in de super class, to not override them in the facade classes.
by the way: all services classes have been created by netbeans generator... maybe there is a bug in it
Here are some of the pointers
Make sure you have jettison jar in your classpath, CXF automatically registers jettison as json provider.
#Context Context is not mandatory, so if you want to access some context parameters you can add.
For Method create add Media Type #Consumes(MediaType.APPLICATION_JSON)
Finally Check why you are getting No message body reader has been found for request class Object Ideally you should have got No message body reader has been found for request class Course(There might be some issues with your class definations)
I have a generated object that I want to:
Preserve existing functionality of without injecting into the constructor and rewriting every method to call injectedObject.sameMethod().
Add additional functionality to that generated object without modifying the generated object.
add additional functionality to.
For example:
public class GeneratedObject {
public String getThis() { ... }
public String getThat() { ... }
}
public interface ObjectWrapper {
String doThisWithThat();
}
public class ObjectWrapperImpl extends GeneratedObject implements ObjectWrapper {
String doThisWithThat() { ... }
}
However, downcasting is not allowed, what is the proper implementation without rewriting a bunch of redundant code just to wrap the object?
I think decorator pattern may help you: "The decorator pattern can be used to extend (decorate) the functionality of a certain object at run-time, independently of other instances of the same class"
Have you tried aspectj? http://www.eclipse.org/aspectj/doc/next/progguide/semantics-declare.html It's a bit complicated but so is your request.
If you can extract an interface from GeneratedObject, then it would be possible to do this using a dynamic proxy. You would make a proxy which implemented the extracted interface and ObjectWrapper, with an invocation handler which passed all calls to methods in the GeneratedObject interface through to the delegate, and sent the doThisWithThat() calls elsewhere.
Proxies aren't pretty, but the ugliness is at least well-localised.
Suppose you have a generic interface and an implementation:
public interface MyInterface<T> {
void foo(T param);
}
public class MyImplementation<T> implements MyInterface<T> {
void foo(T param) {
}
}
These two types are framework types I provide. In the next step I want allow users to extend that interface as well as redeclare foo(T param) to maybe equip it with further annotations.
public interface MyExtendedInterface extends MyInterface<Bar> {
#Override
void foo(Bar param);
// Further declared methods
}
I create an AOP proxy for the extended interface and intercept especially the calls to furtherly declared methods. As foo(…) is now redeclared in MyExtendedInterface I cannot execute it by simply invoking MethodInvocation.proceed() as the instance of MyImplementation only implements MyInterface.foo(…) and not MyExtendedInterface.foo(…).
So is there a way to get access to the method that declared a method initially? Regarding this example is there a way to find out that foo(Bar param) was declared in MyInterface originally and get access to the accoriding Method instance?
I already tried to scan base class methods to match by name and parameter types but that doesn't work out as generics pop in and MyImplementation.getMethod("foo", Bar.class) obviously throws a NoSuchMethodException. I already know that MyExtendedInterface types MyInterface to Bar. So If I could create some kind of "typed view" on MyImplementation my math algorithm could work out actually.
Additional info:
I create the proxy for the MyExtendedInterface as follows:
ProxyFactory factory = new ProxyFactory();
factory.setTarget(new MyImplementation());
factory.setInterfaces(new Class[] { MyExtendedInterface.class });
factory.addInterceptor(new MyInterceptor(MyExtendedInterface.class));
The interceptor pretty much scans the methods and executes JPA queries for all methods declared in MyExtendedInterface but routes all method invocations of methods declared in MyInterface to the proxy target. This works as long as methods from MyInterface are not redeclared as the target then doesn't implement it anymore.
public class MyInterceptor implements MethodInterceptor {
public Object invoke(final MethodInvocation invocation)
throws Throwable {
// handling of query methods
// else
invocation.proceed();
// ^^ works if not redeclared but not if
}
}
So what I would like to do instead of invocation.proceed() is detect the method that originally declared the one being invoked and invoke that on the target manually.
Okay, here's the solution I came up with: As I know the base class and it generics structure (what T means in this case) as well as MyExtendedInterface types MyInterface to Bar I can scan the base implementation for possible matches as follows (pseudocode):
for all methods {
skip those with non matching name and parameters length;
for all generic parametertypes {
if typename = T then concrete type has to be Bar
...
}
}
I don't need a generic solution in this case so that seems to work.
The whole scenario seems strange. You can't apply AOP declared on MyExtendedInterface to MyImplementation, because it does not implement it.
Second, I don't understand why it matters which interface defines a method, since it is the implementation that the method is invoked on.
Apart from that, you can get all the methods declared by a certain class/interface by getDeclaredMethods(). Then you can iterate on them and find something that matches your criteria (name)