提交 b272a2df authored 作者: noelgrandin's avatar noelgrandin

Issue 442: groovy patch for SourceCompiler (function ALIAS)

上级 1140d4a9
......@@ -441,6 +441,8 @@ parameter count, all methods are mapped.
Admin rights are required to execute this command.
This command commits an open transaction.
If you have the Groovy jar in your classpath, it is also possible to write methods using Groovy.
","
CREATE ALIAS MY_SQRT FOR ""java.lang.Math.sqrt"";
CREATE ALIAS GET_SYSTEM_PROPERTY FOR ""java.lang.System.getProperty"";
......@@ -448,6 +450,11 @@ CALL GET_SYSTEM_PROPERTY('java.class.path');
CALL GET_SYSTEM_PROPERTY('com.acme.test', 'true');
CREATE ALIAS REVERSE AS $$ String reverse(String s) { return new StringBuilder(s).reverse().toString(); } $$;
CALL REVERSE('Test');
CREATE ALIAS tr AS $$@groovy.transform.CompileStatic
static String tr(String str, String sourceSet, String replacementSet){
return str.tr(sourceSet, replacementSet);
}
$$
"
"Commands (DDL)","CREATE CONSTANT","
......
......@@ -38,6 +38,7 @@ Change Log
</li><li>Issue 274: Sybase/MSSQLServer compatibility - swap parameters of CONVERT function.
</li><li>Issue 274: Sybase/MSSQLServer compatibility - support index clause e.g. "select * from test (index table1_index)"
</li><li>Fix bug in optimising SELECT * FROM A WHERE X=1 OR X=2 OR X=3 into SELECT * FROM A WHERE X IN (1,2,3)
</li><li>Issue 442: groovy patch for SourceCompiler (function ALIAS)
</li></ul>
<h2>Version 1.3.171 (2013-03-17)</h2>
......
......@@ -77,6 +77,13 @@ public class SourceCompiler {
return compiledClass;
}
String source = sources.get(packageAndClassName);
if (isGroovySource(source)) {
Class<?> clazz = GroovyCompiler.parseClass(source, packageAndClassName);
compiled.put(packageAndClassName, clazz);
return clazz;
}
ClassLoader classLoader = new ClassLoader(getClass().getClassLoader()) {
public Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> classInstance = compiled.get(name);
......@@ -105,6 +112,10 @@ public class SourceCompiler {
return classLoader.loadClass(packageAndClassName);
}
private static boolean isGroovySource(String source) {
return source.startsWith("//groovy") || source.startsWith("@groovy");
}
/**
* Get the first public static method of the given class.
*
......@@ -116,8 +127,9 @@ public class SourceCompiler {
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
int modifiers = m.getModifiers();
if (Modifier.isPublic(modifiers)) {
if (Modifier.isStatic(modifiers)) {
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) {
String mname = m.getName();
if (!mname.startsWith("_") && !m.getName().equals("main")) {
return m;
}
}
......@@ -248,5 +260,57 @@ public class SourceCompiler {
throw DbException.get(ErrorCode.SYNTAX_ERROR_1, err);
}
}
/**
* Access the groovy compiler using reflection, so that we do not gain a compile-time dependency
* unnecessarily.
*/
private static final class GroovyCompiler {
private static final Object loader;
private static final Throwable initfailException;
static {
Object tmpLoader = null;
Throwable tmpInitfailException = null;
try {
// create an instance of ImportCustomiser
Class<?> importCustomizerClass = Class.forName("org.codehaus.groovy.control.customizers.ImportCustomizer");
Object importCustomizer = Utils.newInstance("org.codehaus.groovy.control.customizers.ImportCustomizer");
// Call the method ImportCustomizer#addImports(String[])
String[] importsArray = new String[] { "java.sql.Connection", "java.sql.Types", "java.sql.ResultSet",
"groovy.sql.Sql", "org.h2.tools.SimpleResultSet" };
Utils.callMethod(importCustomizer, "addImports", new Object[] { importsArray });
// Call the method CompilerConfiguration#addCompilationCustomizers(ImportCustomizer...)
Object importCustomizerArray = java.lang.reflect.Array.newInstance(importCustomizerClass, 1);
java.lang.reflect.Array.set(importCustomizerArray, 0, importCustomizer);
Object configuration = Utils.newInstance("org.codehaus.groovy.control.CompilerConfiguration");
Utils.callMethod(configuration, "addCompilationCustomizers", new Object[] { importCustomizerArray });
ClassLoader parent = GroovyCompiler.class.getClassLoader();
tmpLoader = Utils.newInstance("groovy.lang.GroovyClassLoader", parent, configuration);
} catch (Exception ex) {
tmpInitfailException = ex;
}
loader = tmpLoader;
initfailException = tmpInitfailException;
}
public static Class<?> parseClass(String source, String packageAndClassName) {
if (loader == null) {
throw new RuntimeException("compile fail: there is no groovy jar on the classpath?", initfailException);
}
try {
Object codeSource = Utils.newInstance("groovy.lang.GroovyCodeSource", source, packageAndClassName
+ ".groovy", "UTF-8");
Utils.callMethod(codeSource, "setCachable", false);
Class<?> clazz = (Class<?>) Utils.callMethod(loader, "parseClass", codeSource);
return clazz;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论