Ok, this could be a tricky one. For a code generating tool I need to know methods and arguments of a class. The method name and argument types are the easy ones - just using reflection. But the argument name - and I need the real argument name - is a tricky one because this information is in the javadoc. In my case I use Netbeans 8 and I am pretty sure if Netbeans can get the arguments name I can too. Does anyone know how to read the javadoc to get the argument names of a method?
PS I know this question will pop up. I need the real argument names because the generated code provides an api and it is not very helpful for a developper to use an api where the api methods are something like set_a1, set_a2, and so on.
Indeed, this is tricky, and will involve a considerable effort if you intend to find a general solution that works for arbitrary (third-party) classes and arbitrary Java versions.
However, under certain conditions, there may be a simple solution:
If you can compile the classes on your onw, and if you can use Java 8, then you can use the Method Parameter Reflection infrastructure that was added in Java 8. When compiling the classes with javac -parameters ..., then the parameter names are added to the class file, and can be obtained from the method by calling getParameters on the Method object, and then Parameter#getName()
Parameter parameters[] = method.getParameters();
String name = parameters[0].getName();
...
Related
I have some (maybe) strange requirements - I wanted to detect definitions of local (method) variables of a given interface name. When finding such a variable I would like to detect which methods (set/get*) will be called on this variable.
I tried Javassist without luck, and now I have a deeper look into ASM, but not sure if it is possible what I wanted.
The reason for this is that I like to generated a dependency graph with GraphViz of beans that depend on the same data structure.
If this thing is possible could somebody please give me a hint on how it could be done? Maybe there are other Frameworks that could do?
01.09.2015
To make things more clear:
The interface is self written - the target of the whole action is to create a dependency graph in the first step automatically - later on a graphical editor should be implemented that is based on the dependencies.
I wonder how FindBugs/PMD work, because they also use the byte code and detect for example null pointer calls (variable not initialized and method will be called on it). So I thought that I could implement my idea in the same way. The whole code is Spring based - maybe this opens another solution to the point? Last but not least I could work on a source-jar?
While thinging about the problem - would it be possible via ASM/javassist to detect all available methods from the interface and find calls to them in the other classes?
I’m afraid, what you want to do is not possible. In compiled Java code, there are no local variables in the form you have in the source code. Methods use stack frames which have memory reserved for local variables, which is addressed by a numerical index. The type is implied by what instructions write to it and may change throughout the method’s code as the memory may get reused for different variables having a disjunct scope. The names on the other hand are completely irrelevant.
When bytecode gets verified, the effect of all instructions to the stack frame will get modeled to infer the type of each stack frame slot at each point of the execution so that the validity of all operations can be checked. Starting with class file version 50, there will be StackMapTable attributes aiding the process by containing explicit type information, but only for code with branches. For sequential code, the type of variables still has to be derived by inference.
These inferred types are not necessarily the declared types. E.g., on the byte code level, there will be no difference between
CharSequence cs="foo";
cs.charAt(0);
and
String s="foo";
((CharSequence)s).charAt(0);
In both cases, there will be a storage of a String constant into a local variable followed by the invocation of an interface method. The inferred type will be String in both cases and the invocation of a CharSequence method considered valid as String implements CharSequence.
This disproves the idea of detecting that there is a local variable declared using the CharSequence (interface) type, as the actual declared type is irrelevant and not stored in the regular byte code.
There are, however, debugging attributes containing information about the local variables, see the LocalVariableTable attribute and libraries like ASM will tell you about the declarations if such information is present. But you can’t rely on these optional information. E.g. Oracle’s JRE libraries are by default shipped without them.
I don't sure I understood exacly what you want but .
you can use implement on each object ,
evry object that have getter you can implement it with class called getable .
and then you could do stuff only on object that have the function that you implement from the class getable .
https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html
I have an existing JNI method with two parameters. Been around for a while, in use, so I don't want to just change it lest the wrath of angry customers be unleashed.
But, I now need to make an adjustment.
So, I thought, make a second overloaded method with the extra parameter and deprecate the two-parameter version. That part went fine, jar builds and runs with no issues.
The problem is in the C++ side... I defined two methods, one being a wrapper for the other (two parameter calls the three parameter version), but, when I went to export the two methods, I receive:
Error 1 error C2733: second C linkage of overloaded function 'Java_com_xxx' not allowed
So, what do I do to keep the old method name and add a new method with new parameters? Is this doable?
Run javah on your Java file declaring the native methods and you will see that you need two different Java_com_xxx functions. The C-level declarations must be unique.
I found that there seem to be 2 general solutions:
don't obfuscate what is referred to through the reflection API [Retroguard, Jobfuscate]
replace Strings in reflection API invocations with the obfuscated name.
Those solutions work only for calls within the same project - client code (in another project) may not use the reflection API to access non-public API methods.
In the case of 2 it also only works when the Reflection API is used with Strings known at compile-time (private methods testing?). In those cases dp4j also offers a solution injecting the reflection code after obfuscation.
Reading Proguard FAQ I wondered if 2 otherwise always worked when it says:
ProGuard automatically handles
constructs like
Class.forName("SomeClass") and
SomeClass.class. The referenced
classes are preserved in the shrinking
phase, and the string arguments are
properly replaced in the obfuscation
phase.
With variable string arguments, it's generally not possible to determine
their possible values.
Q: what does the statement in bold mean? Any examples?
With variable string arguments, it's generally not possible to determine their possible values.
public Class loadIt(String clsName) throws ClassNotFoundException {
return Class.forName(clsName);
}
basically if you pass a non-constant string to Class.forName, there's generally no way for proguard or any obfuscation tool to figure out what class you are talking about, and thus can't automatically adjust the code for you.
The Zelix KlassMaster Java obfuscator can automatically handle all Reflection API calls. It has a function called AutoReflection which uses an "encrypted old name" to "obfuscated name" lookup table.
However, it again can only work for calls within the same obfuscated project.
See http://www.zelix.com/klassmaster/docs/tutorials/autoReflectionTutorial.html.
It means that this:
String className;
if (Math.random() <= 0.5) className = "ca.simpatico.Foo";
else className = "ca.simpatico.Bar";
Class cl = Class.forName(className);
Won't work after obfuscation. ProGuard doesn't do a deep enough dataflow analysis to see that the class name which gets loaded came from those two string literals.
Really, your only plausible option is to decide which classes, interfaces, and methods should be accessible through reflection, and then not obfuscate those. You're effectively defining a strange kind of API to clients - one which will only be accessed reflectively.
In Ruby, you can do "var1".constantize to get the actual variable var1.
Ruby also has Model.Send("method name, parameters can be here, etc"), and it would be the same as actually calling that method.
What I want to do.. is... kinda tricky... I want the string "var1 == var2" to be converted to actual variables in my java app, then evaluated.
Is there a way to do this?
Have you considered using JRuby?
As to your questions:
There is no peer to constantize that will allow for an eval like syntax where you can pass in a String and convert it to code in Java. You can do things like Class.forName to load a particular class from a String, but it doesn't sound that is what you are looking for.
You can use the Java reflection API to dynamically invoke methods on a class Check out Jakarta Commons BeanUtils for some utility methods that may help.
In Java, similar behaviour is achieved through the Reflection API. However, since Java is a compiled language, local variables' (within methods, constructors, parameters, etc) information is erased on compilation.
However you still have complete access to class names, hierarchies, methods and fields (class variables).
A good starting point is the Reflection API tutorial or the getClass() method of Object.
In Java if you want a dynamic lookup of variables, you would typically place them in a Map and lookup use the keys of that Map.
Can you explain what you are trying to do in more detail, I suspect what you are trying to do can be done simply a different way in Java.
So, I need to dynamically create (or inject) methods into an object that have a specific return type and method signature, because a Java tool we're using will be finding this methods via Reflection and checks for void type. Method names will be determined at runtime.
Using metaClass. = { ... } however adds a closure which doesn't show up as a regular method (even if it can be used as one) and also has a return type.
I can't modify the method finding code, and it it not Groovy-aware.
I can't use methodMissing() or invokeMethod() because the method needs to actually exist. If I could overload class.getMethods() I think it would be possible, but I can't figure out how.
Is there any way to do this in Groovy?
You could use AST Transformations to add the code at compile time, but it wont work on classes that you don't compile, so I'm guessing that probably wont work.
You could probably replace the object with a CGLIB based proxy. If you can be more specific about the code in question...
EDIT: A little more info. Groovy metaClass magic is not available in Java unless the Java code were to explicitly call groovyClass.invokeMethod("someMethod",args);. So there isn't a way to do what you're asking with MetaClasses. CGLIB maybe.