I have a use-case where the return behaviour of the callee method should change based on the annotation of the caller method.
Here is the situation:
#SomeAnnotation
public void caller(){
return SomeOtherClass.caller(String arg);
}
// Returns X in this case
public class SomeOtherClass{
public String callee(String arg){
if(annotationIsPresent(SomeAnnotation.class))
return "X";
else
return "Y";
}
}
I went through some resources and I found this.
I was thinking of using Thread.currentThread().getStackTrace() to get the current invoker method.
I have no clue if this is feasible or is a correct design also. Could someone please comment on it?
Adding code:
Annotation
#Retention(RetentionPolicy.RUNTIME)
public #interface SomeAnnotation {
}
Caller class
#SomeAnnotation
public class Caller {
#SomeAnnotation
public static void caller(){
System.out.println(new Callee().callee());
}
}
Callee
public class Callee {
public String callee(){
String className = Thread.currentThread().getStackTrace()[2].getClassName();
String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
try {
Class<?> klass = Class.forName(className);
Method method = klass.getMethod(methodName);
if(klass.isAnnotationPresent(SomeAnnotation.class))
System.out.println("HELLO");
if(method.isAnnotationPresent(SomeAnnotation.class))
System.out.println("HELLOW");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Main class
public class Main {
public static void main(String[] args){
Caller.caller();
}
}
Related
When I search for the method by reflection it shows the newly provided method. But I don't know how to invoke that method, if someone has got any idea how to do it please tell me.
//some pakage
pakage xyz;
class A {
// a simple method of class A
public void aMethod() {
//simple print statement
System.out.println("A class method");
}
}
class B {
// a method of class B that takes A types as an argument
public void bMethod(A arg) {
Class c = Class.forName("xyz.A");
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
}
}
class Test {
public static void main(String[] args) {
B bObj = new B();
bObj.bMethod(new A() {
public void anotherMethod() {
System.out.println("another method");
}
});
}
}
I suppose maybe this is what you want.
package xyz;
import java.lang.reflect.Method;
class A {
// a simple method of class A
public void aMethod() {
//simple print statement
System.out.println("A class method");
}
}
class B {
// a method of class B that takes A types as an argument
public void bMethod(A arg) throws Exception {
Class c = Class.forName(arg.getClass().getName());
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
method.invoke(arg);
}
}
}
class Test {
public static void main(String[] args) throws Exception {
B bObj = new B();
bObj.bMethod(new A() {
public void anotherMethod() {
System.out.println("another method");
}
});
}
}
You can use reflection to invoke the method on particular object:
public void invokeSomeMethodOnA(A arg, String methodName) {
Method method = arg.getClass().getDeclaredMethod(methodName);
//To invoke the method:
method.invoke(arg, parameters here);
}
I'm trying to spot, using reflection, the 'init' method that is annotaded with the #Override annotation (or with whatever annotation), but ok, heres my example, much simplified, ofcourse
Base class:
public abstract class A
{
public void init()
{
}
}
Then here the subclass:
public class B extends A
{
String bla;
#Override
public void init()
{
}
public void init(String bla)
{
this.bla=bla;
}
}
So the code i run to get the annotated method is this:
public static void main(String[] args)
{
ClassLoader c = Main.class.getClassLoader();
try
{
Class<?> clazz = c.loadClass("correct.path.to.class.B");
for (Method method : clazz.getDeclaredMethods())
{
if (method.getName().equals("init"))
{
System.out.println(method.getDeclaredAnnotations().length);
}
}
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
Both methods are correctly found but surprisingly, i get '0' twice when reading the length of the arrays containing the annotations, any idea whats wrong here?
The method getAnnotation() gives me the same results
Check the documentation for #Override and RetentionPolicy. Basically, the #Override annotation is not available at runtime, it's a source only annotation.
http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/RetentionPolicy.html
http://docs.oracle.com/javase/7/docs/api/java/lang/Override.html
I want my method "themethod" is referencing "foo", then in a static block, try to get the method "foo" with "getMethod", to which I pass the name of the method and type of the parameters, but "foo "receives as a parameter a type generic, then I know not to give to work.
Code:
public class Clazz<T>
{
static Method theMethod;
static
{
try
{
Class<Clazz> c = Clazz.class;
theMethod = c.getMethod( "foo", T.class ); // "T.class" Don't work!
}
catch ( Exception e )
{
}
}
public static <T> void foo ( T element )
{
// do something
}
}
How do I make "theMethod" referencing a method called 'foo'?
Something like this?
import java.lang.reflect.Method
public class Clazz<T>
{
static Method theMethod;
static Class<T> type;
public Clazz(Class<T> type) {
this.type = type;
this.theMethod = type.getMethod("toString");
}
}
System.out.println(new Clazz(String.class).theMethod);
Gives
public java.lang.String java.lang.String.toString()
This should work in the most cases:
public class Clazz<T> {
static Method theMethod;
static {
try {
Class<Clazz> c = Clazz.class;
theMethod = c.getDeclaredMethod("foo", Object.class);
} catch(Exception e) {}
}
public static <T> void foo(T element) {
// do whatever
}
}
I've created two enum classes as singleton:
public enum A {
INSTANCE;
public void init(param p1, param p2) {
}
public void connect() {
}
public void disconnect() {
}
public bool isConnected() {
}
}
public enum B {
INSTANCE;
public void init(param p1) {
}
public void connect() {
}
public void disconnect() {
}
public bool isConnected() {
}
}
As you can see both enum classes are very similar so I was wondering if I should create some kind of base abstract class/enum or interface and then have these two enums extend or implement from it.
UPDATE 1: I'd like to put some shared member variables on the base class
UPDATE 2: Should I just change the way I'm defining the singleton?
As per java enum tutorial
All enums implicitly extend java.lang.Enum. Since Java does not
support multiple inheritance, an enum cannot extend anything else.
Here is interesting SO discussion related to this topic.
As Nambari stated you can't have an enum extend anything. However what they neglected to say is you CAN have an enum implement an interface, which is done as with a class using the implements keyword. I've done this at work and it's very useful in the right situation! There's an example here: http://javahowto.blogspot.co.uk/2008/04/java-enum-examples.html
There is a sweet little class called a DynamicObjectAdapterFactory posted by Heinz Kabutz which uses generics and reflection to adapt an object to implement an interface by providing it with a source class that already implements the interface.
Using it like below you can wrap your INSTANCE in a proxy. Of course the resulting object is no longer an enum but it does retain all of the singletonness of the enum I think. It also, obviously - can use any object to implement your interface.
I think this is as close as you will get to an enum extending a class.
Here's some test code that seems to work. Obviously the object is no longer an enum but as your aim was a singleton this may be acceptable.
public class Test {
// To implement this.
public interface Implement {
public void init();
public void connect();
public void disconnect();
public boolean isConnected();
}
// An implementor that does implement.
public static class Implements implements Implement {
#Override
public void init() {
}
#Override
public void connect() {
}
#Override
public void disconnect() {
}
#Override
public boolean isConnected() {
return false;
}
}
// Extend the INSTANCE in this.
public enum Extend {
INSTANCE;
// Hold my adapted version - thus still a singleton.
public final Implement adaptedInstance;
Extend () {
// Use the constructor to adapt the instance.
adaptedInstance = DynamicObjectAdapterFactory.adapt(this, Implement.class, new Implements());
}
}
// Provides an INSTANCE that has been extended by an Implements to implement Implement.
public static Implement getInstance () {
return Extend.INSTANCE.adaptedInstance;
}
public void test() {
System.out.println("Hello");
Implement i = getInstance();
}
public static void main(String args[]) {
new Test().test();
}
}
Here's the DynamicObjectAdapterFactory - I've tweaked it a little from the original - I hope Dr. Kabutz does not object.
public class DynamicObjectAdapterFactory {
// Use methods in adaptee unless they exist in target in which case use adapter.
// Implement target in passing.
public static <T> T adapt(final Object adaptee,
final Class<T> target,
final Object adapter) {
return (T) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{target},
new InvocationHandler() {
private final String name =
adaptee.getClass().getSimpleName() + "(" + adaptee.toString() + ")"
+ "+" + adapter.getClass().getSimpleName() + "(" + adapter.toString() + ")";
// The methods I wish to adapt.
private Map<MethodIdentifier, Method> adaptedMethods = new HashMap<>();
{
// initializer block - find all methods in adapter object
Method[] methods = adapter.getClass().getDeclaredMethods();
for (Method m : methods) {
// Keep a map of them.
adaptedMethods.put(new MethodIdentifier(m), m);
}
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// Has it been adapted?
Method otherMethod = adaptedMethods.get(new MethodIdentifier(method));
if (otherMethod != null) {
return otherMethod.invoke(adapter, args);
} else {
return method.invoke(adaptee, args);
}
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
#Override
public String toString() {
StringBuilder s = new StringBuilder();
// Really simple. May get more flexible later.
s.append("Adapted: ").append(name);
return s.toString();
}
});
}
private static class MethodIdentifier {
private final String name;
private final Class[] parameters;
public MethodIdentifier(Method m) {
name = m.getName();
parameters = m.getParameterTypes();
}
#Override
public boolean equals(Object o) {
// I am always equal to me.
if (this == o) {
return true;
}
// I cannot be equal to something of a different type.
if (!(o instanceof MethodIdentifier)) {
return false;
}
MethodIdentifier mid = (MethodIdentifier) o;
return name.equals(mid.name) && Arrays.equals(parameters, mid.parameters);
}
#Override
public int hashCode() {
return name.hashCode();
}
}
}
You can use the abstract class below for singleton instead of enum.
public abstract class AbstractSingleton {
private static Map<String, AbstractSingleton> registryMap = new HashMap<String, AbstractSingleton>();
AbstractSingleton() throws SingletonException {
String clazzName = this.getClass().getName();
if (registryMap.containsKey(clazzName)) {
throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
} else {
synchronized (registryMap) {
if (registryMap.containsKey(clazzName)) {
throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
} else {
registryMap.put(clazzName, this);
}
}
}
}
#SuppressWarnings("unchecked")
public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz) throws InstantiationException, IllegalAccessException {
String clazzName = clazz.getName();
if (!registryMap.containsKey(clazzName)) {
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
T instance = clazz.newInstance();
return instance;
}
}
}
return (T) registryMap.get(clazzName);
}
public static AbstractSingleton getInstance(final String clazzName)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
if (!registryMap.containsKey(clazzName)) {
Class<? extends AbstractSingleton> clazz = Class.forName(clazzName).asSubclass(AbstractSingleton.class);
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
AbstractSingleton instance = clazz.newInstance();
return instance;
}
}
}
return registryMap.get(clazzName);
}
#SuppressWarnings("unchecked")
public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz, Class<?>[] parameterTypes, Object[] initargs)
throws SecurityException, NoSuchMethodException, IllegalArgumentException,
InvocationTargetException, InstantiationException, IllegalAccessException {
String clazzName = clazz.getName();
if (!registryMap.containsKey(clazzName)) {
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
Constructor<T> constructor = clazz.getConstructor(parameterTypes);
T instance = constructor.newInstance(initargs);
return instance;
}
}
}
return (T) registryMap.get(clazzName);
}
static class SingletonException extends Exception {
private static final long serialVersionUID = -8633183690442262445L;
private SingletonException(String message) {
super(message);
}
}
}
From: https://www.cnblogs.com/wang9192/p/3975748.html
I have the following code
public abstract class Event {
public void fire(Object... args) {
// tell the event handler that if there are free resources it should call
// doEventStuff(args)
}
// this is not correct, but I basically want to be able to define a generic
// return type and be able to pass generic arguments. (T... args) would also
// be ok
public abstract <T, V> V doEventStuff(T args);
}
public class A extends Event {
// This is what I want to do
#Overide
public String doEventStuff(String str) {
if(str == "foo") {
return "bar";
} else {
return "fail";
}
}
}
somewhere() {
EventHandler eh = new EventHandler();
Event a = new A();
eh.add(a);
System.out.println(a.fire("foo")); //output is bar
}
However I don't know how to do this, as I cannot override doEventStuff with something specific.
Does anyone know how to do this?
It's not really clear what you're trying to do, but perhaps you just need to make Event itself generic:
public abstract class Event<T, V>
{
public abstract V doEventStuff(T args);
}
public class A extends Event<String, String>
{
#Override public String doEventStuff(String str)
{
...
}
}
You're using generics but you are not providing a binding.
public abstract class Event<I, O> { // <-- I is input O is Output
public abstract O doEventStuff(I args);
}
public class A extends Event<String, String> { // <-- binding in the impl.
#Override
public String doEventStuff(String str) {
}
}
Or simpler with only one generic binding...
public abstract class Event<T> { // <-- only one provided
public abstract T doEventStuff(T args);
}
public class A extends Event<String> { // <-- binding the impl.
#Override
public String doEventStuff(String str) {
}
}