Getting Method Call Information from AST - java

How can I get the names of the methods invoked in each method declaration of a program using AST (Abstract Syntax Tree) parser? So far, I have managed to get all the names of the methods' declaration and all the names of the methods being invoked, but I want to know which method call which methods. For example, I want to see that method m1 calls methods mA and mB, while method m2 calls methods mC and mD, etc.
[EDIT 11/9/2011 IDB, transcribing newbie's extended comment back in the body of the original question. I hope I have transcribed it correctly. I hope the author comes back and revises as necessary]:
My problem seems to be that (Eclipse's) MethodDeclaration api doesn't have a GetInvokedMethodName function to call. Here is my code:
public class MethodVisitor extends ASTVisitor {
List<MethodDeclaration> methods = new ArrayList<MethodDeclaration>();
#Override public boolean visit(MethodDeclaration node) {
methods.add(node);
return super.visit(node); }
public List<MethodDeclaration> getMethods()
{ return methods; }
List<MethodInvocation> methods1 = new ArrayList<MethodInvocation>();
#Override public boolean visit(MethodInvocation node)
{ methods1.add(node);
return super.visit(node); }
public List<MethodInvocation> getMethods1()
{ return methods1; }
}
...
for (MethodDeclaration method : visitor .getMethods())
{ System.out.println("Method name: " + method.getName()
+ " Return type: " + method.getReturnType2()
+ " Is constructor: " + method.isConstructor()
+ " Method invoked: " + ASTNode.METHOD_INVOCATION );
); }
for (MethodInvocation method1 : visitor .getMethods1())
{ System.out.println("Method name invoked: " + method1.getName() ); }

I had the same problem. This was my solution to it:
final HashMap<MethodDeclaration, ArrayList<MethodInvocation>> invocationsForMethods =
new HashMap<MethodDeclaration, ArrayList<MethodInvocation>>();
CompilationUnit cu = (CompilationUnit) ap.createAST(null);
cu.accept(new ASTVisitor() {
private MethodDeclaration activeMethod;
#Override
public boolean visit(MethodDeclaration node) {
activeMethod = node;
return super.visit(node);
}
#Override
public boolean visit(MethodInvocation node) {
if (invocationsForMethods.get(activeMethod) == null) {
invocationsForMethods.put(activeMethod, new ArrayList<MethodInvocation>());
}
invocationsForMethods.get(activeMethod).add(node);
return super.visit(node);
}
});
Now, one can ask the invocationsForMethods.keySet() to get all the method declarations for the used AST and invocationsForMethods.get(key) returns all method invocations for the declaration given as a key.

If you want to know which specific method mB (of all the ones named "mB" throughout your vast array of classes) is invoked by m1, you need more than just the AST. You need a full symbol table, that binds each symbol use to the possible definitions that match it.
The process of computing such a symbol table is difficult for many languages and very hard for Java (but not nearly as bad as it is for C++). Somebody has to encode the rules of how an identifier is looked up in the face of (local) scopes, inheritance, overloads, implied casts, etc, and the Java reference manual devotes a significant portion of its content trying to explain that. You don't want to have to do this yourself.
What you really need is a full Java front end, that has both ASTs and the corresponding symbol tables, for each method you want to inspect. You can get this, I think, from interfaces to the (Sun?) Java compiler (I don't personally know how to do this), from the Jikes compiler, from the Eclipse Java AST (?) module, and from tools such as our Java Front End. Another approach is to process class files, which contain the method calls in JVM form, with the advavntage that the JVM instructions all have built with the benefit of a symbol table.
If you want to compute m1 calls mA calls mQ calls .... mZ, you need a tool that is willing to read in the entire source code base at once. The compilers won't do that for you, but you can use Eclipse or our front end to do that.

Related

Can JNA be used for a complex Windows DLL like IMAPI

I've managed to get COM4J to use some functionality in the windows IMAPI (CD writing).
However I've failed to get any of the calls that return SAFEARRAYs working, but this project doesn't appear to be currently active ...
The DLL is usually in C:\Windows\System32\imapi2.dll, and using it also requires using C:\Windows\System32\imapi2fs.dll
Looking around for a JAVA-COM bridge project that is active led me to JNA.
The remit of the project to simplify JAVA-COM bridging intrigued me .... however I fell at the first hurdle, and am hoping someone can help.
So far I've taken the Microsoft IMAPI examples and written a Powershell application, from which I have the series of calls I need to make to the API.[CDInterface][1]
The first thing you need to do with IMAPI is create an Instance of IDiskMaster2, so I've declared that via an Imapi2 interface, like so
public interface Imapi2 extends Library {
Imapi2 INSTANCE = (Imapi2)
Native.load("C:/Windows/System32/imapi2.dll" , Imapi2.class);
public static class IDiscMaster2 extends Structure {
int getCount;
public int getCount() {
return getCount;
}
}
IDiscMaster2 createMsftDiscMaster2();
}
Then in the main code
Imapi2.IDiscMaster2 recorderList = Imapi2.INSTANCE.createMsftDiscMaster2();
System.out.println("Found " + recorderList.getCount() + " Recorders");
Just putting 'imapi2' in the call to Native.load() didn't work either.
I'm guessing I'm doing something fundamentally wrong, but it's not clear how you get JNA to 'see' a new dll you want to interface to ..... and also I am kind of afraid there is something very different about this API from the othe APIs that people are using JNA to talk to, so may not be worth trying!
public interface Imapi2 extends Library {
Imapi2 INSTANCE = (Imapi2)
Native.load("C:/Windows/System32/imapi2.dll" , Imapi2.class);
public class IDiscMaster2 extends Dispatch {
public static final CLSID CLSID_MsftDiscMaster2 = new CLSID("2735412F-7F64-5B0F-8F00-5D77AFBE261E");
public IDiscMaster2() {
}
private IDiscMaster2(Pointer pvInstance) {
super(pvInstance);
}
public static IDiscMaster2 create() {
PointerByReference pbr = new PointerByReference();
WinNT.HRESULT hres = Ole32.INSTANCE.CoCreateInstance(CLSID_MsftDiscMaster2, null, WTypes.CLSCTX_ALL, null, pbr);
if (COMUtils.FAILED(hres)) {
System.out.println("ERROR: Failed to create instance");
return null;
}
return new IDiscMaster2(pbr.getValue());
}
public WinNT.HRESULT _getCount(Pointer count ){
return (WinNT.HRESULT) _invokeNativeObject(2, new Object[]{count}, WinNT.HRESULT.class);
}
public long getCount() {
try {
long count = -1;
Pointer ptr = new Pointer(count);
WinNT.HRESULT result = _getCount(ptr);
COMUtils.checkRC(result);
return count;
} catch ( Exception e ) {
System.out.println("Error : " + e.getMessage());
}
return -1;
}
}
Then invocation in main changed to
Imapi2 imapi2Lib = Imapi2.INSTANCE;
Imapi2.IDiscMaster2 recorderList = new Imapi2.IDiscMaster2();
System.out.println("Found " + recorderList.getCount() + " Recorders");
IntelliJ shows up uninvoked methods, so it doesn't look like create() is getting called. Not sure if this is because I need to call it, or down to the function implementing IDispatch not IUnknown.
[1]: https://github.com/nosdod/CDInterface
I've answered this in a similar question which I originally marked this as a duplicate of. However, given the difficulty loading this, your case is unique enough that I'll attempt to give a separate answer.
The general case for COM is that there is an API function that creates the object. You have mapped this as createMsftDiscMaster2(). Note that you have allocated a resource here and it needs to be disposed of when you are done with it; the API documentation should tell you how to do that (possibly by calling Release() from IUnknown.)
Your next step is to map the IDiscMaster2 COM class. I see two mappings here, so I'm confused as to which one you want. The one at the top of your question is incorrect, but the one extending Dispatch later is the correct way to start, but I'm not clear where you've gone after that. The rest of the class should look similar to the internals of the Dispatch class in JNA.
In that class you can see the boilerplate that you will follow. Note that it extends Unknown which follows the same boilerplate for offsets 0, 1, and 2 for the first 3 COM functions QueryInterface, AddRef, and Release. Dispatch picks up with offsets 3, 4, 5, and 6 for COM functions GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, and Invoke.
So in your mapping for DiskMaster2 you will pick up with offset 7, and your mapping will look like:
public HRESULT TheFunctionName(FOO foo, BAR bar) {
return (HRESULT) this._invokeNativeObject(7,
new Object[] { this.getPointer(), foo, bar },
HRESULT.class);
}
This is where you need to locate the actual header file for this class to determine the order in which the functions appear in the Vtbl. It looks like you attempted to do this with your code, but the offset 2 is already assigned in Unknown, the lowest one you'll be able to use is 7 (and continue on with 8, 9, 10 for each function in this COM interface, in the correct order -- which you must determine from the Vtbl.)
Based on this header, you can see those functions mapped in order and your offsets should be: 7: get__NewEnum, 8: get_Item, 9: get_Count, and 10: get_IsSupportedEnvironment. Use those header function mappings as a start and change them to the _invokeNativeObject() format above. (They all return HRESULT, you'll just be changing the argument list.)

Find all Java methods using only one specific property of a specific type of parameter

We're in the process of trying to identify everywhere that a specific type of object is used only to get a specific property from it, and pass that property into the method instead.
I'm thinking IntelliJ IDEA's "Structural Search" might be a good tool for this, but I'm not sure how to formulate the search template.
A concrete example:
public class MyClass {
public Long getId() {...}
public void setSomethingElse(int se) {...}
}
public class SomeOtherClasses {
public void shouldBeMatched(MyClass mc) {
doSomething();
mc.getId();
doSomethingElse();
}
public void shouldNotBeMatched(MyClass mc) {
doSomething();
mc.getId();
mc.setSomethingElse(14);
doSomethingElse();
}
public void alsoShouldNotBeMatched(MyClass mc) {
shouldBeMatched(mc);
}
}
In the above example, if I'm looking for methods that only use getId, then I should find shouldBeMatched, but not be bothered with shoudNotBeMatched and alsoShouldNotBeMatched, because they do something with the mc object other than call getId().
I'm thinking IntelliJ IDEA's "Structural Search" might be a good tool for this
And it is indeed. The documentation can be tough though.
Let's check Search templates, filters, and script constraints page. It goes as follows.
Let's say, you have a variable that matches a method, a toString()
method. Then this variable is actually a PsiMethod node. Retrieving
variable.parent will produce a PsiClass node, and so forth.
variable.text then will give you the entire text of the method. If you
just need the name of the method, you can use variable.name.
It seems that the task can be done by choosing the right template and writing a corresponding Groovy script.
The template is called methods of the class and can be found under Existing templates. They provide __context__variable to be used with a script.
We have to be sure matched methods have parameters. It is simple enough, just put a count filter on a $Parameter$ variable.
Then we need to extract the name of a parameter of desired type and see if it is called in the body of the method. The following script will do.
def parameters = __context__.getParameterList().getParameters();
def parameter = parameters.find { p -> p.getType().getName().equals('MyClass') };
if (parameter == null) return false;
String parameterName = parameter.getName();
String methodText = __context__.getText();
String occurrence = "${parameterName}.";
String methodCall = "${parameterName}.getId()";
return methodText.count(occurrence) > 0 && methodText.count(occurrence) == methodText.count(methodCall);
Put it in the $Method$ variable filter and verify the results.

Dynamically generate a single function (without subfunctions), representing a binary expression tree, at run time with Byte Buddy

Introduction
I want to compare some libraries for generating code at run time. At the moment I touched the surface of Javassist and Byte Buddy.
As a proof of concept I am trying to solve a small problem, which is a starting point for a more complex one.
Basically I have a binary expression tree which I want to convert into a single line of code and load it into my java run time. For simplicity reasons I have only add nodes and constants as leafs so far.
Javassist Reference
I already have a way for doing this in Javassist (which at least works for a single node with two leafs). The code is looking like this:
public class JavassistNodeFactory{
public DynamicNode generateDynamicNode(INode root){
DynamicNode dynamicNode = null;
try {
CtClass cc = createClass();
interceptMethod(root, cc);
compileClass(cc);
dynamicNode = instantiate(cc);
}catch (Exception e){
System.out.println("Error compiling class with javassist: "+ e.getMessage());
e.printStackTrace();
}
return dynamicNode;
}
private DynamicNode instantiate(CtClass cc) throws CannotCompileException, IllegalAccessException, InstantiationException {
Class<?> clazz = cc.toClass();
return (DynamicNode) clazz.newInstance();
}
private void compileClass(CtClass cc) throws NotFoundException, IOException, CannotCompileException {
cc.writeFile();
}
private void interceptMethod(INode root, CtClass cc) throws NotFoundException, CannotCompileException {
CtMethod calculateMethod = cc.getSuperclass().getDeclaredMethod("calculateValue",null);
calculateMethod.setBody("return "+ nodeToString(root)+ ";");
}
private CtClass createClass() throws CannotCompileException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass(
"DN"+ UUID.randomUUID().toString().replace("-","")
);
cc.setSuperclass(pool.get("org.jamesii.mlrules.util.runtimeCompiling.DynamicNode"));
return cc;
}
private static String nodeToString(INode node){
if (node.getName().equals("")){
return ((ValueNode)node).getValue().toString();
}else{
List<? extends INode> children = node.getChildren();
assert(children.size()==2);
return ("("+nodeToString(children.get(0))+node.getName()+nodeToString(children.get(1))+")");
}
}
}
The DynamicNode class looks like this:
public class DynamicNode implements INode {
#Override
public <N extends INode> N calc() {
Double value = calculateValue();
return (N) new ValueNode<Double>(value);
}
#Override
public List<? extends INode> getChildren() {
return null;
}
#Override
public String getName() {
return null;
}
private Double calculateValue() {
return null;
}
}
The important part is the nodeToString() function, where I generate an arithmetic formula represented by the returned string, from a given root node. TheValueNode is a leaf of the tree with a constant Value, which would be returned as a String.
Other nodes (only add nodes for my case) will call the function recursively for each child and print brackets arround the expression as well as printing the operator (returned by the getName() function) in the middle of the two children (in short: "(leftChild+rightChild)").
The body of the calculateValue() function will be altered in the interceptMethod() function by Javassist, to return the result of the generated formula.
Byte Buddy Attempt
I have played around with Byte Buddy to achieve a similar solution. But as I looked deeper into the concepts and the documentation, I felt more and more like this is not a problem Byte Buddy was designed for. The majority of examples and questions seem to concentrate on the function delegation to other functions (which actually exist already at compile time, and are only connected to at run time). This is not really convenient in my case, since I have no way of knowing the actual tree I want to convert, at compile time. It is probably possible to use the underlying ASM library, but I would like to avoid handling byte code by myself (and possible successors of mine).
I have a (obviously not working) basic implementation, but I am stuck at the point where I have to provide an Implementation for the intercept() function of the Byte Buddy library. My last state looks like this:
public class ByteBuddyNodeFactory{
#Override
public DynamicNode generateDynamicNode(INode root) {
DynamicNode dynamicNode = null;
try {
Class<?> dynamicType = new ByteBuddy()
.subclass(DynamicNode.class)
.name("DN"+ UUID.randomUUID().toString().replace("-",""))
//this is the point where I have problems
//I don't know how to generate the Implementation for the intercept() function
//An attempt is in the nodeToImplementation() function
.method(ElementMatchers.named("calculateValue")).intercept(nodeToImplementation(root))
.make()
.load(Object.class.getClassLoader())
.getLoaded();
dynamicNode = (DynamicNode) dynamicType.newInstance();
} catch (Exception e) {
System.out.println("Error compiling testclass with bytebuddy: " + e.getMessage());
e.printStackTrace();
}
return dynamicNode;
}
private Implementation.Composable nodeToImplementation(INode node){
if (node.getName().equals("")){
return (Implementation.Composable)FixedValue.value(((ValueNode)node).getValue());
}else{
List<? extends INode> children = node.getChildren();
assert(children.size()==2);
switch (node.getName()){
case ("+"):
//This is the point where I am completely lost
//This return is just the last thing I tried and may be not even correct Java code
// But hopefully at least my intention gets clearer
return (MethodCall.invoke((Method sdjk)-> {
return (nodeToImplementation(children.get(0)).andThen(node.getName().andThen(nodeToImplementation(children.get(1)))));
}));
default:
throw new NotImplementedException();
}
}
}
}
My idea was to concatenate subfunctions together and therefore tried to work with the Composable Implementation. I tried to return a MethodDelegation but as I mentioned I got the feeling that this wouldn't be the right approach. After that I tried MethodCall but I soon realized that I have exactly no idea how to make things work with this one either^^
Question
Is it possible in Byte Buddy to generate a function from a tree structure as dynamically as in Javassist, without calling as many sub functions as I have nodes?
How would I do this, if possible?
And if it is not possible: is it possible with other byte code manipulation libraries like cglib.
I would prefer to stay an abstraction level above byte code, since the study of the underlying concepts should be irrelevant for my problem.
What you are trying to do is not easily possible with Byte Buddy's high-level APIs. Instead, you should assemble a method using StackManipulations if you want to use Byte Buddy. Stack manipulations do still contain Java byte code but these bits should be so trivial that they would be easy to implement.
The reason that Byte Buddy does not aim for this scenario is that you can normally find a better abstraction for your code than to assemble code snippets. Why can your nodes not implement the actual implementation which is then called from your instrumented method? The JIT compiler does typically optimize this code to the same result as your manually inlined code. Additionally, you preserve debuggability and reduce the complexity of your code.

Listing all unimplemented methods called from within a method

We have a huge project where many methods have been declared upfront and implementations are in progress. All declared methods have a body which simply throws an exception, say, UnimplException.
Now since the methods have been declared and a valid (compilable) body has been provided, they can be called from within other methods.
Now the question is that is there any way to list all such unimplemented (having just a compilable body throwing a particular exception) methods given a particular method?
To illustrate more(the code is to convey the idea and not strictly compiler friendly):
class A {
methA () {
throw new UnimplException();
}
}
class B {
methB () {
// proper body
// and calls methA
A.methA();
// does something else
// and returns.
}
}
class C {
methC () {
// proper body
// calls methB
B.methB();
}
}
So, if we start from, say, methC, then we want to travel all the way down the method tree to reach to methA because methC calls methB (which is properly implemented and we are not interested) which in turn calls methA which is not properly implemented and that is what we want to find.
We want to search for all such unimplemented methods starting from a method and going few levels deep until we cover all such unimplemented methods.
We thought of JavaAssist but we aren't sure how to go down all the levels because it seems to be giving us all methods called from within a method but not recursively.
Any help is greatly appreciated :)
Have you seen this project: https://github.com/gousiosg/java-callgraph? This appears to do the Java introspection part, listing every method call from every method in a jar file. I'd try using that to do the heavy lifting of parsing your code, then just recurse through the results.
Something like:
Use the callgraph code to build a list of all method calls.
Save that data somewhere.
Recursively parse that structure to find matching methods.
So from your example, step 1 would give something like the following:
A:methA -> UnimplException:<init>
B:methB -> A:methA
C:methC -> B:methB
Then shove those in a Multimap and do a fairly straightforward recursive search:
// this is populated from the output of the callgraph code
com.google.common.collect.Multimap<String, String> methodMap;
void checkAllMethods() {
for (String method : methodMap.keySet()) {
List<String> callStack = new ArrayList<>();
if (doesMethodThrowUnimplException(method, callStack)) {
System.out.println(method);
// can print callStack too if interested
}
}
}
boolean doesMethodThrowUnimplException(String method, List<String> callStack) {
for (String child : methodMap.get(method)) {
// have to check the exact method name from callgraph
if (child.equals("UnimplException:<init>")) {
return true;
}
// recurse into child if not already seen
if (!callStack.contains(child)) {
callStack.add(child);
if (doesMethodThrowUnimplException(child, callStack)) {
return true;
}
callStack.remove(callStack.size() - 1);
}
}
return false;
}
Doesn't strictly satisfy your requirements as this will report any method which throws the UnimplException, not those who only throw the exception, but not sure if that matters.
Standard disclaimer - just typed this in - haven't compiled / run it, so may well be typos, but hopefully the idea helps.

Translating a string-representation of a function's parameter list to actual parameters, for a reflective call

UPDATE: After getting an unexpected-in-a-good-way answer, I've added some context to the bottom of this question, stating exactly how I'll be using these string-function-calls.
I need to translate a string such as
my.package.ClassName#functionName(1, "a string value", true)
into a reflective call to that function. Getting the package, class, and function name is not a problem. I have started rolling my own solution for parsing the parameter list, and determining the type of each and returning an appropriate object.
(I'm limiting the universe of types to the eight primitives, plus string. null would be considered a string, and commas and double-quotes must be strictly escaped with some simple marker, such as __DBL_QT__, to avoid complications with unescaping and splitting on the comma.)
I am not asking how to do this via string-parsing, as I understand how. It's just a lot of work and I'm hoping there's a solution already out there. Unfortunately it's such generic terminology, I'm getting nowhere with searching.
I understand asking for an external existing library is off topic for SO. I'm just hoping to get some feedback before it's shutdown, or even a suggestion on better search terms. Or perhaps, there is a completely different approach that might be suggested...
Thank you.
Context:
Each function call is found within a function's JavaDoc block, and represents a piece of example code--either its source code or its System.out output--which will be displayed in that spot.
The parameters are for customizing its display, such as
indentation,
eliminating irrelevant parts (like the license-block), and
for JavaDoc-linking the most important functions.
This customization is mostly for the source-code presentation, but may also be applied to its output.
(The first parameter is always an Appendable, which will do the actual outputting.)
The user needs to be be able to call any function, which in many cases will be a private-static function located directly below the JavaDoc-ed function itself.
The application I'm writing will read in the source-code file (the one containing the JavaDoc blocks, in which these string-function-calls exist), and create a duplicate of the *.java file, which will subsequently processed by javadoc.
So for every piece of example code, there will be likely two, and possibly more of these string-function-calls. There may be more, because I may want to show different slices of the same example, in different contexts--perhaps the whole example in the overall class JavaDoc block, and snippets from it in the relevant functions in that class.
I have already written the process that parses the source code (the source code containing the JavaDoc blocks, which is separate from the one that reads the example-code), and re-outputs its source-code blindly with insert example-code here and insert example-code-output here markers.
I'm now at the point where I have this string-function-call in an InsertExampleCode object, in a string-field. Now I need to do as described at the top of this question. Figure out which function they want to invoke, and do so.
Change the # to a dot (.), write a class definition around it so that you have a valid Java source file, include tools.jar in your classpath and invoke com.sun.tools.javac.Main.
Create your own instance of a ClassLoader to load the compiled class, and run it (make it implement a useful interface, such as java.util.concurrent.Callable so that you can get the result of the invocation easily)
That should do the trick.
The class I created for this, called com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature, is a significant piece of Codelet, used to translate the "customizer" portion of each taglet, which is a function that customizes the taglet's output.
(Installation instructions. The only jars that must be in your classpath are codelet and xbnjava.)
Example string signatures, in taglets:
{#.codelet.and.out com.github.aliteralmind.codelet.examples.adder.AdderDemo%eliminateCommentBlocksAndPackageDecl()}
The customizer portion is everything following the percent sign (%). This customizer contains only the function name and empty parameters. This implies that the function must exist in one of a few, strictly-specified, set of classes.
{#.codelet.and.out com.github.aliteralmind.codelet.examples.adder.AdderDemo%lineRange(1, false, "Adder adder", 2, false, "println(adder.getSum())", "^ ")}
This specifies parameters as well, which are, by design, "simple"--either non-null strings, or a primitive type.
{#.codelet.and.out com.github.aliteralmind.codelet.examples.adder.AdderDemo%com.github.aliteralmind.codelet.examples.LineRangeWithLinksCompact#adderDemo_lineSnippetWithLinks()}
Specifies the explicit package and class in which the function exists.
Because of the nature of these taglets and how the string-signatures are implemented, I decided to stick with direct string parsing instead of dynamic compilation.
Two example uses of SimpleMethodSignature:
In this first example, the full signature (the package, class, and function name, including all its parameters) are specified in the string.
import com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature;
import com.github.xbn.lang.reflect.InvokeMethodWithRtx;
import java.lang.reflect.Method;
public class SimpleMethodSigNoDefaults {
public static final void main(String[] ignored) {
String strSig = "com.github.aliteralmind.codelet.examples.simplesig." +
"SimpleMethodSigNoDefaults#getStringForBoolInt(false, 3)";
SimpleMethodSignature simpleSig = null;
try {
simpleSig = SimpleMethodSignature.newFromStringAndDefaults(
String.class, strSig, null, null,
null); //debug (on=System.out, off=null)
} catch(ClassNotFoundException cnfx) {
throw new RuntimeException(cnfx);
}
Method m = null;
try {
m = simpleSig.getMethod();
} catch(NoSuchMethodException nsmx) {
throw new RuntimeException(nsmx);
}
m.setAccessible(true);
Object returnValue = new InvokeMethodWithRtx(m).sstatic().
parameters(simpleSig.getParamValueObjectList().toArray()).invokeGetReturnValue();
System.out.println(returnValue);
}
public static final String getStringForBoolInt(Boolean b, Integer i) {
return "b=" + b + ", i=" + i;
}
}
Output:
b=false, i=3
This second example demonstrates a string signature in which the (package and) class name are not specified. The potential classes, one in which the function must exist, are provided directly.
import com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature;
import com.github.xbn.lang.reflect.InvokeMethodWithRtx;
import java.lang.reflect.Method;
public class SimpleMethodSigWithClassDefaults {
public static final void main(String[] ignored) {
String strSig = "getStringForBoolInt(false, 3)";
SimpleMethodSignature simpleSig = null;
try {
simpleSig = SimpleMethodSignature.newFromStringAndDefaults(
String.class, strSig, null,
new Class[]{Object.class, SimpleMethodSigWithClassDefaults.class, SimpleMethodSignature.class},
null); //debug (on=System.out, off=null)
} catch(ClassNotFoundException cnfx) {
throw new RuntimeException(cnfx);
}
Method m = null;
try {
m = simpleSig.getMethod();
} catch(NoSuchMethodException nsmx) {
throw new RuntimeException(nsmx);
}
m.setAccessible(true);
Object returnValue = new InvokeMethodWithRtx(m).sstatic().
parameters(simpleSig.getParamValueObjectList().toArray()).invokeGetReturnValue();
System.out.println(returnValue);
}
public static final String getStringForBoolInt(Boolean b, Integer i) {
return "b=" + b + ", i=" + i;
}
}
Output:
b=false, i=3

Categories