Play 2 doesn't call provided action method in Global's onRequest - java

I'm trying to call different action methods depending on something I put in the session earlier. For this I override the onRequest method in Global like it's recommended in Play's tutorial. I use Java reflection to construct a new method with the same name and parameters but in a different class B. Class B and and the original class with the original actionMethod implement the same interface. So there shouldn't be a problem.
My onRequest in Global looks like:
#Override
public Action onRequest(Request request, final Method actionMethod) {
if (checkSomething) {
return super.onRequest(request, getNewActionMethod(actionMethod));
}
return super.onRequest(request, actionMethod);
}
private Method getNewActionMethod(Method oldActionMethod) {
String name = oldActionMethod.getName();
Class<?>[] parameterTypes = oldActionMethod.getParameterTypes();
Method newActionMethod = null;
try {
newActionMethod = B.class.getMethod(name, parameterTypes);
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newActionMethod;
}
The Problem here is that Play just ignores my new action method and keeps insisting to call the old one. Am I missing something?
I'm using Play framework 2.2.3.

Related

Mocking local object of a method and reading from it

I am using powermckito and trying to mock a local object and read a API from it. My implementation class is as below:
public class LogoutUtil {
public static void updateState() {
SrvcContext sc = new SrvcContext();
sc.setUserName("UserNAME");
}
}
I am trying to mock the SrvcContext object and read the user name by calling getter.
Here is my test code:
#Test
public void updateStateTest() {
SrvcContext svc = PowerMockito.mock(SrvcContext.class);
LogoutUtil.updateState();
try {
PowerMockito.whenNew(SrvcContext.class).withNoArguments().thenReturn(svc);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String userName = svc.getUserName(); //This gives null
Assert.assertEquals("UserNAME", userName);
}
Any help how to do it. I cant change the LogoutUtil class.
Thanks
The problem is that the method LogoutUtil.updateState is static and testing and mocking static methods is not always straightforward.
But with PowerMockito you can do it by calling mockStatic method: have a look here: it should solve your issue

Checking if class is proxified with CDI 1.2

In CDI 1.2 there is a way to check if a class instance is proxified? I need this because I need to get the name of original class, not the proxy name.
#Inject Bean bean;
public void sysout() {
// will print something like com.Bean$$Weld9239823
System.out.println(bean.getClass());
// I don't know how to check if the bean instance if a proxy or real class instance
}
Using Weld classes I can do this job:
public void sysout() {
// will print true because this is a proxy
System.out.println(ProxyObject.class.isAssignableFrom(bean));
// will print com.Bean
System.out.println(((TargetInstanceProxy) bean).getTargetInstance());
}
In CDI 1.1 there is no method to do this. I search inside CDI 1.2 docs if a method was added about this, but I don't found anything.
So... I miss something and CDI 1.2 there is a method to get original class name and instance? Or if not, there is a plain to add this feature in near feature?
For Weld on WildFly do this:
public boolean isProxy(Object obj) {
try{
return Class.forName("org.jboss.weld.bean.proxy.ProxyObject").isInstance(obj);
} catch (Exception e) {
log.error("Unable to check if object is proxy", e);
}
return false;
}
To retrive actual object instead of proxy (I need to serialize it) I do this:
public Object getObject(Object obj) {
Field f = null;
boolean isAccessible = false;
try {
for(Field fi : Class.forName(handler).getDeclaredFields()) {
if(fi.getName().equals(field)) {
f = fi;
isAccessible = f.isAccessible();
f.setAccessible(true);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
if(f == null) {
throw new RuntimeException(new NoSuchFieldException(String.format(
"The required field '%s' not found in '%s'. " +
"May be the code is obsolete for running on this application server.",
field, method)));
} else {
try{
obj = f.get(getHandler(obj));
for(Method m : Class.forName(instance).getMethods()) {
if(m.getName().equals(value)) {
return m.invoke(obj);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
f.setAccessible(isAccessible);
}
throw new NoSuchMethodError(String.format(
"The required method '%s' not found in '%s'. " +
"May be the code is obsolete for running on this application server.",
value, instance));
}
}
Be aware, that it is the darkest magic as possible, have very poor performance and can break at any WildFly update, if they change classes, methods for fields in it.
This is a terrible hack, but for Weld (and possibly other implementations) you can check if the class name contains "Proxy": possibleProxy.getClass().getSimpleName().contains("Proxy"). I use it only for logging purposes to get a cleaned up version of the wrapped class name:
/**
* Get the actual simple name of the objects class that might be wrapped by
* a proxy. A "simple" class name is not fully qualified (no package name).
*
* #param possibleProxy an object that might be a proxy to the actual
* object.
* #return the simple name of the actual object's class
*/
public static String getActualSimpleClassName(final Object possibleProxy) {
final String outerClassName = possibleProxy.getClass().getSimpleName();
final String innerClassName;
if (outerClassName.contains("Proxy")) {
innerClassName = outerClassName.substring(0, outerClassName.indexOf('$'));
} else {
innerClassName = outerClassName;
}
return innerClassName;
}
you can make a method inside your proxied cdi bean like
public String getClassName() {
return this.getClass().getName();
}
this is not the best solution, but a simple pragmatic way to get the class name through the proxy... the downside of this is that the method must be on every implementation...

Determine what JAVA-EE application module called intercepted method

Lets say we have a few modules in our application:
REST API
WEB
CORE
DAO
For all methods in CORE we have EJB #Interceptor defined. Is it possible to determine what module is calling method in CORE?
Example: I have a method CORE.methodThatHasInterceptor()
Than I call it from WEB.unknownMethod(){ CORE.methodThatHasInterceptor() }
It goes to interceptor of methodThatHasInterceptor method:
#AroundInvoke
public Object interceptor(InvocationContext invocCtx) throws Exception {
// is it possible to know that it was called from WEB.unknownMethod() ?
}
The javadoc of InvocationContext is quite informative on that subject:
http://docs.oracle.com/javaee/6/api/javax/interceptor/InvocationContext.html
I'll quote the example code right at the top:
#AroundInvoke
public Object logInvocation(InvocationContext ctx) throws Exception {
String class = ctx.getMethod().getDeclaringClass().getName();
String method = ctx.getMethod().getName();
Logger.global.entering(class, method, ctx.getParameters());
try {
Object result = ctx.proceed();
Logger.global.exiting(class, method, result);
return result;
}
catch (Exception e) {
Logger.global.throwing(class, method, e);
throw e;
}
}

Event handling with Java Reflection

Ok so, this is quite confusing to explain. I will try my best.
Inspired by the Bukkit Event System where you can make voids an event handler by just using #EventHandler.
Example:
#EventHandler
public void aRandomName(PlayerMoveEvent ev) {
}
As you can see, the name of the method doesn't matter. Which event is passed on is determined by the event argument type.
All events extend the Event class.
I have made up some code which I think would work, except for one thing.
public List<Object> eventContainers;
public void fireEvent(Event e) {
Method[] methods;
for (Object o : eventContainers) {
Object[] classes = o.getClass().getClasses();
for (Object clss : classes) {
methods = clss.getClass().getMethods();
for (Method m : methods) {
if (m.getAnnotation(EventHandler.class) != null) {
try {
Class[] requiredTypes = m.getParameterTypes();
for(Class cl : requiredTypes) {
if(e.equals(cl)) {
m.invoke(clss, e);
}
}
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (InvocationTargetException ex) {
}
}
}
}
}
}
What my code does:
Loops through all the classes in eventContainers, looks for methods that have the #EventHandler annotation and sends the specified event to that method. However, I want to see what kind of event the given event in fireEvent(Event e) is, and then look at the methods who require an event parameter of that kind. How would I do that? I figure that
Class[] requiredTypes = m.getParameterTypes();
for(Class cl : requiredTypes) {
if(e.equals(cl)) {
m.invoke(clss, e);
}
}
will not work.
Ultimately I want to be able to pass on events to plugins. Like this:
EventManager.fireEvent(new PlayerMoveEvent(player));
Which will be sent to all plugins and the plugins that have
#EventHandler
public void aVoid(PlayerMoveEvent e) {
//stuff
}
If you have any questions, I will try to explain it better. Thanks in advance for your help!
Your code uses e.equals(cl), which is comparing an instance of Event with an instance of Class (the class of an instance of Event) - this will never return true. What you want to do instead is:
if(e.getClass().equals(cl)) {
m.invoke(clss, e);
}
Alternatively, if you want methods annotated with #EventHandler to handle all subclasses of the class that their method signature defines (i.e. a method like handle(Event e) would be called with PlayerMoveEvents as well as all other events), then you want:
if(cl.isAssignableFrom(e.getClass())) {
m.invoke(clss, e);
}
See the Class Javadoc here for more information.
Note that I think there are a few other problems in you code. For example, Method.invoke should be called with an instance of the class that contains a method that is annotated with #EventHandler. It is a little unclear from your code, but I believe this should therefore be:
m.invoke(o, e);
Also, by calling o.getClass().getClasses(), you are iterating over the classes defined in the class of o - you probably want to iterate over the methods of the class of o directly, i.e.:
for (Method m : o.getClass().getMethods()) {
if (m.getAnnotation(EventHandler.class) != null) {
Class[] requiredTypes = m.getParameterTypes();
if (requiredTypes.length == 1 && requiredTypes[0].isAssignableFrom(e.getClass()) {
m.invoke(o, e);
}
}
}
You can get the parameter types from a Method using method.getGenericParameterTypes(), so:
m.invoke(clss, m.getGenericParameterTypes()[0].class.cast(e));
Not sure if that's what you want.
Assuming the EventHandler annotated method only has one parameter
Method[] methods = YourClass.class.getDeclaredMethods();
Object yourInstance = null; // get it
Event e = null; // get it
for (Method method : methods) {
EventHandler handler = method.getAnnotation(EventHandler.class);
if (handler != null) {
Class<?>[] parameterTypes = method.getParameterTypes();
// you're going to need different logic if you have more than one parameter
if (parameterTypes.length == 1 && parameterTypes[0].isAssignableFrom(e.getClass())) {
method.invoke(yourInstance, e);
}
}
}
I've not included any exception handling.
Get all the methods of event handler candidate classes and iterate over them. If a method has the #EventHandler annotation, get its parameter type list. If it only has one parameter and that type is assignable from your event type e.getClass(), then invoke it passing in your event.
I have now modified the code to a working event system!!!!!! :D thanks so much andersschuller!
public void fireEvent(Event e) {
Method[] methods;
for (Object o : eventContainers) {
methods = o.getClass().getMethods();
for (Method m : methods) {
if (m.getAnnotation(EventHandler.class) != null) {
try {
if (m.getParameterTypes()[0].isAssignableFrom(e.getClass())) {
m.invoke(o, e);
}
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (InvocationTargetException ex) {
}
}
}
}
}
I kept all answers in mind, thanks all!

Why is there no InputManager.getInstance() for me? And injectInputEvent()?

I'm trying to develop a service that injects touch events to the system while the service interacts with some hardware/remote server. I've googled and everyone suggests using the InputManager class, referencing Monkey as an example project to follow.
However, there is no getInstance() method for me in InputManager! All I have access to is exactly what the documentation shows. No getInstance() method, and most importantly, no injectInputEvent() method.
My build target SDK is Android 4.1.2, and my AndroidManifest.xml file specifies a target SDK version of 16 (I've tried changing the min target to 16 too, which didn't help (plus I'd like to keep it at 8 if possible)).
How on earth can I use InputManager like Monkey does? Where are the methods Monkey is using, and why can't I use them?
You cannot inject input events to one application from other application. Also you cannot inject events to your own application from within application. https://groups.google.com/forum/?fromgroups=#!topic/android-developers/N5R9rMJjgzk%5B1-25%5D
If you want to automate, you can use monkeyrunner scripts to do the same.
Class cl = InputManager.class;
try {
Method method = cl.getMethod("getInstance");
Object result = method.invoke(cl);
InputManager im = (InputManager) result;
method = cl.getMethod("injectInputEvent", InputEvent.class, int.class);
method.invoke(im, event, 2);
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Maybe this is a bit late but could be helpful for future reference.
Method 1: Using an instrumentation object
Instrumentation instrumentation = new Instrumentation();
instrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
instrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
Method 2: Using internal APIs with reflection
This method uses reflection to access internal APIs.
private void injectInputEvent(KeyEvent event) {
try {
getInjectInputEvent().invoke(getInputManager(), event, 2);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
}
private static Method getInjectInputEvent() throws NoSuchMethodException {
Class<InputManager> cl = InputManager.class;
Method method = cl.getDeclaredMethod("injectInputEvent", InputEvent.class, int.class);
method.setAccessible(true);
return method;
}
private static InputManager getInputManager() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<InputManager> cl = InputManager.class;
Method method = cl.getDeclaredMethod("getInstance");
method.setAccessible(true);
return (InputManager) method.invoke(cl);
}
injectInputEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
injectInputEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
Please note that method 1 is a clean solution based on public API and internally it uses the same calls from method 2.
Also note that neither of this two methods can be invoked from the MainThread.

Categories

Resources