Avoiding sharing Java meta classes across different Groovy scripts - java

My situation
I call multiple Groovy scripts from Java, they both contain long-lived Groovy objects.
I would like my Groovy scripts to make some changes to a Java meta-class for a Java class (that have about 100 instances). However, the scripts should be able to make different changes, and changes in one of the scripts should not be reflected in the other scripts.
The problem: The meta-class for the Java class is shared across all the scripts.
This question is similar to How do I undo meta class changes after executing GroovyShell? but in this case I want two scripts to execute simultaneously, so it is not possible to reset after script execution.
Example Code
SameTest.java
public interface SameTest {
void print();
void addMyMeta(String name);
void addJavaMeta(String name);
void callMyMeta(String name);
void callJavaMeta(String name);
}
SameSame.java
import groovy.lang.Binding;
import groovy.util.GroovyScriptEngine;
public class SameSame {
public SameTest launchNew() {
try {
GroovyScriptEngine scriptEngine = new GroovyScriptEngine(new String[]{""});
Binding binding = new Binding();
binding.setVariable("objJava", this);
SameTest script = (SameTest) scriptEngine.run("test.groovy", binding);
return script;
} catch (Exception | AssertionError e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
SameSame obj = new SameSame();
SameTest a = obj.launchNew();
SameTest b = obj.launchNew();
a.addMyMeta("a");
a.callMyMeta("a");
try {
b.callMyMeta("a");
throw new AssertionError("Should never happen");
} catch (Exception ex) {
System.out.println("Exception caught: " + ex);
}
a.addJavaMeta("q");
b.callJavaMeta("q");
a.print();
b.print();
}
}
test.groovy
ExpandoMetaClass.enableGlobally()
class Test implements SameTest {
SameSame objJava
void print() {
println 'My meta class is ' + Test.metaClass
println 'Java meta is ' + SameSame.metaClass
}
void addMyMeta(String name) {
println "Adding to Groovy: $this $name"
this.metaClass."$name" << {
"$name works!"
}
}
void addJavaMeta(String name) {
println "Adding to Java: $this $name"
objJava.metaClass."$name" << {
"$name works!"
}
}
void callMyMeta(String name) {
println "Calling Groovy: $this $name..."
"$name"()
println "Calling Groovy: $this $name...DONE!"
}
void callJavaMeta(String name) {
println "Calling Java: $this $name..."
objJava."$name"()
println "Calling Java: $this $name...DONE!"
}
}
new Test(objJava: objJava)
Output
Adding to Groovy: Test#7ee955a8 a
Calling Groovy: Test#7ee955a8 a...
Calling Groovy: Test#7ee955a8 a...DONE!
Calling Groovy: Test#4a22f9e2 a...
Exception caught: groovy.lang.MissingMethodException: No signature of method: Test.a() is applicable for argument types: () values: []
Possible solutions: any(), any(groovy.lang.Closure), is(java.lang.Object), wait(), wait(long), each(groovy.lang.Closure)
Adding to Java: Test#7ee955a8 q
Calling Java: Test#4a22f9e2 q...
Calling Java: Test#4a22f9e2 q...DONE!
My meta class is groovy.lang.ExpandoMetaClass#2145b572[class Test]
Java meta is groovy.lang.ExpandoMetaClass#39529185[class SameSame]
My meta class is groovy.lang.ExpandoMetaClass#72f926e6[class Test]
Java meta is groovy.lang.ExpandoMetaClass#39529185[class SameSame]
Desired result
The two lines showing information about the Java meta should be different.
This should crash:
a.addJavaMeta("q");
b.callJavaMeta("q");
The question
Is it possible somehow to use different MetaClassRegistry's in the different GroovyScriptEngine instances?
Or is there any other way to make the desired result as shown above happen?

The feature you are looking for is one I had planed for Groovy 3. But since I will no longer be able to work full time on Groovy and since nobody else dares a big change to the MOP this is no option at the moment.
So is it possible to use different MetaClassRegistry's in the different GroovyScriptEngine instances?
No, since you cannot use different MetaClassRegistry's. The implementation is somewhat abstracted, but the usage of MetaClassRegistryImpl is hardcoded and allows for only one global version.
Or is there any other way to make the desired result as shown above happen?
That depends on your requirements.
If you could let the scripts not share the Java classes (load them using differing class loaders), then you don't have a problem with shared meta classes to begin with (for those). If you want more the idea bayou.io had might be best.
You could provide your own meta class creation handle (see setMetaClassCreationHandle in MetaClassRegistry). Then you would have to of course capture a call like ExpandoMetaClass.enableGlobally(). You could use ExpandoMetaClass with a custom invoker (set someClass.metaClass.invokeMethod = ...) or of course directly extend the class. You would then somehow need a way to recognize that you are coming from one script or the other (there is something called origin or caller in the bigger invokemethod signature, but the information is not always reliable. Same thing for get/setProperty). As for how to reliably and efficiently transport that information... well.. that's something I have no answer for. You have to experiment if what ExpandoMetaClass provides is good enough for you. Maybe you could use a ThreadLocal to store the information... though then you would have to write a transform, which will rewrite all method and property calls and most probably cause a performance disaster.

Related

Verify whether a method parameter is used in the method body

I have an interface which looks like the following
interface Evaluator {
boolean requiresP2();
EvalResult evaluate(Param1 p1, Param2 p2, Param3 p3);
// some more methods
}
This interface is implemented by several classes. The parameter p2 of the evaluate method is used by some and not used by others. The method requiresP2 basically returns a boolean telling whether the evaluate method uses p2 or not.
Now, this questions may appear a little weird out of context but believe me, it makes sense in our use case. Plus, it would require a lot of time to refactor all the code to eliminate the need for the requiresP2 method so I would appreciate if we discuss solutions other than a top-to-bottom refactoring of the codebase.
The problem is that the return value of method requiresP2 is based on how the evaluate method is implemented. Therefore everyone must ensure that they update the requiresP2 method when they change the evaluate method.
I am looking for ways so that this can be enforced by the compiler/unit-tests/linters rather than leaving it to the developer's memory.
EDIT: I am still exploring the applicability of mocking frameworks to this problem.
I thought that I could reflection in unit tests to inspect evaluate's body in the unit test to check if it refers to p2 or not and then making sure it matches with the value returned by requiresP2 method but it seems that it is not possible to inspect method body using reflection.
I am looking for suggestions on how to do this. Any input is appreciated.
There is another option you did not mention: a Static Code Analysis tool.
You can use the SonarQube + SonarLint combination in order to get your desired enforcement:
Use the SonarQube server in order to create a new static code analysis rule, which will be based on the interface you are using and your unique use case.
Then install SonarLint on your IDE/IDEs (Eclipse and IntelliJ are both supported), and connect it to the SonarQube server.
This way the static code analysis scan will detect improper usage of your interface and indicate this with a visual marking in the IDE, on the relevant code lines (which is actually linting your code).
You can use ASM to check whether the parameter is used.
To add it to your project using e.g. Apache Ivy, you would add this to ivy.xml:
<dependency org="org.ow2.asm" name="asm" rev="6.1.1" />
Or do the equivalent for Maven, Gradle, etc. Then you can check on the parameter by:
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
// . . .
public static boolean usesP2(Evaluator evaluator) {
AtomicBoolean usesP2 = new AtomicBoolean(false);
String internalName = evaluator.getClass().getName().replace('.', '/');
String classFileResource = "/" + internalName + ".class";
ClassVisitor visitor = new ClassVisitor(Opcodes.ASM6) {
#Override
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
if ("evaluate".equals(name)) {
return new MethodVisitor(Opcodes.ASM6) {
#Override
public void visitVarInsn(final int insn, final int slot) {
if (slot == 2) usesP2.set(true);
}
};
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
};
try (InputStream is = Evaluator.class.getResourceAsStream(classFileResource)) {
ClassReader reader = new ClassReader(is);
reader.accept(visitor, 0);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return usesP2.get();
}
public static void assertCorrectlyDocumentsP2(Evaluator evaluator) {
boolean usesP2 = usesP2(evaluator);
if (usesP2 && !evaluator.requiresP2()) {
throw new AssertionError(evaluator.getClass().getName() +
" uses P2 without documenting it");
}
if (!usesP2 && evaluator.requiresP2()) {
throw new AssertionError(evaluator.getClass().getName() +
" says it uses P2 but does not");
}
}
Unit tests:
#Test
public void testFalsePositive() {
assertCorrectlyDocumentsP2(new FalsePositive());
}
#Test
public static void testFalseNegative() {
assertCorrectlyDocumentsP2(new FalseNegative());
}
(This supposes there are two bad Evaluators, FalsePositive and FalseNegative, one of which documents that it uses P2 but doesn't, and the other which doesn't document that it uses P2 even though it does, respectively.)
Note: In usesP2 we check for a variable instruction (an instruction which accesses a local variable) in slot 2 of the stack frame. The slots are numbered from 0, and the first one is this. P2 is in slots 2 only because Evaluator::evaluate is an instance method. If it were a static method, we would have to check if slot 1 were used in order to detect if parameter P2 were used. Caveat lector.

Command pattern vs reflection

I have controller that executes some commands according to command name, taken from url. The main point is in not to use if and switch clauses. As I know there are ONLY two ways how to do it - 1) command pattern 2) reflection.
//Command pattern
class Controller{
private HashMap<String,Command> commands;
public void executeCommand(String commandName){
commands.get(commandName).execute();
}
...
}
//reflection
class Controller{
public void readCommand(){
....
}
public void executeCommand(String commandName){
this.getClass().getMethod(commandName+"Command").invoke(this);
}
...
}
So the questios:
Which one is better?
Is it normal in one application to let developers use one of the methods they want.
Are there other ways?
first way is better, use reflections only when don't have other options.
in one application there should be one approach to solve one kind of problem.
I think the first approach is fine. (much better then if/else blocks)
Which one is better?
Obviously first one is better. Even though you have quoted that you are using Command pattern, it's not complete "Command" pattern. Command pattern will have Command (abstract), Concrete Command, Receiver, Invoker and Client.
Have a look at this question:
Using Command Design pattern
Apart from Command Patten, I would like to highlight pros and cons of reflection.
Pros:
Handling dependency injection
Developing plug and play frameworks
Cons:
Reflection calls are slower
You can violate security and explode application with bad intent ( e.g. setting private variables of a class, which is invisible to other class)
Have a look at related SE question regarding Reflection :
What is reflection and why is it useful?
Is it normal in one application to let developers use one of the methods they want.
It is normal for developers to chose best method to solve a particular problem.
Are there other ways?
It depends on type of problem you are going to address. Design patterns provides solutions to recurring problems.
All solution can't be fit in existing design patterns. You may have developed new patterns to solve your problem.
I think there are 2 different ways for your first approach. Each command could be a subclass of the abstract class Command. Or each command could be an instance of the class command. That depends on how flexible that is all supposed to be, and are the are parameters and return values for commands? With subclasses it would look like this (just to get the idea):
abstract public class Command {
abstract public void execute();
}
public class LsCommand extends Command
{
#Override
public void execute() {
try {
Runtime.getRuntime().exec("ls");
} catch (IOException e) {}
}
}
public class ChdirCommand extends Command
{
#Override
public void execute() {
try {
Runtime.getRuntime().exec("chdir");
} catch (IOException e) {}
}
}
Here my answers:
Your first way is better. Always prefer design patterns over
reflection.
Sorry I don't understand question 2. But it doesn't have a question mark anyway, so I just skip it :)
You might want to look into the Strategy design pattern, where each command could even be made of different parts of sub commands.
Another idea would be the Factory design pattern. In that case you
would put each command into a class and then use the ClassLoader to
load the class by name.
It is not obviously one vs another. You can have both:
public class Controller {
public void executeCommand(String commandName){
CommandFactory.getCommand(commandName).execute();
}
}
public class CommandFactory {
private static final String COMMAND_PACKAGE = "come.example.command.";
private static Map<String, Command> commandMap = new HashMap<>();
public static Command getCommand (String commandName){
if (commandMap.containsKey(commandName)){
return commandMap.get(commandName);
}
String commandNameCapitalized = commandName.substring(0, 1).toUpperCase() + commandName.substring(1);
String commandClassString = COMMAND_PACKAGE + commandNameCapitalized;
try {
Class commandClass = Class.forName(commandClassString);
Command command = (Command) commandClass.newInstance();
commandMap.put(commandName, command);
return command;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}

Groovy No signature of method calling Java library

As many questions begin, this is driving me crazy.
I have a homegrown StarTeam java library. I have one static method like this:
public static Label getLatestDeploymentLabel(com.starbase.starteam.File child) {
// blah
}
The method works as expected when I call it from java. When I call it from Groovy, I get:
Caught: groovy.lang.MissingMethodException:
No signature of method: static pkg.starteam.StarTeamUtils.getLatestDeploymentLabel()
is applicable for argument types: (com.starbase.starteam.File)
values: [FILENAME-FOO.sql] at starteam.run(starteam.groovy:54)
I put in a println right before I call that method:
chgset.elements().each() { item ->
println "type of item is ${item.class.getName()}"
def latestlabel = StarTeamUtils.getLatestDeploymentLabel(item)
}
And confirm that, in fact, it's iterating what I expect it's iterating over:
type of item is com.starbase.starteam.File
I've seen a few different similar issues in other posts relating to static methods and the responses are along the lines of "are you sure it's a static method?". I'm sure it's a static method.
There isn't much groovy code to this. What there is of it is all contained in a single script in the default package. The main method is then called implicitly and it's in the body of the script class that the call out to the java library is made. I set the classpath in a DOS batch wrapper script, e.g.:
SET INITIALCLASSPATH=%CLASSPATH%
SET NEWCP=c:/libs/etc.jar;c:/etc/etc.jar
SET GROOVYPATH=c:/groovy.bat
SET CLASSPATH=%NEWCP%
%GROOVYPATH% %*
SET CLASSPATH=%INITIALCLASSPATH%
I created a simple situation which I think emulates my situation.
C:\apps\groovy-1.8.6\scripts>type Other.java
class Other {
private String name = "notset";
public Other(String name) {
this.name = name;
System.out.println("Created an other");
}
public String toString() {
return name;
}
}
C:\apps\groovy-1.8.6\scripts>type ThingList.java
import java.util.ArrayList;
import java.util.Iterator;
class ThingList {
ArrayList ourlist = new ArrayList<Other>();
public ThingList(){}
public ArrayList add(Other thing) {
ourlist.add(thing);
return ourlist;
}
public Iterator iterator(){
return ourlist.iterator();
}
}
C:\apps\groovy-1.8.6\scripts>type JavaLib.java
class JavaLib {
public JavaLib() {}
public static ThingList getThingList(Other thing) {
ThingList tl = new ThingList();
Other one = new Other("extra one");
tl.add(thing);
tl.add(one);
return ThingList;
}
}
C:\apps\groovy-1.8.6\scripts>type testthing.groovy
def myOther = new Other("A new other")
println "type of myOther is ${myOther.class.getName()}"
def myList = getThingList(myOther)
myList.each() {
println it
}
C:\apps\groovy-1.8.6\scripts>type wrapper.bat
#ECHO OFF
SET INITIALCLASSPATH=%CLASSPATH%
SET GROOVY=C:\apps\groovy-1.8.6\bin\groovy.bat
SET CP=.
SET CLASSPATH=%CP%
%GROOVY% %*
SET CLASSPATH=%INITIALCLASSPATH%
C:\apps\groovy-1.8.6\scripts>wrapper.bat testthing.groovy
Created an other
type of myOther is Other
Caught: groovy.lang.MissingMethodException: No signature of method: testthing.ge
tThingList() is applicable for argument types: (Other) values: [A new other]
groovy.lang.MissingMethodException: No signature of method: testthing.getThingLi
st() is applicable for argument types: (Other) values: [A new other]
at testthing.run(testthing.groovy:3)
C:\apps\groovy-1.8.6\scripts>
Any insights or suggestions would be greatly appreciated!
AndyJ
Without a way to reproduce, it's impossible to say for sure what the problem is. One possibility is that it is a class loading problem. Is the Groovy code contained in a regular Groovy class that's sitting on the class path, or does the Groovy code get loaded dynamically (e.g. by using GroovyShell)?

How to make a link betweeen the name a function and the actual function in java

I am building a user interface in netBeans (coding by hand, more flexible) with multiple toolbars.
What I am trying to do is create an actionListener for each button. I am retrieving names of the functions from XML and parse them to string. I will write implementations for those functions in a separate class, but my problem is the following:
How do I make the link between the function name and the string containing it's name?
Example: String is Open(), function will be Open(someParameter) and in the definitions class there will be static void Open(param).
First of all, consider my comment about your idea of dynamic button behavior resolved from strings being a wrong approach. However if you still need exactly what you asked, what you need is Reflection API.
Here's an example:
Class c = SomeClassWithMethods.class;
Method m = c.getMethod("someMethodName", String.class, Integer.class, Integer.TYPE);
m.invoke(baseObjectFromWhichToCallTheMethod, "stringParam", 10, 5);
Added:
Another option, which is a little bit prettier than reflection, but still a messy design, would be to use a map to link those Strings to methods. The code is a bit longer, but from the Java perspective it is much better than using reflection for your task (unless you have some specific requirement of which I'm not aware). This is how it would work:
//Interface whose instances will bind strings to methods
interface ButtonClickHandler {
void onClick();
}
class SomeClassYouNeed {
//One of the methods that will be bound to "onButtonOneClick()"
public void onButtonOneClick() {
log.info("ButtonOneClick method is called");
}
public void onButtonTwoClick() {
log.info("ButtonTwoClick method is called");
}
//Map that will hold your links
private static Map<String, ButtonClickHandler> buttonActionMap;
//Static constructor to initialize the map
static {
buttonActionMap = new Map<String, ButtonClickHandler>();
buttonActionMap.put("onButtonOneClick()",new ButtonClickHandler() {
#Override
public void onClick() {
onButtonOneClick();
}
});
buttonActionMap.put("onButtonTwoClick()",new ButtonClickHandler() {
#Override
public void onClick() {
onButtonTwoClick();
}
});
}
public void callByName(String methodName) {
final ButtonClickHandler handler = buttonActionMap.get(methodName);
if (handler == null) {
throw new IllegalArgumentException("No handler found by name: "+methodName);
}
handler.onClick();
}
}
After you call callByName("onButtonTwoClick()") it will fetch the respective instance of ButtonClickHandler which will use the static method onButtonTwoClick() to process the click of the button.
It seems to me that you are looking for the equivalent of JS "eval" function in Java. This might help. Nevertheless it is generally not a good idea as #Max stated, you might want to rethink your design.
If i have understood your question correctly you are trying to generate your code files based on some strings taken from a XML file. I can suggest you this library to generate your codes.
For tutorials you can visit this link.
You may even use the Java Reflection API. Here is a link for the tutorial.
Its upto you, that which of the above two you use.

Java translator for println usages to convenient logger

I often see (and reuse) 3rd party source code that doesn't have appropriate output. Is there any tool (code translator) that convert println output to suitable log framework code
private void processCreateTraining() {
System.out.println("Training set created");
//..
}
to something like
private void processCreateTraining() {
LOG.info("Training set created");
//..
}
It could be done by search-and-replace or Structural Replace in IDEA. But is there more sophisticated/robust solution that provide more flexibility: different logging framework support, ask severity on occurrence replace, string concatenation via StringBuilder.
If I come across third party libraries that use println all over the place, I tend NOT to use it. It is a sign of poor workmanship, and that implies (to me) that there are likely to be other more insidious problems with the code.
But no, I'm not aware of any plugin or tool to deal specifically with this case.
Sure, try something like this:
public static void main(String[] args) {
WrappedOutputStream los = new WrappedOutputStream();
System.setOut(new PrintStream(los, true));
System.out.println("catch me");
}
WrappedOutputStream.java
class WrappedOutputStream extends ByteArrayOutputStream {
public void flush() throws IOException {
String str = "WRAPPED: " + this.toString();
// process
}
}

Categories