Is there a way to get a method object without having to use the Method's name to grab it?
For example I have the class:
class Car {
public String drive();
public String giveUp();
public String fillUp();
}
I would like to create a Map<String, Method> of methods (aka: ("move", drive()), ("name", giveUp()), ....).
I'm not able to get the method object via name due to obfuscation being used. Is there a way to grab the method name without having to bind this?
I guess another way of asking this is:
For a class you have getClass(), is there an equivalent for methods? I'm looking for something allong the lines of giveUp.Method.
There is no such construct as Car.giveUp.method() in Java, because methods are not "first-class citizens" like classes and objects.
Without knowing what the obfuscator does to your code, or adding additional information, you cannot distinguish the methods, because apart from their name, they have the same signature.
Some obfuscators produce text files that map the original name to the obfuscated name, and you could use that map file to identify the obfuscated method at runtime.
You could add an annotation to the method, like
#MappedMethod("move")
public String drive();
with a self-written annotation #MappedMethod and a default attribute of type String. Then use reflection to get all methods and their annotations, and use the annotation value as key.
You can use Reflection to get all the methods.
Class<Car> clazz = Car.class;
Method[] methods = clazz.getDeclaredMethods();
Them you iterate over methods and map them:
for(Method method: methods)
map.put( method.getName(), method);
Related
Currently, I have a number of nested classes inside an outer class. Each nested class has an overriden toString method. My goal is to iterate through these nested classes to access the value returned by the overriden toString without initializing every single nested class. I've tried iterating through the array returned by Class#getDeclaredClasses
The simplified outer class:
class MyClass {
static class NestedClassOne {
#Override
public String toString() {return "One";}
}
static class NestedClassTwo {
#Override
public String toString() {return "Two";}
}
}
The method I've tried, using the Class#getDeclaredClasses array:
for (Class<?> NestedClass : MyClass.class.getDeclaredClasses()) {
System.out.println(NestedClass.toString());
}
This method, to my dismay, only prints the following:
class ... MyClass$NestedClassTwo
class ... MyClass$NestedClassOne
Your toString() is invoked directly on the class object. I.e., it calls Class<T>.toString() not NestedClassOne.toString(). For that you need to use reflection:
Class<NestedClassOne> clazz = NestedClassOne.class;
Method method = clazz.getMethod( "toString" );
NestedClassOne obj = clazz.newInstance();
Object result = method.invoke( obj );
System.out.println( result );
I'll repeat my comments however:
This sounds like a bad idea. You really shouldn't be using reflection like this. An enum or something similar would likely be a better fit.
It's just kind of obviously super brittle. It throws numerous exceptions, which enums won't. If the code structure changes at all (changing to a different constructor for example) it breaks. If the method name changes, the compiler can't detect it. Etc. I wouldn't want to maintain code that works the way you are asking for.
My goal is to 1) iterate through these nested classes to 2) access the value returned by the overridden toString without initializing every single nested class.
The first part you are doing. The second part is not possible.
The toString() methods you are trying to call are instance methods.
You can't call an instance method until you have created an instance.
You can't create an instance of a class without triggering1 the static initialization of the class.
What your attempted code is actually doing is calling the toString() method on the Class objects. That gives you the names of the classes.
#markspace's answer shows how to create an instance and call the toString() method via reflection. The caveats are that it assumes that each class has a no-args constructor, and that creating the instances doesn't have undesirable side-effects.
1 - There are scenarios involving classes with cyclic dependencies where an instance of a class may be created before its static initialization has completed.
I agree with #markspace's comments. I'm not sure what the real purpose of this is, but there is likely to be a better (more robust) way than calling toString() methods. (For example ... using a custom annotation with runtime retention.)
Even if there isn't, the constraint of not initializing the classes seems artificial to me: is this a premature optimization?
I'm writing a custom API using Reflection to save Objects to file. I have the following class structure:
#Constructor
public XYZPOJO(#Key(key = "word") String word, #Key(key = "variations") ArrayList<String> varList) {
this.word = word;
this.varList = varList;
}
String word;
ArrayList<String> varList = new ArrayList<String>();
#Key(key = "word")
public String getWord() {
return word;
}
#Key(key = "variations")
public ArrayList<String> getVarList() {
return varList;
}
When saving Object to file, my program retrieves each method annotated with #Key, invokes method and saves invoked value to file using the value of #Key as the property name. Later, when I want to construct instance of Object it will search for constructor annotated with #Constructor and then retrieve value of #Key of each parameter in constructor and retrieve value of key (property) from file.
My main issue is that for every field I want to persist I need to duplicate the #Key annotation (and value) before each method and before the corresponding parameter in constructor. Moreover, if both the constructor/method annotation do not match exactly it will fail to instantiate Object. It is very easy to accidentally copy the wrong values.
Is there a way to define each #Key just once?
I was thinking of adding #Key just once before each field I wish to persist however I believe (please correct me if I'm wrong) that I would no longer be able to instantiate class via constructor (I believe I would need to instantiate class by directly setting value of each field via reflection, thereby circumventing constructor, correct?). However, this is not ideal since the constructor performs certain necessary functions before the class is instantiated.
What other solution(s) are there?
Thanks!
You could do that like every other library for serialization (or just switch to one of these libraries, as they all support everything you do), so possible solutions:
Skip annotation by default and just use name of getter (like getMoney -> money) and use annotation only in constructor. And on getter if you want to use other name in serialized form. Additionally you can look for field with same name to check annotations on it too, but it's optional and not needed.
Annotate only parameters in constructor but allow to set both name and property name (by default you can assume that name == property unless someone provided both values) And later you can change it to getter method name, like that money -> getMoney (just add get and make first letter upper case)
Apply 1st idea but also use parameter names from constructor that are available in runtime if someone compiles code with -parameters flag. And then you don't need any annotation, unless you want to use different name in serialized form, then just add annotation to only field/getter.
Note:
Typical libraries just scan for public methods to find properties. So they look for methods that starts with get or is followed by upper case letter, that have no arguments and some return type. As typical data class will look like that.
i need to call a function - (getters and setters of a property), but my problem is, the name of the property is generated at runtime (name of some variable + number).
Is it possible to manipulate the bytecode via javassist or gclib so that the function calls are directed to some proxy object/function, and there the real method name and the number extracted from the called function name, so that i can call the function afterwards (with the number as parameter)?
I tried the following, but it didnt work:
MethodHandler handler = new MethodHandler() {
#Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) {
String realMethodName=thisMethod.substring(0,5);
Integer param=Integer.parseInt(thisMethod.substring(5));
Method m = self.getClass().getMethod(realMethodName);
m.invoke(self,param);
return null;
}
};
I think this might be one of the few scenarios where using Java reflection Proxy objects might come in handy.
You could define some interface, but delegate the method to the (dynamic) invocation handler which would then call those "getter/setter" methods.
Side note: when implementing such an invocation handler you have to understand that ANY method call on the corresponding object will trigger its "invoke" method; event when you call toString or equals or whatever else is inherited from Object.
EDIT: and one more (different) thought: are you sure you need to create dynamic method names at all? If you have some numeric (or string based) key - what not using a Map for example?
Like
Map<WhateverKeyType,YourPropertyClass>
that would be much more "normal java" way of handling your problem (instead of thinking about reflection or byte code manipulation).
If you wanted to implement something similar but could think of using another library than javassist, consider using Byte Buddy (which I wrote, for disclosure).
Considering, you have an interface
interface Foo { Object getProperty() }
that you wanted to implement to access a property of the bean
class Bar { Object getAbc123() { ... } }
Then using Byte Buddy, you could implement a class
Foo accessor = new ByteBuddy()
.subclass(Foo.class)
.method(named("getProperty"))
.intercept(MethodCall.invoke(Bar.class.getDeclaredMethod("getAbc123"))
.on(new Bar()))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded()
.newInstance();
of the interface that redirects the invocation of getProperty to the method of your choosing. With a little bit of customization, you can surely create a more generic solution.
I understand that the following can be done .
User user = new User();
user.setUsername("a");
user.setPassword("abc");
Class c = user.getClass();
However I have a situation in which I have to extract the instance information from the variable "c"
Is it even possible ? . We do have a c.newInstance() method but that would create a new instance of the object User. I need to access the existing instance of the User , which was responsible for creating the "c" variable in the first place .
Thanks
-----------EDIT-----------
Looking at the comments I understood that my concept of getClass was flawed . What I want to achieve is that I need a method which would iterate over an object's getters . So what would be the signature of such ?
I was thinking on the lines of
public static <T> List<NameValuePair> entityConvert1(Class<T> entity)
however as per all the comments , I understand passing the Class wont send in any instance specific information in the method .
I need a torch here .
Update:
It seems like, you just want to get the getter methods from your class, and invoke it to get the value for a particular instance.
You can get all the getters using Introspector. Write a generic method, taking 2 arguments - Class<T>, and T types:
public static <T> void executeGetters(Class<T> clazz, T instance) throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
for(PropertyDescriptor propertyDescriptor: beanInfo.getPropertyDescriptors()){
// Get Method instance used for reading this property
Method method = propertyDescriptor.getReadMethod();
// Invoke this method on 'instance'.
System.out.println(method.invoke(instance));
}
}
Now, invoke this method as:
executeGetters(User.class, user);
This will print the value of all the properties for user instance. Note, if there is a getter method missing for the User class, this Method instance will be null, and you might get a NPE. You need to check for that.
I need to access the existing instance of the User , which was responsible for creating the "c" variable in the first place
Can't be done because there is no link between the getClass() method's result and c. The problem is that the Class c represents an instance of the type of c not the particular instance which is user. Class itself is a representation of the bytecode file loaded by the JVM and what it exposes so you can do reflection operations. It's not even directly analogous to the actual User class represented by the bytecode. It's more low level than what you're thinking.
Let us say that I want to create a class MyString which is a wrapper for java.lang.String. I have added a new method called reverse.
public class MyString {
private String text=null;
public MyString(String foo){
text=foo;
}
public String reverse(){
// implementation omitted
return reversedString;
}
}
Now String is final. Therefore I cannot extend it. One way to have MyString support all methods that String supports is by providing wrapper method implementations such as the method toCharArray():
public char[] toCharArray(){
// redirect to String member field 'text'
return text.toCharArray();
}
Is there a way I can redirect method calls to the member field without actually having to code the wrapper implementation? Something similar to super?
No, this cannot be done directly.
You could define an interface containing all java.lang.String methods (plus your methods) and implement it with a dynamic proxy redirecting to the string implementation (with all the negative implications of dynamic proxies).
Probably you're better of with a type conversion new MyString(string).reverse() unfortunately Java does not have C#'s extension methods or Scala's implicit type conversions.
There are of course plenty of reverse implementations, for example from the apache commons library. It is implemented in a procedural style:
String reversed = StringUtils.reverse(string);
(I think your reverse method should return MyString not String so you can write: s.reverse().reverse()).
Not sure if I completely understand the question, but ultimately, if you want your MyString to have all the same methods as String, then at some level your class must also have all of the same methods defined. You can't really get around this.
You can probably come up with neat ways so that for every method you don't have to type return text.blah(), something more elegant than that; but I don't see any way how you could avoid having the method definitions in your MyString at all.
You can't do this as you have to write the methods to expose them for use. But, for example, you can use the Netbeans' "Create Delegates..." feature and you get all delegate methods with some mouse clicks.