i am trying to invoking method using reflect, here i need to pass generic class "clazz" in the arguments.but i am not to achieve that..
here in example i tried using Class but this is not working
public void log( Class<?> clazz,Throwable throwable, String pattern) {
Method method= CommonsLogger.class.getMethod("info", Class<T>,String.class,Throwable.class);
//try catch removed
}
You can't do like this. This should work,
CommonsLogger.class.getMethod("info", String.class, Throwable.class)
Related
There is a method that deals with Annotations something like
public void getAnnotationValue(ProceedingJoinPoint joinPoint)
{
MethodSignature methodSignature = (MethodSignature) joinPoint.getStaticPart().getSignature();
Method method = methodSignature.getMethod();
Annotation annotation = method.getParameterAnnotations()[0][0];
RequestHeader requestParam = (RequestHeader) annotation;
System.out.println(requestParam.value());
}
I want to convert it into a generic method that accepts joinPoint and Annotation Type something like
getAnnotationValue(joinPoint, RequestHeader);
For which I tried using:
public void getAnnotationValue(ProceedingJoinPoint joinPoint, Class<? extends Annotation> annotationType)
{
MethodSignature methodSignature = (MethodSignature) joinPoint.getStaticPart().getSignature();
Method method = methodSignature.getMethod();
Annotation annotation = method.getParameterAnnotations()[0][0];
annotationType requestParam = (annotationType) annotation;
System.out.println(requestParam.value());
}
But it prompts error stating type unresolved error? How to handle it and pass Annotation Value into that function!!
The "best" thing you could do:
public void foo(Class<? extends java.lang.annotation.Annotation> annotationClass) { ...
There is no specific "type" class for Annotations, but you fall back on ordinary Class objects, and simply express that you expect sub classes of the Annotation base class.
What you want to do just does not work that way. The problem is not the method signature but your wrong understanding of how to use types in Java. In this line ...
annotationType requestParam = (annotationType) annotation;
... you have two errors:
You cannot declare a variable with annotationType requestParam because annotationType is not a class name literal but a variable name. This is a syntax error and the compiler flags it as such.
You cannot use (annotationType) annotation in order to cast for the same reason as in the first case. Java does not work that way, the code is just invalid.
Having said that, later on your code assumes that the captured annotation class has a method value(), which might happen to be true for some annotation classes, but would not work in a generic case. But assuming that method does exist in all cases in which you call the helper method, you could change it to read like this instead:
public void getAnnotationValue(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getStaticPart().getSignature();
Method method = methodSignature.getMethod();
Annotation annotation = method.getParameterAnnotations()[0][0];
Class<? extends Annotation> annotationType = annotation.annotationType();
try {
System.out.println(annotationType.getMethod("value").invoke(annotation));
} catch (Exception e) {
throw new SoftException(e);
}
}
IMO this is very ugly and not good programming. But it compiles and runs. BTW, if the annotation type does not have a value() method, you will see a NoSuchMethodException thrown.
I think you are suffering from the XY problem here. You are not describing which actual problem you want to solve but the way you believe the solution should look like, blinding yourself and others for better ways to solve the problem. Consequently, my sample code probably does not really solve your problem but just makes your ugly solution work somehow. This is not the same as good design.
I have written the following:
public class DataContainer<Data>{
public DataContainer(Class<Data> clazz, String method) throws NoSuchMethodException, SecurityException{
clazz.getMethod(method);
}
}
And so I create my objects this way:
new DataContainer<SomeClass>(SomeClass.class, "get");
But I wanted it to look more like:
public class DataContainer<Data>{
public DataContainer(String method) throws NoSuchMethodException, SecurityException{
Data.getMethod(method);
}
}
And a construct call should look like this:
new DataContainer<SomeClass>("get");
How can I avoid passing the Data class when I construct A DataContainer object? I know Data can't be manipulated at runtime (new DataContainer<>("get"); -> what is Data then?) but I've heard there are solutions to work around, unfortunately it seems like I haven't the vocab yet to google it.
Also it's a simplified version of my problem, we assume method is valid, public and hasn't arguments.
It's not really possible in the way you want to use your code, due to type erasure.
However, some generic information is preserved at runtime, i.e. when it is accessible to reflection. One such situation would be generics on the class hierarchy, i.e. you could do something like this (which we do quite frequently):
//Note that I used T instead of Data to reduce confusion
//Data looks a lot like an actual class name
public abstract class DataContainer<T>{
public DataContainer(String method) throws NoSuchMethodException, SecurityException {
Class<?> actualClass = getActualTypeForT();
//use reflection to get the method from actualClass and call it
}
protected Class<?> getActualTypeForT() {
//get the generic boundary here, for details check http://www.artima.com/weblogs/viewpost.jsp?thread=208860
}
}
//A concrete subclass to provide the actual type of T for reflection, can be mostly empty
public class SomeClassContainer extends DataContainer<SomeClass> {
//constructor etc.
}
Something similar should be possible for class fields or parameters, although I didn't test that.
public class RestResponseDTO<T extends Object> {
private T result;
}
code where I am initializing this:
public RestResponseDTO getObject(String url,Class clz){
Class cv = clz.getClass();
RestResponseDTO<cv> restResponseDTO =restTemplate.getForObject(url,RestResponseDTO.class);
return restResponseDTO;
}
How can I initalize RestResponseDTO in my getObject function depending upon the clz type?
ps- getForObject is spring restTemplate's standard function- http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java.lang.String-java.lang.Class-java.lang.Object...-
You can add method like this:
void init(Class clazz) {
//you initializing logic
}
and call it
RestResponseDTO<cv> restResponseDTO =restTemplate.getForObject(url,RestResponseDTO.class);
restResponseDTO.init(clz);
return restResponseDTO;
PS: Your cv variable will always have same value.
Please try:
ResponseEntity responseEntity = restTemplate.getForObject(url,RestResponseDTO.class);
and
responseEntity.getBody()
will give you Object T.
You can not pass a class with generic parameter to a method that has the parametertype Class<?>, you need something like Type.
One way (the only i am aware of) around is: create a concrete type that includes the generic parameter.
class IntegerResponse extends RestResponse<Integer>{
...
}
That way you can pass IntegerResponse.class
I have a problem using the invoke method in java.
I have a method to use to provide me a Method object and it looks like:
public static Method provideMethod(String methodName, Class targetClass) throws NoSuchMethodException {
Method method = targetClass.getDeclaredMethod(methodName,null);
//Set accessible provide a way to access private methods too
method.setAccessible(true);
return method;
}
Ok this method works perfectly when I'm trying to access methods, from any context (static, or non static), that have no arguments.
Now the problem is that I can't call invoke and pass arguments to a method that have arguments, for instance:
I have the following method :
private static boolean createDirectory(String path, String fileName) {
...
}
And I want to invoke it like this:
Boolean created = (Boolean) DataUtils.provideMethod("createDirectory", FileUtils.class).
invoke(null, String.class, String.class);
But I'm getting java.lang.NoSuchMethodException: createDirectory [].
Does somebody knows how can I invoke a private static method that have parameters ?
And, how can I pass values to that methods arguments?
Thanks,
Arkde
You're explicitly calling a reflection method which looks for a method declared with the given parameter types - but you're not providing any parameter types.
If you want to find any method with the given name, use getDeclaredMethods() and just filter by name... but then when you call invoke, you need to provide the string values, not the parameter types.
Alternatively, change your provideMethod call to also accept the parameter types, so you can use:
DataUtils.provideMethod("createDirectory", FileUtils.class,
String.class, String.class)
.invoke(null, "foo", "bar")
You're specifically only looking up methods with no arguments when you call
Method method = targetClass.getDeclaredMethod(methodName,null)
In order to find the createDirectory method, you'd need to call
targetClass.getDeclaredMethod("createDirectory", String.class, String.class)
but at present your provideMethod method has no way of doing this.
I would suggest that you change the signature of provideMethod so that it allows the caller to pass in the classes of the arguments that they're looking for, like so:
public static Method provideMethod(String methodName, Class targetClass, Class... parameterTypes) throws NoSuchMethodException {
Method method = targetClass.getDeclaredMethod(methodName, parameterTypes);
//Set accessible provide a way to access private methods too
method.setAccessible(true);
return method;
}
Change this
Method method = targetClass.getDeclaredMethod(methodName, null);
to something like that
Method method = targetClass.getDeclaredMethod(methodName, Class<?>... parameterTypes);
and your provideMethod accordingly.
How can I find out through reflection what is the string name of the method?
For example given:
class Car{
public void getFoo(){
}
}
I want to get the string "getFoo", something like the following:
Car.getFoo.toString() == "getFoo" // TRUE
You can get the String like this:
Car.class.getDeclaredMethods()[0].getName();
This is for the case of a single method in your class. If you want to iterate through all the declared methods, you'll have to iterate through the array returned by Car.class.getDeclaredMethods():
for (Method method : Car.class.getDeclaredMethods()) {
String name = method.getName();
}
You should use getDeclaredMethods() if you want to view all of them, getMethods() will return only public methods.
And finally, if you want to see the name of the method, which is executing at the moment, you should use this code:
Thread.currentThread().getStackTrace()[1].getMethodName();
This will get a stack trace for the current thread and return the name of the method on its top.
Since methods aren't objects themselves, they don't have direct properties (like you would expect with first-class functions in languages like JavaScript).
The closest you can do is call Car.class.getMethods()
Car.class is a Class object which you can use to invoke any of the reflection methods.
However, as far as I know, a method is not able to identify itself.
So, you want to get the name of the currently executing method? Here's a somewhat ugly way to do that:
Exception e = new Exception();
e.fillInStackTrace();
String methodName = e.getStackTrace()[0].getMethodName();
Look into this thread:
Getting the name of the currently executing method
It offers some more solutions - for example:
String name = new Object(){}.getClass().getEnclosingMethod().getName();
With Java 8, you can do this with a few lines of code (almost) without any additional libraries. The key is to convert your method into a serialisable lambda expression. Therefore, you can just define a simple interface like this:
#FunctionalInterface
public interface SerializableFunction<I, O> extends Function<I, O>, Serializable {
// Combined interface for Function and Serializable
}
Now, we need to convert our lambda expression into a SerializedLambda object. Apparently, Oracle does not really want us to do that, so take this with a grain of salt... As the required method is private, we need to invoke it using reflections:
private static final <T> String nameOf(SerializableFunction<T, ?> lambda) {
Method findMethod = ReflectionUtils.findMethod(lambda.getClass(), "writeReplace");
findMethod.setAccessible(true);
SerializedLambda invokeMethod = (SerializedLambda) ReflectionUtils.invokeMethod(findMethod, lambda);
return invokeMethod.getImplMethodName();
}
I'm using Springs ReflectionUtils class here for simplicity, but you can of course replace this by manually looping through all superclasses and use getDeclaredMethod to find the writeReplace method.
And this is it already, now you can use it like this:
#Test
public void testNameOf() throws Throwable {
assertEquals("getName", nameOf(MyClassTest::getName));
}
I haven't checked this with Java 9s module system, so as a little disclaimer it might be more tricky to do this with more recent Java versions...
try this,
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
Wait, since you already know the method name, can't you just type it as a string?
Instead of (pseudo) Class.methodName.toString(), just use "methodName".
Otherwise you can use Class#getDeclaredMethods() to get all the methods in a class