How to create chain of dynamic proxies? - java

I create two InvocationHandler, one for logging purpose and the other one for measuring time. Each on works but I do not know how to create a chain of these two, so that both will be executed. I thought it would be enough that for example the LoggingInvocationHandler extends the TimerInvocationHandler
public class DynamicProxyMain {
public static void main(String[] args) {
System.out.println("Starting dynamic proxy sample");
SubjectInterface timerProxy = (SubjectInterface) Proxy.newProxyInstance(SubjectInterface.class.getClassLoader(),
new Class<?>[]{SubjectInterface.class},
new TimerInvocationHandler(new SubjectInterfaceImpl()));
SubjectInterface logginProxy = (SubjectInterface) Proxy.newProxyInstance(SubjectInterface.class.getClassLoader(),
new Class<?>[]{SubjectInterface.class},
new LoggingInvocationHandler(new SubjectInterfaceImpl()));
timerProxy.methodA("a");
timerProxy.methodB("test b");
timerProxy.methodC(1, "test c");
}
}
public class LoggingInvocationHandler implements InvocationHandler {
Object impl;
String CLASSNAME = this.getClass().getCanonicalName();
public LoggingInvocationHandler(Object impl){
this.impl = impl;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object retVal;
System.out.println("LoggingHandler:" + this.getClass().getName() + " has been called");
retVal = method.invoke(impl, args);
System.out.println("LoggingHandler:" + this.getClass().getName() + " has ended");
return retVal;
}
}
public class TimerInvocationHandler extends LoggingInvocationHandler implements InvocationHandler{
private Object impl;
public TimerInvocationHandler(Object impl) {
super(impl);
this.impl = impl;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object retVal = null;
System.out.println("getting duration time for method " + method.getName());
long duration = -System.currentTimeMillis();
retVal = super.invoke(proxy,method,args);
duration += System.currentTimeMillis();
System.out.println("it took " + duration + " milliseconds");
System.out.println("duration time handler has ended");
return retVal;
}
}
Actually I solved it, so that both InvocationHandlers will be called. I edited my post with the currently working code

The idea bears a similarity to Intercepting Filter, I'll give your an implementation of it, which slightly modified in order to work with DynamicProxyHandler, if you're interested and want more details, you should read the link thoroughly.
Participants:
InvocationChain - which is responsible for dispatching invocations.
Invocation - where you should put things like logging and timer.
DynamicProxyHanlder - that simply delegates the request to InvocationChain.
Implementaiton:
DynamicProxyHandler.java
public class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
InvocationChain chain = new InvocationChainImp();
DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return chain.invoke(proxied, method, args);
}
}
Invocation.java
public interface Invocation {
Object invoke(Object callee, Method method, Object[] args, InvocationChain chain);
}
InvocationChain.java
public interface InvocationChain {
public Object invoke(Object callee, Method method, Object[] args);
}
InvocationChainImp.java
public class InvocationChainImp implements InvocationChain {
List<Invocation> list = new ArrayList<>();
Object result;
Iterator<Invocation> tasks;
InvocationChainImp() {
list.add(new LoggingInvocation());
list.add(new TimerInvocation());
list.add(new FinalInvocation());
tasks = list.iterator();
}
#Override
public Object invoke(Object callee, Method method, Object[] args) {
if (tasks.hasNext()) {
Object result = tasks.next().invoke(callee, method, args, this);
this.result = (this.result == null ? result : this.result);
}
return this.result;
}
Last not least, we want to define some custom classes that must be confined to Invocation interface for logging, timer, etc.
LoggingInvocation.java
public class LoggingInvocation implements Invocation {
#Override
public Object invoke(Object callee, Method method, Object[] args, InvocationChain chain) {
chain.invoke(callee, method, args);
Logger.getLogger(this.getClass().getCanonicalName()).info(method.getName() + "() execution logged!");
return null;
}
}
TimerInvocation.java
public class TimerInvocation implements Invocation {
#Override
public Object invoke(Object callee, Method method, Object[] args, InvocationChain chain) {
long start_time = System.nanoTime();
chain.invoke(callee, method, args);
long end_time = System.nanoTime();
System.out.println("Timer: excution took " + (end_time - start_time) / 1e6 + "ms");
return null;
}
}
FinalInvocation.java where the request is finally invoked on the proxied instance.
public class FinalInvocation implements Invocation {
#Override
public Object invoke(Object callee, Method method, Object[] args, InvocationChain chain) {
try {
return method.invoke(callee, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
Rest of code is trivial, as it's just used to prove that the implementation works.
You can stop reading now if want to write your own.
SubjectInterface.java
public interface SubjectInterface {
String hello();
}
SubjectInterfaceImp.java
public class SubjectInterfaceImp implements SubjectInterface {
#Override
public String hello() {
System.out.println("in SubjectInterfaceImp: Greeting!");
return "hello";
}
}
Main.java
public class Main {
public static void main(String[] args) throws Exception {
SubjectInterface subject = (SubjectInterface) Proxy.newProxyInstance(
SubjectInterface.class.getClassLoader(),
new Class[] { SubjectInterface.class }, new DynamicProxyHandler(new SubjectInterfaceImp()));
System.out.println("in Main: subject.hello() = " + subject.hello());
}
}
Okay, we have enough of code, it's show time, let's see we got, voila!
in SubjectInterfaceImp: Greeting!
Timer: excution took 0.532198ms
九月 02, 2016 12:37:36 下午 LoggingInvocation invoke
信息: hello() execution logged!
in Main: subject.hello() = hello

This is not the natural way to implement it.TimerInvocationHandler has nothing to do with LoggingInvocationHandler.
define a decorator which is a InvocationHandler and wraps a another InovovationHandler
https://en.wikipedia.org/wiki/Decorator_pattern
EDIT: since one comment ask me to provide a sample implementation,following part is added, but this is the not exact decorator pattern, but i think others can understand the solution. in this case TimeInvocationHandler is not limited to measure the login time
public class TimerInvocationHandler implements InvocationHandler
{
protected InvocationHandler invocationHandler;
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
//do whatever you want
Object result = invocationHandler.invoke(proxy, method, args);
// do what ever you want
return result;
}
}

Related

I am having trouble in using jdk dynamic proxy

Before using spring aop and cglib, Now I replaced a simple example.I found that executing method sayHello1 () and sayHello2 () both output "before" and "after" Oh my god, it's very difficult, Do you understand what I am talking about? I am going crazy now. T.T
public interface HelloWorld {
void sayHello1(String say);
void sayHello2(String say);
}
public static class HelloWorldImpl implements HelloWorld {
#Override
public void sayHello1(String say) { System.out.println(say); }
#Override
public void sayHello2(String say) { System.out.println(say); }
}
public static class Invocation implements InvocationHandler {
private final Object target;
public Invocation(Object target) { this.target = target; }
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before..."); // TODO method before
Object object = method.invoke(target, args);
System.out.println("after..."); // TODO method after
return object;
}
}
public static void main(String[] args) {
HelloWorld helloWorld = (HelloWorld) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[] { HelloWorld.class },
new Invocation(new HelloWorldImpl())
);
helloWorld.sayHello1("Hello World1 ...");
helloWorld.sayHello2("Hello World2 ...");
}
You mean you want something like this?
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Instrumenting " + method);
Object result;
switch (method.getName()) {
case "sayHello1":
System.out.println("before A");
result = method.invoke(target, args);
System.out.println("after A");
break;
case "sayHello2":
System.out.println("before B");
// Let's change the argument just for fun
args[0] = "changed argument";
result = method.invoke(target, args);
System.out.println("after B");
break;
default:
result = method.invoke(target, args);
}
return result;
}
That would yield the following console log:
Instrumenting public abstract void de.scrum_master.spring.q62001911.HelloWorld.sayHello1(java.lang.String)
before A
Hello World1 ...
after A
Instrumenting public abstract void de.scrum_master.spring.q62001911.HelloWorld.sayHello2(java.lang.String)
before B
changed argument
after B
Of course you could print further information or differentiate overloaded methods with the same names by parameter types. Try things like
method.getParameterTypes();
method.getParameterCount();
method.getReturnType();
Is this tedious? Yeah, it is, but still straightforward. And it being tedious is the reason why AspectJ or Spring AOP with their elegant pointcut + advice model are so much easier to use because they did the work already and hide the inner complexity from you.

In Java Proxy, if i use an Object's method (like toString()),why it's method.invoke(this),not method.invoke(proxy) or other

In some code,like Mybatis,I saw the use of JDK-proxy.
Example:
org.apache.ibatis.logging.jdbc.ConnectionLogger:
public final class ConnectionLogger extends BaseJdbcLogger implements InvocationHandler {
#Override
public Object invoke(Object proxy, Method method, Object[] params)
throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, params);
}
}
...
}
}
Maybe my code like this :
UserMapper user = getProxy(UserMapper.class);
user.hashCode()
If i use the method like hashCode() , it means i want to get the hashCode from the user, not user's Proxy.hashCode(), not invocationHandler.hashCode().And I really try to change the method like this,it happens an error:
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(proxy, params);
}
But why use 'this'(is this means an object from ConnectionLogger ?)
Please tell me ,and sorry for my English ;)
You guessed right. The proxy address refers to the invocationhandler. Here is the test
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
System.out.println(this);
System.out.println(Integer.toHexString(System.identityHashCode(this)));
System.out.println(Integer.toHexString(System.identityHashCode(proxy)));
return method.invoke(this, args);
}
return "ddd";
}
public static void main(String[] args) {
InsertDataHandler c =new InsertDataHandler();
Object L=c.getProxy();
// L.toString();
System.out.println(L.toString());
}
E:\xzb\jdk\bin\java.exe
com.example.tenant.InsertDataHandler#728938a9
728938a9
21b8d17c
com.example.tenant.InsertDataHandler#728938a9

Java - Execute a class method with a specify annotation

I have a android application, but it is not relevant.
I have a class called "Front controller" which will receive some message
through it's constructor. The message, for brievity, could be an integer.
I want somewhere else to create a new controller which will execute
a method based on the integer defined above
public class OtherController {
#MessageId("100")
public void doSomething(){
//execute this code
}
#MessageId("101")
public void doSomethingElse(){
//code
}
}
The front controller could be something like this:
public class FrontController {
private int id;
public FrontController(int id){
this.id=id;
executeProperControllerMethodBasedOnId();
}
public void executeProperControllerMethodBasedOnId(){
//code here
}
public int getId(){
return id;
}
}
So, if the Front Controller will receive the integer 100, it
will execute the method annotated with #MessageId(100). The
front controller don't know exactly the class where this method
is.
The problem which I found is that I need to register somehow
each controller class. I Spring I had #Component or #Controller
for autoloading. After each controllers are register, I need to
call the properly annotated method.
How to achieve this task? In Spring MVC, I had this system
implemented, used to match the HTTP routes. How could I implement
this in a plain java project?
Any suggestions?
Thanks to Google Reflections (hope you can integrate this in your android project.)
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections-maven</artifactId>
<version>0.9.8</version>
</dependency>
For optimisation I've added the requirement to also annotate the class with MessageType annotation and the classes should be in the same package (org.conffusion in my example):
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MessageType {
}
The OtherController looks like:
#MessageType
public class OtherController {
#MessageId(id=101)
public void method1()
{
System.out.println("executing method1");
}
#MessageId(id=102)
public void method2()
{
System.out.println("executing method2");
}
}
The implementation will look like:
public void executeProperControllerMethodBasedOnId() {
Set<Class<?>> classes = new org.reflections.Reflections("org.conffusion")
.getTypesAnnotatedWith(MessageType.class);
System.out.println("found classes " + classes.size());
for (Class<?> c : classes) {
for (Method m : c.getMethods()) {
try {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object o = c.newInstance();
if (mid.id() == id)
m.invoke(o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Maybe you can optimise and build a static hashmap containing already scanned message ids.
You need to implement some of the work by yourself using reflection, I would recommend to prepare message handlers on initial phase in regards to performance. Also you possibly want to think about Singleton/Per Request controllers. Some of the ways to implement the solution:
interface MessageProcessor {
void execute() throws Exception;
}
/* Holds single instance and method to invoke */
class SingletonProcessor implements MessageProcessor {
private final Object instance;
private final Method method;
SingletonProcessor(Object instance, Method method) {
this.instance = instance;
this.method = method;
}
public void execute() throws Exception {
method.invoke(instance);
}
}
/* Create instance and invoke the method on execute */
class PerRequestProcessor implements MessageProcessor {
private final Class clazz;
private final Method method;
PerRequestProcessor(Class clazz, Method method) {
this.clazz = clazz;
this.method = method;
}
public void execute() throws Exception {
Object instance = clazz.newInstance();
method.invoke(instance);
}
}
/* Dummy controllers */
class PerRequestController {
#MessageId(1)
public void handleMessage1(){System.out.println(this + " - Message1");}
}
class SingletonController {
#MessageId(2)
public void handleMessage2(){System.out.println(this + " - Message2");}
}
class FrontController {
private static final Map<Integer, MessageProcessor> processors = new HashMap<Integer, MessageProcessor>();
static {
try {
// register your controllers
// also you can scan for annotated controllers as suggested by Conffusion
registerPerRequestController(PerRequestController.class);
registerSingletonController(SingletonController.class);
} catch (Exception e) {
throw new ExceptionInInitializerError();
}
}
private static void registerPerRequestController(Class aClass) {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
processors.put(mid.value(), new PerRequestProcessor(aClass, m));
}
}
}
private static void registerSingletonController(Class aClass) throws Exception {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object instance = aClass.newInstance();
processors.put(mid.value(), new SingletonProcessor(instance, m));
}
}
}
/* To process the message you just need to look up processor and execute */
public void processMessage(int id) throws Exception {
if (processors.containsKey(id)) {
processors.get(id).execute();
} else {
System.err.print("Processor not found for message " + id);
}
}
}

Java reflection: implement interface and pass to another class

I'm not sure if this is possible with Java, but I'm trying to implement an interface that's unavailable at compile time** and pass it to another class as an object of that interface. Let's say I have an interface like:
public interface MyInterface {
void onReceive(int i);
}
and another class like:
public void MyClass {
ArrayList<MyInterface> listenerList = new ArrayList<MyInterface>();
public void add(MyInterface m) {
listenerList.add(m);
}
}
If they were available at compile time, I would be using them like:
blah = new MyInterface() {
public void onReceive(int i) {
System.out.println("BLAH");
}
}
MyClass mc = new MyClass();
myClass.add(blah);
I'm wondering if there is a way to write code that does the same as above if the first two classes are only available at runtime.
Thanks in advance!
**I'm trying to use a framework library from Android's ROM, but it is in dalvik bytecode so I can't use it for compilation.
UPDATE: Here's some sample code I used to test the solution:
File a/IIMSListener.java
// Excerpt from decompiled class
public interface IIMSListener
{
void onReceive(int p0, int p1/*, IMSParameter p2*/);
}
File a/IMSRemoteListenerStub.java
// Excerpt from decompiled class
import java.util.concurrent.*;
import java.util.*;
public class IMSRemoteListenerStub
{
public List<IIMSListener> mListenerList = new CopyOnWriteArrayList<IIMSListener>();
public boolean addListener(final IIMSListener iimsListener) {
if (iimsListener != null && !this.mListenerList.contains(iimsListener)) {
this.mListenerList.add(iimsListener);
return true;
}
return false;
}
public boolean removeListener(final IIMSListener iimsListener) {
if (iimsListener != null && this.mListenerList.contains(iimsListener)) {
this.mListenerList.remove(iimsListener);
return true;
}
return false;
}
}
File b/test.java
import java.lang.reflect.;
import java.util.;
public class test {
public static void main(String[] args) throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException,
NoSuchMethodException,
SecurityException,
ClassNotFoundException {
// Implement interface
Class<?> IIMSListener = Class.forName("IIMSListener");
Object listenerInstance = Proxy.newProxyInstance(IIMSListener.getClassLoader(), new Class<?>[]{IIMSListener}, new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("onReceive")){
System.out.println("ARGS: " + (Integer)args[0] + ", " + (Integer)args[1]);
return 1;
}
else return -1;
}
});
// Test
Method onReceive = listenerInstance.getClass().getDeclaredMethod("onReceive", new Class[] { int.class, int.class });
onReceive.invoke(listenerInstance, new Object[] { 1, 2 });
try {
// Pass to another class
Class IMSRemoteListenerStub = Class.forName("IMSRemoteListenerStub");
Constructor ctor = IMSRemoteListenerStub.getConstructor();
Object stubInstance = ctor.newInstance(new Object[] {});
Method addListener = stubInstance.getClass().getDeclaredMethod("addListener", new Class[] { IIMSListener });
addListener.invoke(stubInstance, new Object[] { listenerInstance });
// Test
Field mListenerList = IMSRemoteListenerStub.getField("mListenerList");
List<?> list = (List<?>)mListenerList.get(stubInstance);
onReceive.invoke(list.get(0), new Object[] { 3, 4 });
}
catch (InstantiationException e) {}
catch (NoSuchFieldException e) {}
}
}
Execution:
$ cd b
$ CLASSPATH=".:../a" java test
ARGS: 1, 2
ARGS: 3, 4
If it is going to be same interface then use Dynamic Proxies
//Loading the class at runtime
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
Class<?> someInterface = Class.forName("SomeInterface");
Object instance = Proxy.newProxyInstance(someInterface.getClassLoader(), new Class<?>[]{someInterface}, new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Handle the invocations
if(method.getName().equals("someMethod")){
return 1;
}
else return -1;
}
});
System.out.println(instance.getClass().getDeclaredMethod("someMethod", (Class<?>[])null).invoke(instance, new Object[]{}));
}

Callback functions in Java

Is there a way to pass a call back function in a Java method?
The behavior I'm trying to mimic is a .Net Delegate being passed to a function.
I've seen people suggesting creating a separate object but that seems overkill, however I am aware that sometimes overkill is the only way to do things.
If you mean somthing like .NET anonymous delegate, I think Java's anonymous class can be used as well.
public class Main {
public interface Visitor{
int doJob(int a, int b);
}
public static void main(String[] args) {
Visitor adder = new Visitor(){
public int doJob(int a, int b) {
return a + b;
}
};
Visitor multiplier = new Visitor(){
public int doJob(int a, int b) {
return a*b;
}
};
System.out.println(adder.doJob(10, 20));
System.out.println(multiplier.doJob(10, 20));
}
}
Since Java 8, there are lambda and method references:
Oracle Docs: Lambda Expressions
Oracle Docs: Method References
For example, if you want a functional interface A -> B, you can use:
import java.util.function.Function;
public MyClass {
public static String applyFunction(String name, Function<String,String> function){
return function.apply(name);
}
}
And here is how you can call it:
MyClass.applyFunction("42", str -> "the answer is: " + str);
// returns "the answer is: 42"
Also you can pass class method. For example:
#Value // lombok
public class PrefixAppender {
private String prefix;
public String addPrefix(String suffix){
return prefix +":"+suffix;
}
}
Then you can do:
PrefixAppender prefixAppender= new PrefixAppender("prefix");
MyClass.applyFunction("some text", prefixAppender::addPrefix);
// returns "prefix:some text"
Note:
Here I used the functional interface Function<A,B>, but there are many others in the package java.util.function. Most notable ones are
Supplier: void -> A
Consumer: A -> void
BiConsumer: (A,B) -> void
Function: A -> B
BiFunction: (A,B) -> C
and many others that specialize on some of the input/output type. Then, if it doesn't provide the one you need, you can create your own FunctionalInterface:
#FunctionalInterface
interface Function3<In1, In2, In3, Out> { // (In1,In2,In3) -> Out
public Out apply(In1 in1, In2 in2, In3 in3);
}
Example of use:
String computeAnswer(Function3<String, Integer, Integer, String> f){
return f.apply("6x9=", 6, 9);
}
computeAnswer((question, a, b) -> question + "42");
// "6*9=42"
And you can also do that with thrown exception:
#FunctionalInterface
interface FallibleFunction<In, Out, Ex extends Exception> {
Out get(In input) throws Ex;
}
public <Ex extends IOException> String yo(FallibleFunction<Integer, String, Ex> f) throws Ex {
return f.get(42);
}
For simplicity, you can use a Runnable:
private void runCallback(Runnable callback)
{
// Run callback
callback.run();
}
Usage:
runCallback(new Runnable()
{
#Override
public void run()
{
// Running callback
}
});
or with Java8 lambdas
runCallback(() -> {
// Running callback
});
yet i see there is most preferred way which was what i was looking for.. it's basically derived from these answers but i had to manipulate it to more more redundant and efficient.. and i think everybody looking for what i come up with
To the point::
first make an Interface that simple
public interface myCallback {
void onSuccess();
void onError(String err);
}
now to make this callback run when ever you wish to do to handle the results - more likely after async call and you wanna run some stuff which depends on these reuslts
// import the Interface class here
public class App {
public static void main(String[] args) {
// call your method
doSomething("list your Params", new myCallback(){
#Override
public void onSuccess() {
// no errors
System.out.println("Done");
}
#Override
public void onError(String err) {
// error happen
System.out.println(err);
}
});
}
private void doSomething(String param, // some params..
myCallback callback) {
// now call onSuccess whenever you want if results are ready
if(results_success)
callback.onSuccess();
else
callback.onError(someError);
}
}
doSomething is the function that takes some time you wanna add a callback to it to notify you when the results came, add the call back interface as a parameter to this method
hope my point is clear, enjoy ;)
A little nitpicking:
I've seem people suggesting creating a
separate object but that seems
overkill
Passing a callback includes creating a separate object in pretty much any OO language, so it can hardly be considered overkill. What you probably mean is that in Java, it requires you to create a separate class, which is more verbose (and more resource-intensive) than in languages with explicit first-class functions or closures. However, anonymous classes at least reduce the verbosity and can be used inline.
This is very easy in Java 8 with lambdas.
public interface Callback {
void callback();
}
public class Main {
public static void main(String[] args) {
methodThatExpectsACallback(() -> System.out.println("I am the callback."));
}
private static void methodThatExpectsACallback(Callback callback){
System.out.println("I am the method.");
callback.callback();
}
}
I found the idea of implementing using the reflect library interesting and came up with this which I think works quite well. The only down side is losing the compile time check that you are passing valid parameters.
public class CallBack {
private String methodName;
private Object scope;
public CallBack(Object scope, String methodName) {
this.methodName = methodName;
this.scope = scope;
}
public Object invoke(Object... parameters) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Method method = scope.getClass().getMethod(methodName, getParameterClasses(parameters));
return method.invoke(scope, parameters);
}
private Class[] getParameterClasses(Object... parameters) {
Class[] classes = new Class[parameters.length];
for (int i=0; i < classes.length; i++) {
classes[i] = parameters[i].getClass();
}
return classes;
}
}
You use it like this
public class CallBackTest {
#Test
public void testCallBack() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
TestClass testClass = new TestClass();
CallBack callBack = new CallBack(testClass, "hello");
callBack.invoke();
callBack.invoke("Fred");
}
public class TestClass {
public void hello() {
System.out.println("Hello World");
}
public void hello(String name) {
System.out.println("Hello " + name);
}
}
}
A method is not (yet) a first-class object in Java; you can't pass a function pointer as a callback. Instead, create an object (which usually implements an interface) that contains the method you need and pass that.
Proposals for closures in Java—which would provide the behavior you are looking for—have been made, but none will be included in the upcoming Java 7 release.
When I need this kind of functionality in Java, I usually use the Observer pattern. It does imply an extra object, but I think it's a clean way to go, and is a widely understood pattern, which helps with code readability.
Check the closures how they have been implemented in the lambdaj library. They actually have a behavior very similar to C# delegates:
http://code.google.com/p/lambdaj/wiki/Closures
You also can do theCallback using the Delegate pattern:
Callback.java
public interface Callback {
void onItemSelected(int position);
}
PagerActivity.java
public class PagerActivity implements Callback {
CustomPagerAdapter mPagerAdapter;
public PagerActivity() {
mPagerAdapter = new CustomPagerAdapter(this);
}
#Override
public void onItemSelected(int position) {
// Do something
System.out.println("Item " + postion + " selected")
}
}
CustomPagerAdapter.java
public class CustomPagerAdapter {
private static final int DEFAULT_POSITION = 1;
public CustomPagerAdapter(Callback callback) {
callback.onItemSelected(DEFAULT_POSITION);
}
}
I tried using java.lang.reflect to implement 'callback', here's a sample:
package StackOverflowQ443708_JavaCallBackTest;
import java.lang.reflect.*;
import java.util.concurrent.*;
class MyTimer
{
ExecutorService EXE =
//Executors.newCachedThreadPool ();
Executors.newSingleThreadExecutor ();
public static void PrintLine ()
{
System.out.println ("--------------------------------------------------------------------------------");
}
public void SetTimer (final int timeout, final Object obj, final String methodName, final Object... args)
{
SetTimer (timeout, obj, false, methodName, args);
}
public void SetTimer (final int timeout, final Object obj, final boolean isStatic, final String methodName, final Object... args)
{
Class<?>[] argTypes = null;
if (args != null)
{
argTypes = new Class<?> [args.length];
for (int i=0; i<args.length; i++)
{
argTypes[i] = args[i].getClass ();
}
}
SetTimer (timeout, obj, isStatic, methodName, argTypes, args);
}
public void SetTimer (final int timeout, final Object obj, final String methodName, final Class<?>[] argTypes, final Object... args)
{
SetTimer (timeout, obj, false, methodName, argTypes, args);
}
public void SetTimer (final int timeout, final Object obj, final boolean isStatic, final String methodName, final Class<?>[] argTypes, final Object... args)
{
EXE.execute (
new Runnable()
{
public void run ()
{
Class<?> c;
Method method;
try
{
if (isStatic) c = (Class<?>)obj;
else c = obj.getClass ();
System.out.println ("Wait for " + timeout + " seconds to invoke " + c.getSimpleName () + "::[" + methodName + "]");
TimeUnit.SECONDS.sleep (timeout);
System.out.println ();
System.out.println ("invoking " + c.getSimpleName () + "::[" + methodName + "]...");
PrintLine ();
method = c.getDeclaredMethod (methodName, argTypes);
method.invoke (obj, args);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
PrintLine ();
}
}
}
);
}
public void ShutdownTimer ()
{
EXE.shutdown ();
}
}
public class CallBackTest
{
public void onUserTimeout ()
{
System.out.println ("onUserTimeout");
}
public void onTestEnd ()
{
System.out.println ("onTestEnd");
}
public void NullParameterTest (String sParam, int iParam)
{
System.out.println ("NullParameterTest: String parameter=" + sParam + ", int parameter=" + iParam);
}
public static void main (String[] args)
{
CallBackTest test = new CallBackTest ();
MyTimer timer = new MyTimer ();
timer.SetTimer ((int)(Math.random ()*10), test, "onUserTimeout");
timer.SetTimer ((int)(Math.random ()*10), test, "onTestEnd");
timer.SetTimer ((int)(Math.random ()*10), test, "A-Method-Which-Is-Not-Exists"); // java.lang.NoSuchMethodException
timer.SetTimer ((int)(Math.random ()*10), System.out, "println", "this is an argument of System.out.println() which is called by timer");
timer.SetTimer ((int)(Math.random ()*10), System.class, true, "currentTimeMillis");
timer.SetTimer ((int)(Math.random ()*10), System.class, true, "currentTimeMillis", "Should-Not-Pass-Arguments"); // java.lang.NoSuchMethodException
timer.SetTimer ((int)(Math.random ()*10), String.class, true, "format", "%d %X", 100, 200); // java.lang.NoSuchMethodException
timer.SetTimer ((int)(Math.random ()*10), String.class, true, "format", "%d %X", new Object[]{100, 200});
timer.SetTimer ((int)(Math.random ()*10), test, "NullParameterTest", new Class<?>[]{String.class, int.class}, null, 888);
timer.ShutdownTimer ();
}
}
I've recently started doing something like this:
public class Main {
#FunctionalInterface
public interface NotDotNetDelegate {
int doSomething(int a, int b);
}
public static void main(String[] args) {
// in java 8 (lambdas):
System.out.println(functionThatTakesDelegate((a, b) -> {return a*b;} , 10, 20));
}
public static int functionThatTakesDelegate(NotDotNetDelegate del, int a, int b) {
// ...
return del.doSomething(a, b);
}
}
it's a bit old, but nevertheless... I found the answer of Peter Wilkinson nice except for the fact that it does not work for primitive types like int/Integer.
The problem is the .getClass() for the parameters[i], which returns for instance java.lang.Integer, which on the other hand will not be correctly interpreted by getMethod(methodName,parameters[]) (Java's fault) ...
I combined it with the suggestion of Daniel Spiewak (in his answer to this); steps to success included: catching NoSuchMethodException -> getMethods() -> looking for the matching one by method.getName() -> and then explicitly looping through the list of parameters and applying Daniels solution, such identifying the type matches and the signature matches.
with java 8 this task is kinda easy, if you want to use callback in multi-thread scenario you can do something similar like the following:
public void methodA (int n, IntConsumer consumer) {
// create a thread
Thread t = new Thread(() -> {
// some time consuming operation
int result = IntStream.range(0, n).sum();
// after the result is ready do something with it.
consumer.accept(result);
});
t.start();
}
and to use this method do:
methodA(1000000, System.out::println);
public class HelloWorldAnonymousClasses {
//this is an interface with only one method
interface HelloWorld {
public void printSomething(String something);
}
//this is a simple function called from main()
public void sayHello() {
//this is an object with interface reference followed by the definition of the interface itself
new HelloWorld() {
public void printSomething(String something) {
System.out.println("Hello " + something);
}
}.printSomething("Abhi");
//imagine this as an object which is calling the function'printSomething()"
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp =
new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
//Output is "Hello Abhi"
Basically if you want to make the object of an interface it is
not possible, because interface cannot have objects.
The option is to let some class implement the interface and then call that function using the object of that class.
But this approach is really verbose.
Alternatively, write new HelloWorld() (*oberserve this is an interface not a class) and then follow it up with the defination of the interface methods itself. (*This defination is in reality the anonymous class).
Then you get the object reference through which you can call the method itself.
Create an Interface, and Create the Same Interface Property in Callback Class.
interface dataFetchDelegate {
void didFetchdata(String data);
}
//callback class
public class BackendManager{
public dataFetchDelegate Delegate;
public void getData() {
//Do something, Http calls/ Any other work
Delegate.didFetchdata("this is callbackdata");
}
}
Now in the class where you want to get called back implement the above Created Interface.
and Also Pass "this" Object/Reference of your class to be called back.
public class Main implements dataFetchDelegate
{
public static void main( String[] args )
{
new Main().getDatafromBackend();
}
public void getDatafromBackend() {
BackendManager inc = new BackendManager();
//Pass this object as reference.in this Scenario this is Main Object
inc.Delegate = this;
//make call
inc.getData();
}
//This method is called after task/Code Completion
public void didFetchdata(String callbackData) {
// TODO Auto-generated method stub
System.out.println(callbackData);
}
}
Simpliest and easiest way is by creating a reusable model and trigger.... https://onecompiler.com/java/3wejrcby2?fbclid=IwAR0dHbGDChRUJoCZ3CIDW-JQu7Dz3iYGNGYjxYVCPCWfEqQDogFGTwuOuO8

Categories