Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GROOVY-7423: Access to Method parameter names at runtime. #38

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/groovy/ui/GroovyMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ private static Options buildOptions() {
.addOption(builder("i").argName("extension").optionalArg(true).desc("modify files in place; create backup if extension is given (e.g. \'.bak\')").build())
.addOption(builder("n").hasArg(false).desc("process files line by line using implicit 'line' variable").build())
.addOption(builder("p").hasArg(false).desc("process files line by line and print result (see also -n)").build())
.addOption(builder("pa").hasArg(false).desc("Generate metadata for reflection on method parameter names (jdk8+ only)").longOpt("parameters").build())
.addOption(builder("l").argName("port").optionalArg(true).desc("listen on a port and process inbound lines (default: 1960)").build())
.addOption(builder("a").argName("splitPattern").optionalArg(true).desc("split lines using splitPattern (default '\\s') using implicit 'split' variable").longOpt("autosplit").build())
.addOption(builder().longOpt("indy").desc("enables compilation using invokedynamic").build())
Expand Down Expand Up @@ -245,6 +246,7 @@ private static boolean process(CommandLine line) throws ParseException, IOExcept
main.isScriptFile = !line.hasOption('e');
main.debug = line.hasOption('d');
main.conf.setDebug(main.debug);
main.conf.setParameters(line.hasOption("pa"));
main.processFiles = line.hasOption('p') || line.hasOption('n');
main.autoOutput = line.hasOption('p');
main.editFiles = line.hasOption('i');
Expand Down
8 changes: 8 additions & 0 deletions src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,14 @@ protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor)
visitParameterAnnotations(parameters[i], i, mv);
}

// Add parameter names to the MethodVisitor (jdk8+ only)
if (getCompileUnit().getConfig().getParameters()) {
for (int i = 0; i < parameters.length; i++) {
// TODO handle ACC_SYNTHETIC for enum method parameters?
mv.visitParameter(parameters[i].getName(), 0);
}
}

if (controller.getClassNode().isAnnotationDefinition() && !node.isStaticConstructor()) {
visitAnnotationDefault(node, mv);
} else if (!node.isAbstract()) {
Expand Down
66 changes: 66 additions & 0 deletions src/main/org/codehaus/groovy/control/CompilerConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ public class CompilerConfiguration {
*/
private boolean debug;

/**
* If true, generates metadata for reflection on method parameters
*/
private boolean parameters = false;

/**
* The number of non-fatal errors to allow before bailing
*/
Expand Down Expand Up @@ -179,10 +184,12 @@ public CompilerConfiguration() {
setClasspath("");
setVerbose(false);
setDebug(false);
setParameters(safeGetSystemProperty("groovy.parameters") != null);
setTolerance(10);
setScriptBaseClass(null);
setRecompileGroovySource(false);
setMinimumRecompilationInterval(100);
// TODO change following try/catches to use #safeGetSystemProperty(...) ??
// Target bytecode
String targetByteCode = null;
try {
Expand Down Expand Up @@ -253,6 +260,45 @@ public CompilerConfiguration() {
setOptimizationOptions(options);
}

/**
* Retrieves a System property, or null if any of the following exceptions occur.
* <ul>
* <li>SecurityException - if a security manager exists and its checkPropertyAccess method doesn't allow access to the specified system property.</li>
* <li>NullPointerException - if key is null.</li>
* <li>IllegalArgumentException - if key is empty.</li>
* </ul>
* @param key the name of the system property.
* @return
*/
private String safeGetSystemProperty(String key){
return safeGetSystemProperty(key, null);
}

/**
* Retrieves a System property, or null if any of the following exceptions occur (Warning: Exception messages are
* suppressed).
* <ul>
* <li>SecurityException - if a security manager exists and its checkPropertyAccess method doesn't allow access to the specified system property.</li>
* <li>NullPointerException - if key is null.</li>
* <li>IllegalArgumentException - if key is empty.</li>
* </ul>
* @param key the name of the system property.
* @param def a default value.
* @return
*/
private String safeGetSystemProperty(String key, String def){
try {
return System.getProperty(key, def);
} catch (SecurityException t){
// suppress exception
} catch (NullPointerException t){
// suppress exception
} catch (IllegalArgumentException t){
// suppress exception
}
return def;
}

/**
* Copy constructor. Use this if you have a mostly correct configuration
* for your compilation but you want to make a some changes programatically.
Expand All @@ -276,6 +322,7 @@ public CompilerConfiguration(CompilerConfiguration configuration) {
setClasspathList(new LinkedList<String>(configuration.getClasspath()));
setVerbose(configuration.getVerbose());
setDebug(configuration.getDebug());
setParameters(configuration.getParameters());
setTolerance(configuration.getTolerance());
setScriptBaseClass(configuration.getScriptBaseClass());
setRecompileGroovySource(configuration.getRecompileGroovySource());
Expand Down Expand Up @@ -450,6 +497,11 @@ else if (text.startsWith("paranoia")) {
text = configuration.getProperty("groovy.output.debug");
if (text != null && text.equalsIgnoreCase("true")) setDebug(true);

//
// Parameters
//
setParameters(configuration.getProperty("groovy.parameters") != null);

//
// Tolerance
//
Expand Down Expand Up @@ -625,13 +677,27 @@ public boolean getDebug() {
return this.debug;
}

/**
* Returns true if parameter metadata generation has been enabled.
*/
public boolean getParameters() {
return this.parameters;
}

/**
* Turns debugging operation on or off.
*/
public void setDebug(boolean debug) {
this.debug = debug;
}

/**
* Turns parameter metadata generation on or off.
*/
public void setParameters(boolean parameters) {
this.parameters = parameters;
}

/**
* Returns the requested error tolerance.
*/
Expand Down
19 changes: 15 additions & 4 deletions src/main/org/codehaus/groovy/tools/FileSystemCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Arrays;

/**
* Command-line compiler (aka. <tt>groovyc</tt>).
Expand Down Expand Up @@ -275,6 +276,8 @@ public static CompilerConfiguration generateCompilerConfigurationFromOptions(Com
configuration.setTargetDirectory(cli.getOptionValue('d'));
}

configuration.setParameters(cli.hasOption("pa"));

if (cli.hasOption("encoding")) {
configuration.setSourceEncoding(cli.getOptionValue("encoding"));
}
Expand All @@ -287,11 +290,18 @@ public static CompilerConfiguration generateCompilerConfigurationFromOptions(Com
if (cli.hasOption('j')) {
Map<String, Object> compilerOptions = new HashMap<String, Object>();

String[] opts = cli.getOptionValues("J");
compilerOptions.put("namedValues", opts);
String[] namedValues = cli.getOptionValues("J");
compilerOptions.put("namedValues", namedValues);

opts = cli.getOptionValues("F");
compilerOptions.put("flags", opts);
String[] flags = cli.getOptionValues("F");
if (flags != null && cli.hasOption("pa")){
// convert to a list, so we can add a parameter...
List<String> tmp = new ArrayList<String>(Arrays.asList(flags));
tmp.add("parameters");
// convert back to an array...
flags = tmp.toArray(new String[tmp.size()]);
}
compilerOptions.put("flags", flags);

configuration.setJointCompilationOptions(compilerOptions);
}
Expand Down Expand Up @@ -336,6 +346,7 @@ public static Options createCompilationOptions() {
options.addOption(Option.builder("h").longOpt("help").desc("Print a synopsis of standard options").build());
options.addOption(Option.builder("v").longOpt("version").desc("Print the version").build());
options.addOption(Option.builder("e").longOpt("exception").desc("Print stack trace on error").build());
options.addOption(Option.builder("pa").longOpt("parameters").desc("Generate metadata for reflection on method parameter names (jdk8+ only)").build());
options.addOption(Option.builder("j").longOpt("jointCompilation").desc("Attach javac compiler to compile .java files").build());
options.addOption(Option.builder("b").longOpt("basescript").hasArg().argName("class").desc("Base class name for scripts (must derive from Script)").build());

Expand Down
1 change: 1 addition & 0 deletions src/spec/doc/tools-groovy.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ int (disable any int based optimizations) |
| -n | | process files line by line using implicit 'line' variable |
| -p | | process files line by line and print result (see also -n) |
| -v | --version | display the Groovy and JVM versions | groovy -v
| -pa | --parameters | Generates metadata for reflection on method parameter names on JDK 8 and above. Defaults to false. | groovy --parameters Person.groovy
|=======================================================================
3 changes: 3 additions & 0 deletions src/spec/doc/tools-groovyc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ argument. | groovyc -cp lib/dep.jar MyClass.groovy
| | --configscript | Advanced compiler configuration script | groovyc --configscript config/config.groovy src/Person.groovy
| -Jproperty=value | | Properties to be passed to `javac` if joint compilation is enabled | groovyc -j -Jtarget=1.5 -Jsource=1.5 A.groovy B.java
| -Fflag | | Flags to be passed to `javac` if joint compilation is enabled | groovyc -j -Fnowarn A.groovy B.java
| -pa | --parameters | Generates metadata for reflection on method parameter names on JDK 8 and above. Defaults to false. | groovyc --parameters Person.groovy
|=======================================================================

*Notes:*
Expand Down Expand Up @@ -144,6 +145,8 @@ you need to set this flag to true. Defaults to false. |No

|configscript |Set the configuration file used to customize the compilation configuration. |No

|parameters |Generates metadata for reflection on method parameter names on JDK 8 and above. Defaults to false. |No

|=======================================================================

*Example:*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public void testCopyConstructor1() {

init.setWarningLevel(WarningMessage.POSSIBLE_ERRORS);
init.setDebug(true);
init.setParameters(true);
init.setVerbose(false);
init.setTolerance(720);
init.setMinimumRecompilationInterval(234);
Expand All @@ -147,6 +148,7 @@ public void testCopyConstructor1() {

assertEquals(WarningMessage.POSSIBLE_ERRORS, init.getWarningLevel());
assertEquals(true, init.getDebug());
assertEquals(true, init.getParameters());
assertEquals(false, init.getVerbose());
assertEquals(720, init.getTolerance());
assertEquals(234, init.getMinimumRecompilationInterval());
Expand Down Expand Up @@ -194,6 +196,7 @@ public void testCopyConstructor2() {

init.setWarningLevel(WarningMessage.POSSIBLE_ERRORS);
init.setDebug(false);
init.setParameters(false);
init.setVerbose(true);
init.setTolerance(55);
init.setMinimumRecompilationInterval(975);
Expand All @@ -211,6 +214,7 @@ public void testCopyConstructor2() {

assertEquals(WarningMessage.POSSIBLE_ERRORS, init.getWarningLevel());
assertEquals(false, init.getDebug());
assertEquals(false, init.getParameters());
assertEquals(true, init.getVerbose());
assertEquals(55, init.getTolerance());
assertEquals(975, init.getMinimumRecompilationInterval());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,22 @@ public void setScriptBaseClass(final String scriptBaseClass) {
this.scriptBaseClass = scriptBaseClass;
}

/**
* If true, generates metadata for reflection on method parameter names (jdk8+ only). Defaults to false.
*
* @param parameters set to true to generate metadata.
*/
public void setParameters(boolean parameters) {
configuration.setParameters(parameters);
}

/**
* Returns true if parameter metadata generation has been enabled.
*/
public boolean getParameters() {
return configuration.getParameters();
}

/**
* Load the file and then execute it
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
* <li>keepStubs</li>
* <li>forceLookupUnnamedFiles</li>
* <li>configscript</li>
* <li>parameters</li>
* </ul>
* And these nested tasks:
* <ul>
Expand Down Expand Up @@ -215,6 +216,12 @@ public class Groovyc extends MatchingTask {

private Set<String> scriptExtensions = new LinkedHashSet<String>();


/**
* If true, generates metadata for reflection on method parameter names (jdk8+ only). Defaults to false.
*/
private boolean parameters = false;

/**
* Adds a path for source compilation.
*
Expand Down Expand Up @@ -803,6 +810,22 @@ public boolean getForceLookupUnnamedFiles() {
return forceLookupUnnamedFiles;
}

/**
* If true, generates metadata for reflection on method parameter names (jdk8+ only). Defaults to false.
*
* @param parameters set to true to generate metadata.
*/
public void setParameters(boolean parameters) {
this.parameters = parameters;
}

/**
* Returns true if parameter metadata generation has been enabled.
*/
public boolean getParameters() {
return this.parameters;
}

/**
* Executes the task.
*
Expand Down Expand Up @@ -1034,6 +1057,13 @@ private void doForkCommandLineList(List<String> commandLineList, Path classpath,
}
}

/**
* Add "groovyc" parameters to the commandLineList, based on the ant configuration.
*
* @param commandLineList
* @param jointOptions
* @param classpath
*/
private void doNormalCommandLineList(List<String> commandLineList, List<String> jointOptions, Path classpath) {
commandLineList.add("--classpath");
commandLineList.add(classpath.toString());
Expand All @@ -1052,6 +1082,9 @@ private void doNormalCommandLineList(List<String> commandLineList, List<String>
if (stacktrace) {
commandLineList.add("-e");
}
if (parameters) {
commandLineList.add("--parameters");
}
if (useIndy) {
commandLineList.add("--indy");
}
Expand Down
1 change: 1 addition & 0 deletions subprojects/groovy-ant/src/spec/doc/groovy-ant-task.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Assuming `groovy-all-VERSION.jar` is in `my.classpath` you will need to declare
|fork|If enabled the script will be executed in another JVM (disabled by default).|No
|scriptBaseClass|The name of the base class for scripts.|No
|indy|If enabled the script will be executed with `invokedynamic` (disabled by default).|No
|parameters |Generates metadata for reflection on method parameter names on JDK 8 and above. Defaults to false. |No
|============================================

== Parameters specified as nested elements
Expand Down