Translation of a string representation of a list of function parameters into actual parameters, for a reflective call

UPDATE: after receiving the answer “unexpectedly in good”, I added some context at the bottom of this question, indicating exactly how I will use these string calls.

I need to translate a line such as

my.package.ClassName#functionName(1, "a string value", true) 

into the reflexive call of this function. Getting the package name, class, and function is not a problem. I started rolling my own solution for parsing a list of parameters and determining the type of each and returning the corresponding object.

(I limit all type types to eight primitives as well as a string. null will be considered a string, and commas and double quotes must be strictly escaped with a simple marker, such as __DBL_QT__ , to avoid the complications of canceling and splitting a comma.)

I am not asking how to do this using string parsing, as I understand it. This is just a lot of work, and I hope there is already a solution. Unfortunately, such a generalized terminology, I have not looked for a search anywhere.

I understand that requesting an external existing library is disabled for SO. I just hope to get some feedback before disconnecting, or even suggesting better search queries. Or perhaps there is a completely different approach that could be suggested ...

Thanks.


Context:

Each function call is located inside the JavaDoc block of the function and represents part of the sample code - either its source code or its output System.out , which will be displayed in this place.

Parameters for setting its display, for example

  • indentation
  • elimination of irrelevant parts (e.g., license block) and
  • for JavaDoc binding of the most important functions. This setting is mainly intended to represent the source code, but can also be applied to its output.

(The first parameter is always equal to Appendable , which will execute the actual output.)

The user should 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 that I am writing will read in the source code file (the one that contains the JavaDoc blocks in which these calls to string functions exist) and create a duplicate of the * .java file, which will subsequently be processed by javadoc .

So, for each example code snippet, there are likely to be two and possibly more of these string calls. Maybe more, because I can show different fragments of the same example in different contexts - maybe the whole example in the general class is a JavaDoc block and fragments from it in the corresponding functions of this class.

I already wrote a process that parses the source code (source code containing JavaDoc blocks that is separate from the one that reads the sample code), and again outputs the source code using insert example-code here and insert example-code-output here .

Now I am at the point where I have this call to the string function in the InsertExampleCode object in a string field. Now I need to do as described at the beginning of this question. Find out what function they want to call, and do it.

+1
source share
2 answers

Change # to a period ( . ), Write a class definition around it so that you have the correct Java source file, include tools.jar in your classpath and call com.sun.tools.javac.Main .

Create your own instance of ClassLoader to load the compiled class and run it (so that it implements a useful interface like java.util.concurrent.Callable so you can easily get the result of the call)

That should do the trick.

+1
source

The class I created, called com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature , is a significant Codelet snippet used to translate the "customizer" part of each taglet, which is a function that customizes tag output.

( Installation instructions . The only banks that should be in your class path are codelet and xbnjava.)

Examples of line labels in taglets:

{@.codelet.and.out com.github.aliteralmind.codelet.examples.adder.AdderDemo%eliminateCommentBlocksAndPackageDecl()}

Part of the custom component is everything that matches the percent sign ( % ). This customizer contains only the function name and empty parameters. This means that the function must exist in one of several strictly defined classes.

{@.codelet.and.out com.github.aliteralmind.codelet.examples.adder.AdderDemo%lineRange(1, false, "Adder adder", 2, false, "println(adder.getSum())", "^ ")}

It also specifies parameters that are “simple” in design — either non-empty strings or a primitive type.

{@.codelet.and.out com.github.aliteralmind.codelet.examples.adder.AdderDemo%com.github.aliteralmind.codelet.examples.LineRangeWithLinksCompact#adderDemo_lineSnippetWithLinks()}

Defines the explicit package and class in which this function exists.


Due to the nature of these taglets and how string labels are implemented, I decided to stick with direct parsing of strings instead of dynamically compiling.

Two examples of using SimpleMethodSignature :

In this first example, the line indicates the full signature (name of the package, class, and function, including all its parameters).

  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 lowercase label in which the class name (package and) is not specified. Potential classes 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 
0
source

Source: https://habr.com/ru/post/972305/


All Articles