Hi everyone tried different ways to run a groovy in java with no luck, had read some documentation but things aren't that clear at the moment.
Anyone may know how to run this groovy?
package com.test.dev.search;
public class SearchQueryBase implements SearchQuery {
public QueryString getMatterQuery( SearchFilter filter ) {
String[] terms = filter.getSearchTerm().toLowerCase().split( " " );
...
...
...
}
}
This is a .groovy file (the one from above), I've tried the follow to run it without luck.
Down here is the Java class in which I want to run the above Groovy and execute getMatterQuery() to see the output from java main.
public static void main(String args[]) throws CGException {
String TEMPLATE_PACKAGE_PREFIX = "<path_to_groovy_file.";
String templateFileName = TEMPLATE_PACKAGE_PREFIX + "SearchQueryBase";
SearchFilter test = null;
Binding binding = new Binding();
binding.setVariable("filter", test);
GroovyShell shell = new GroovyShell(binding);
shell.evaluate(templateFileName);
System.out.println("Finish");
}
EDIT #1
This is the error I'm getting when I run it;
Exception in thread "main" groovy.lang.MissingPropertyException: No such property: Common for class: Script1
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)
at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
at Script1.run(Script1.groovy:1)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:580)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:618)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:589)
1.
the GroovyShell.evaluate(java.lang.String scriptText) accepts string as a groovy text (content), and you try to call it with filename instead. use shell.evaluate( new File(templateFileName) )
2.
you can continue using shell.evaluate( new File(...) ) but keep in your groovy file only content of the method getMatterQuery():
String[] terms = filter.getSearchTerm().toLowerCase().split( " " );
...
...
...
so you'll have groovy script, and your code should work
3.
if you want to keep groovy as a class and call the method getMatterQuery() from this class with parameter, then your java code should be like this:
import groovy.lang.*;
...
public static void main(String[]s)throws Exception{
GroovyClassLoader cl=new GroovyClassLoader();
//path to base folder where groovy classes located
cl.addClasspath(path_to_groovy_root);
//the groovy file with SearchQueryBase.groovy
//must be located in "com/test/dev/search" subfolder under path_to_groovy_root
Class c = cl.loadClass("com.test.dev.search.SearchQueryBase");
SearchQuery o = (SearchQuery) c.newInstance();
System.out.println( o.getMatterQuery(test) );
}
Related
I am really stumped. I'm just an old C X11/Motif programmer trying to write a little Java program. After a week of reading the Oracle Java Documentation, as well as the
Stack Overflow answers related to getResource, I still can not figure out how to retrieve the path to the icon files in my jar file.
My icons are contained within the jar file for my application. I wish to access them using the relative position within jar file. I am assuming the best way to do this is through the getResource method.
The core part of my code for my program called Fŭd (pronounced food - like the cat spells it in the comic strip "Get Fuzzy") is as follows:
package localhost.system1;
imports not shown for brevity.
public class Fud extends JPanel
implements FocusListener, ActionListener, ItemListener
{
private static final long serialVersionUID = 1L;
static Food data = null;
static int prev = 0;
static int next = 1;
static int plus = 2;
static int minus = 3;
public static void main(String args[]) throws Exception
{
LocalDate now = LocalDate.now();
int dateDifference = 0;
// load in the existing data
data = new Food(programName);
data.loadFood(programName);
// test to see if data is up to date. Add days if not
dateDifference = Math.abs((int)ChronoUnit.DAYS.between(now, data.day[0].date));
if ( dateDifference != 0)
{
data.adjustToToday(dateDifference, programName);
}
/////////////////////////////////////////////////
// create the GUI and switch running over to it.
/////////////////////////////////////////////////
Fud fud = new Fud();
Class<? extends Fud> fudClass = fud.getClass();
String className = fudClass.getName();
System.out.println("fudClass getname returns " + className);
URL testURL = fudClass.getResource("prev.png");
System.out.println("fudClass getResource returned " + testURL);
// Create GUI and turn the control over to it
javax.swing.SwingUtilities.invokeLater
(new Runnable()
{
public void run()
{
URL[] iconURL = new URL[4];
iconURL[prev] = Fud.class.getResource("prev.png");
iconURL[next] = Fud.class.getResource("next.png");
iconURL[plus] = Fud.class.getResource("plus.png");
iconURL[minus] = Fud.class.getResource("minus.png");
createAndShowGUI(fud, iconURL);
}
}
);
} // end of main
.
.
.
Rest of methods and subroutines needed
.
.
.
}
When run, the code returns the following results:
fudClass getname returns localhost.system1.Fud
fudClass getResource returned null
This has me quite frustrated. No matter what I try (and I have tried a number of things) the result remains the same. I keep getting NULL for a response from the getResource method. When I query the jar file with jar -tf Fud.jar I get the following:
jar tf Fud.jar
META-INF/MANIFEST.MF
localhost/
localhost/system1/
localhost/system1/Day.class
localhost/system1/Food.class
localhost/system1/Fud$1.class
localhost/system1/Fud$2.class
localhost/system1/Fud$3.class
localhost/system1/Fud$4.class
localhost/system1/Fud$5.class
localhost/system1/Fud$6.class
localhost/system1/Fud$7.class
localhost/system1/Fud.class
minus.png
next.png
plus.png
prev.png
So the icons are in the Jar file. Can anyone tell me what I am doing wrong? In Eclipse, my project explorer looks like:eclipse Project Explorer
I added the Image directory to my project Java build in eclipse as follows: Eclipse Java Build
I built the program using Eclipse Version: 2021-12 (4.22.0) Build id: 20211202-1639. Furthermore, I am using Java 17.0.1 2021-10-19 LTS on Windows 11 Pro build 22000.434.
You have to add a slash in front of the resource:
Fud.class.getResource("/prev.png");
otherwise java searching in the same folder as the class is located,
so it will search in localhost/system1
I want to instatiate a groovy class and i have some concerns
My first choice is to use GroovyShell :
groovy-script:
class Foo {
public String doStuff(String stuff) {
return stuff + "_utils";
}
}
new Foo(); // ??
main-script :
GroovyShell shell = new GroovyShell();
Script script = shell.parse(new File(path));
def clazz = script.run();
String result = clazz.doStuff("test");
print(result); // test_utils;
The second option is to use GroovyClassLoader :
groovy-script
class Foo {
public String doStuff(String stuff) {
return stuff + "_utils";
}
}
main-script
GroovyClassLoader loader = new GroovyClassLoader();
Script script = loader.parseClass(new File(path))
Object clazz = script.newInstance();
Object[] args = new Object[1];
args[0] = "test";
String result = clazz.invokeMethod("doStuff", args);
print(result) // test_utils
Both will run fine, i would prefer to use GroovyShell because i use it everywhere in my current code, but i don't know if new Foo() inside my scripts can cause any memory leaks. Is it possible?
GroovyShell uses the default GroovyClassLoader. So if you don't need any extra specific features that are provided by GroovyClassLoader, you should stick to GroovyShell to keep it simple. GroovyShell and GroovyClassLoader are instances of garbage collected and I don't believe there are memory leaks for neither of them.
After #daggett's help i managed to find the solution that fits my needs.
I will not use groovy classes at all.
A simple example
utility groovy script :
String doStuff() {
return "doStuff";
}
String doStuff2(){
return "doStuff2";
}
calling the utility methods from the main groovy script
GroovyShell shell = new GroovyShell();
Script utilsScript = shell.parse(new File(PATH_TO_UTIL_SCRIPT));
String result = utilsScript.doStuff();
println(result); // doStuff;
String result2 = utilsScript.doStuff2();
println(result2); // doStuff2;
This is not the answer to the original question but since it fits my need i am fine.
I am successfully able to compile Groovy in Java at runtime and store it in a database and pull it out. I can't compile a Groovy class if it has inner classes or an inner enum. Has anyone successfully compiled Groovy code like this and included inner classes/enums and able to pull the script out by classname?
For example, I want to load the "Test" script shown below that contains inner classes and run the script at run time.
Compiler code:
public byte[] compileGroovyScript(final String className, final String script) {
byte[] compiledScriptBytes = null;
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(className, script);
compileUnit.compile(Phases.CLASS_GENERATION);
for (Object compileClass : compileUnit.getClasses()) {
GroovyClass groovyClass = (GroovyClass) compileClass;
compiledScriptBytes = groovyClass.getBytes();
}
return compiledScriptBytes;
}
Code to pull script out:
public Class getGroovyScript(final String className, final byte[] script) {
Class clazz = null;
try (GroovyClassLoader classLoader = new GroovyClassLoader(this.getClass().getClassLoader())) {
clazz = classLoader.defineClass(className, script);
} catch (IOException e) {
} catch (Exception e) {
}
return clazz;
}
Code to run the script:
Class groovyClass = app.getGroovyScript(className, compiledScript);
TestScript script = (TestScript) groovyClass.newInstance();
System.out.println(script.getMessage());
Groovy script:
import com.groovy.groovy.TestScript
class Test implements TestScript {
String getMessage() {
[1..10].each(){
println it
}
return "Jello"
}
}
It isn't clear from the description why you are doing the compiling yourself. If you can just let Groovy do it for you then the whole thing can just be simplified to something like this:
String script = // string containing the script you want to parse
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
Class theParsedClass = groovyClassLoader.parseClass(script);
Ok this may be a little late but hopefully it helps the next person. I think you need to save a List for each groovy class and then cl.defineClass and finally cl.loadClass. I think groovy sometimes compile to a list of classes basically as in below when I addSource(), I add one class and then loop over all the generated classes from that one file.
This is the code I am currently running(though I have not tried saving and reloading at a later time)
GroovyClassLoader cl = new GroovyClassLoader();
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(scriptCode.getClassName(), scriptCode.getScriptSourceCode());
compileUnit.compile(Phases.CLASS_GENERATION);
compileUnit.setClassLoader(cl);
GroovyClass target = null;
for (Object compileClass : compileUnit.getClasses()) {
GroovyClass groovyClass = (GroovyClass) compileClass;
cl.defineClass(groovyClass.getName(), groovyClass.getBytes());
if(groovyClass.getName().equals(scriptCode.getClassName())) {
target = groovyClass;
}
}
if(target == null)
throw new IllegalStateException("Could not find proper class");
return cl.loadClass(target.getName());
take note of the cl.defineClass call which puts the class in the classloader so when it is looked up(the enum or innerclass), it will be there.
and so now I think you do not need to create your own class loader(though you avoid useless defineClass until it is needed with your own classloader which can be useful and more performant).
This forgoes any error handling for the sake of simplicity here, but this is probably what you want:
public byte[] compileGroovyScript(final String className, final String script) {
byte[] compiledScriptBytes = null;
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(className, script);
compileUnit.compile(Phases.CLASS_GENERATION);
List classes = compileUnit.getClasses();
GroovyClass firstClass = (GroovyClass)classes.get(0);
compiledScriptBytes = firstClass.getBytes();
return compiledScriptBytes;
}
Depending on your requirements, you might want to provide access to the inner classes and you could do that with something like this which finds the class with the matching name instead of assuming the first class:
public byte[] compileGroovyScript(final String className, final String script) {
byte[] compiledScriptBytes = null;
CompilationUnit compileUnit = new CompilationUnit();
compileUnit.addSource(className, script);
compileUnit.compile(Phases.CLASS_GENERATION);
for (Object compileClass : compileUnit.getClasses()) {
GroovyClass groovyClass = (GroovyClass) compileClass;
if(className.equals(groovyClass.getName())) {
compiledScriptBytes = groovyClass.getBytes();
break;
}
}
return compiledScriptBytes;
}
I am running into this myself but having just done an on-demand java compiler at runtime, I believe you are running into the same issue I solved in this code
https://github.com/deanhiller/webpieces/tree/master/runtimecompile/src/main/java/org/webpieces/compiler/api
webpieces/runtimecompile is a re-usable on-demand java compiler using the eclipse compiler.
Now, for groovy, I think you are running into this case
1. you compile ONE script
2. this results in 'multiple' class file objects (I think) just like mine did
3. This is where you need to store EACH in the database SEPARATELY
4. Then you need a classloader that tries to lookup the 'inner classes' when jvm asks for it
5. finally you do a yourclassLoader.loadApplicationClass (much like the one in CompileOnDemandImpl.java in the project above
6. To be clear, step 5 causes step 4 to happen behind the scenes (and that is what is confusing).
If you step through the test case AnonymousByteCacheTest, it pretty much is doing something like that.
you don't need to install ANYTHING to run the build on that project, just clone it and "./gradlew test" and will pass and "./gradlew eclipse" or "./gradlew idea" and it generates IDE files so you can step through it.
It is very very similar. I am trying to get the groovy version working next myself.
I downloaded apache commons FileUtils to perform a copy directory and added them under libraries in eclipse as well. When I say Fileutils.copyDirectory(s,d) as give below eclipse says " Multiple markers at this line -Syntax error on token "(", delete this token
-Syntax error on token ")", delete this token". Can someone help
import org.apache.commons.io.FileUtils;
Public class b {
File s = new file("C://Tom//eso");
File d = new file("C://Tom//pos");
FileUtils.copyDirectory(s,d);
}
Try this:
import org.apache.commons.io.FileUtils;
public class B {
public static void main(String[] args) throws Exception {
File s = new File("C:/Tom/eso");
File d = new File("C:/Tom/pos");
FileUtils.copyDirectory(s,d);
}
}
There are several errors in your code:
Classes start with an uppercase char - it's File, not file. And it's class B, not class b (remember to also rename the file to B.java)
You must not use double / chars, just one
The code must reside inside a method, not at the class level
It's public, not Public
You're not handling exceptions, either throw them or catch them
File s = new file("C://Tom//eso");
File d = new file("C://Tom//pos");
file should be capitalized. It should be new File(....
Side note: Usually for windows the path looks like C:\\Tom\\eso, you have forward-slashes instead of backward.
You're trying to call a method outside of the body of a method...try something more along the lines of;
public class b {
public static void main(String args[]) {
File s = new File("C:/Tom/eso");
File d = new File("C:/Tom/pos");
try {
FileUtils.copyDirectory(s,d);
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
Just to highlight...
Public should be public
file should be File
// should be either / or \\ (most people prefer /)
Execution code must be executed from the context of a method or static init section
I'd also recommend that you take the time to learn the Java naming conventions as well as have a read through the tutorials under the Trails Covering the Basics section
Two errors.
First
File s = new file("C://Tom//eso");
File d = new file("C://Tom//pos");
should be
File s = new File("C://Tom//eso");
File d = new File("C://Tom//pos");
Second
FileUtils.copyDirectory(s,d);
should in main method.
I'm trying to get require.js to load modules on the server-side with Java 6 and Rhino.
I'm able to load require.js itself just fine. Rhino can see the require() function. I can tell because Rhino complains that it can't find the function when I change require() to something else like requireffdkj().
But when I try to require even a simple JS, like hello.js
var hello = 'hello';
using either of the following:
require('hello');
require('./hello');
it doesn't work. I get
Caused by: javax.script.ScriptException: sun.org.mozilla.javascript.internal.JavaScriptException: [object Error] (<Unknown source>#31) in <Unknown source> at line number 31
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:153)
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:167)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
I have my hello.js at the top of the Java classpath. That's where I have require.js as well. I tried moving hello.js everywhere I could think it might possibly go, including the root of my hard drive, the root of my user directory, the directory from which I'm running my Java app, etc. Nothing works.
I looked at the CommonJS spec (http://wiki.commonjs.org/wiki/Modules/1.0) and it says that top-level IDs (like hello) are resolved from the "conceptual module name space root", whereas relative IDs (like ./hello) are resolved against the calling module. I'm not sure where either of those baselines is, and I suspect that's the issue.
Any suggestions? Can I even use require.js from Rhino?
EDIT: Thinking that I need to set the environment up as per Pointy's suggestion in the comment below, I tried evaluating r.js as well. (I tried evaluating after evaluating require.js, and then again before require.js.) In either case I get an error:
Caused by: javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "arguments" is not defined. (<Unknown source>#19) in <Unknown source> at line number 19
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:153)
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:167)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
"arguments" appears to be a variable in r.js. I think it's for command line arguments, so I don't think r.js is the right path for what I'm trying to do. Not sure though.
require.js works well with rhino. Recently, I used it in a project.
You have to make sure to use r.js (not require.js) , modified version of require.js for rhino.
You have to extend ScritableObject class to implement load and print function. When you call require(["a"]), the load function in this class will be called, you can tweak this function to load the js file from any location. In the below example, I load from classpath.
You have to define the property arguments in the sharedscope as shown below in the sample code
Optionally, you can configure the sub path using require.config, to specify the subdirectory inside classpath where js files are located.
JsRuntimeSupport
public class JsRuntimeSupport extends ScriptableObject {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(JsRuntimeSupport.class);
private static final boolean silent = false;
#Override
public String getClassName() {
return "test";
}
public static void print(Context cx, Scriptable thisObj, Object[] args,
Function funObj) {
if (silent)
return;
for (int i = 0; i < args.length; i++)
logger.info(Context.toString(args[i]));
}
public static void load(Context cx, Scriptable thisObj, Object[] args,
Function funObj) throws FileNotFoundException, IOException {
JsRuntimeSupport shell = (JsRuntimeSupport) getTopLevelScope(thisObj);
for (int i = 0; i < args.length; i++) {
logger.info("Loading file " + Context.toString(args[i]));
shell.processSource(cx, Context.toString(args[i]));
}
}
private void processSource(Context cx, String filename)
throws FileNotFoundException, IOException {
cx.evaluateReader(this, new InputStreamReader(getInputStream(filename)), filename, 1, null);
}
private InputStream getInputStream(String file) throws IOException {
return new ClassPathResource(file).getInputStream();
}
}
Sample Code
public class RJsDemo {
#Test
public void simpleRhinoTest() throws FileNotFoundException, IOException {
Context cx = Context.enter();
final JsRuntimeSupport browserSupport = new JsRuntimeSupport();
final ScriptableObject sharedScope = cx.initStandardObjects(browserSupport, true);
String[] names = { "print", "load" };
sharedScope.defineFunctionProperties(names, sharedScope.getClass(), ScriptableObject.DONTENUM);
Scriptable argsObj = cx.newArray(sharedScope, new Object[] {});
sharedScope.defineProperty("arguments", argsObj, ScriptableObject.DONTENUM);
cx.evaluateReader(sharedScope, new FileReader("./r.js"), "require", 1, null);
cx.evaluateReader(sharedScope, new FileReader("./loader.js"), "loader", 1, null);
Context.exit();
}
}
loader.js
require.config({
baseUrl: "js/app"
});
require (["a", "b"], function(a, b) {
print('modules loaded');
});
js/app directory should be in your classpath.