I am investigating methods of dynamically modifying the behaviour of a Java application (specifically, I'm trying to make a Minecraft mod that allows users to modify the behaviour of the objects they find by writing code without the need to restart the game) and I stumbled upon Groovy. My question is: is it possible to integrate Java and Groovy in such way they "share" objects? (I'm thinking about having a specific set of classes that are actually Groovy code so you can change the code during runtime, similarly to what you can do in any Smalltalk implementation)
Take a look at Integrating Groovy in a Java Application. It shows examples of how you can run a Groovy script from inside a Java application and share data between them using groovy.lang.Binding.
What a cool idea!
1. Groovy: Java and Groovy can share objects and call back and forth. Groovy classes that implement Java interfaces are easily called from Java. (There are other ways, like calling groovyObject.invokeMethod("methodName", args) from Java.) Of JVM languages, Groovy has the tightest integration with Java. It's also easy for Java programmers to learn since it shares so much with Java.
The book Groovy in Action has a chapter on "Integrating Groovy" that explains and compares the approaches (in more detail than the reference docs do): GroovyShell, GroovyScriptEngine, GroovyClassLoader, Spring integration, and JSR-223 ScriptEngineManager. GroovyClassLoader is the most capable choice.
However, while it's easy to compile and load Groovy code at runtime, I'm puzzled about how to change behavior of existing object instances (short of the notes below on hot swapping). (It might depend on whether the class overrides a Java interface or subclasses a Java class.) Consider:
class G implements Runnable {
void run() { println 'Groovy' }
}
g = new G()
g.run()
This prints Groovy. Now redefine the class:
class G implements Runnable {
void run() { println 'Groovy!' }
}
g1 = new G()
g.run()
g1.run()
This prints
Groovy
Groovy!
Now use the meta-class to change methods at runtime:
G.metaClass.run = { println 'Groovy!!!' }
g2 = new G()
g.run()
g1.run()
g2.run()
This prints
Groovy
Groovy!
Groovy!
If we omitted implements Runnable from those class definitions, then the last step would instead print
Groovy
Groovy!
Groovy!!!
But with our class that does implement Runnable, now do:
G.metaClass.run = { println 'Very Groovy!!!' }
g3 = new G()
g.run()
g1.run()
g2.run()
g3.run()
this prints:
Groovy
Groovy!
Very Groovy!!!
Very Groovy!!!
A workaround would implement the methods in closures held in class variables.
2. Hot Swapping: If the main point is to redefine method bodies at run time for classes with existing instances, then you can simply run within an IDE's debugger and use hot swapping.
E.g. for IntelliJ, here are the instructions to configure hot swapping of Java and Groovy code.
3. Expanded Hot Swapping: If you also want to be able to add/remove methods and instance variables at run time, then see this JetBrains article on extended hot swapping via DCEVM (Dynamic Code Evolution VM).
See Hot Swap code code at https://github.com/HotswapProjects
Also see this SO Q&A on hot swapping techniques.
I'm not sure that's something you can accomplish with Groovy without compiling it. You could do it, but the "scripting" aspect of Groovy won't help you. I'd look into having the player write javascript and using Java's ScriptEngine. See here: http://docs.oracle.com/javase/7/docs/technotes/guides/scripting/programmer_guide/
Yes, You can achieve that. For example, You have something written in java that uses some objects from let's say spring context. So now what u can do is :
execute groovy script before that java code is executed,
use delegate design pattern to wrap it, overwrite some methods
finaly put it back into context.
So basicly in moment where Your java code is executed, he'll get a wrapped object with some changes made in runtime.
If that's what are You trying to do, let me know i could write You some example code.
Related
I have a Java project(running in Eclipse) without main method and need to debug and see which is the caller class and the flow of the program. How do I start?
It is a simple project and does not contain any web/tomcat related data.
Thank you for your responses. I am new to StackOverflow and so pardon my writing and asking questions.
I am including packages and trying to create objects of a class, but it is not recognizing the classes. All the classes are public.
There is no way to run a Java SE application without starting with public static void main. If you want to debug the code of a library or framework you need to create a main method and call the code from there.
Take a look to JUnit. If you just want to debug your code is what you normally have to do.
Since Java requires all methods and variables to be within classes, the JVM needs a starting point that exists before any objects are initialized. Therefore, main must be static and public for the JVM to find it. Unlike C++, the main method does not return a status code, so it is of return type void rather than int.
So, given the following code:
public MyInterface getMyInterface() {
return new MyInterface() {
public SomethingElse getSomethingElse() {
// ....
}
}
}
...
MyInterface obj = getMyInterface();
Is there some way to instrument a call to getSomethingElse() on that obj? To go in and do some bytecode modification or something?
I have production code in there that in a different situation (call it "design time") I want to add some tracing/logging and such code for help in troubleshooting and analysis. Performance is critical for the production case so I want to leave it without the extra tracing/logging overhead. But in the design time situation, I want to have all the trace info.
Yes, it is possible to do what you're asking, although there are definitely better ways to accomplish it - the most obvious would be to create a default implementation of MyInterface, and then a "tracing" subclass of it that extends and logs before invoking the superclass version.
If instrumentation is your only option, then when running at design time, you can start your project with a java agent in Java 5 or add a java agent to the classpath at runtime in Java 6. See the instrumentation documentation.
To instrument the class, you will probably want to use a tool like ASM. The steps would be something like this:
In your Agent class, implement java.lang.instrument.ClassFileTransformer .
In your agentmain() or premain() method, request to transform classes.
When you receive a call to the transform method, you can check if the class implements MyInterface by using Class.getInterfaces().
Optionally, you can check to see if its Class.getEnclosingClass() is the class in which you wrote/found this code.
If the Class passes these sanity checks, then create a ClassWriter that adds logging to the getSomethingElse() method. The ASMifier helps a lot when trying to figure out how to generate the code you want.
Then, in production, none of that code will exist. In development, you would add your Java Agent in your environment, which would enable your debugging.
Again, there are almost certainly better ways to do this, but there are good reasons to use instrumentation, and this is a mini-crash course in doing it.
Hope that helps,
If you want to turn on logging on in development, the simplest thing to do is
if(LOGGER.isDebugEnabled())
LOGGER.debug("my debug message");
The over head added is sub-nanosecond so even if you are working on a system where every nano-seconds count, this is still the best pattern to use.
You can get the class with
Class.forName("package.OuterClass$NNN");
You need to call a constructor which takes an instance of the outer class.
This sounds like a good case for using aspects.
You can simply apply logging/tracing code around any methods you want in your testing environment and leave them out when you move to production.
I have some Java code written that I'd like to convert to JavaScript.
I wonder if it is possible to use the GWT compiler to compile the mentioned Java code into JavaScript code preserving all the names of the methods, variables and parameters.
I tried to compile it with code optimizations turned off using -draftCompile but the method names are mangled.
If GWT compiler can't do this, can some other tool?
Update
The Java code would have dependencies only to GWT emulated classes so the GWT compiler would definitely be able to process it.
Update 2
This Java method :
public String method()
got translated to this JavaScript funciton :
function com_client_T_$method__Lcom_client_T_2Ljava_lang_String_2()
using the compiler options :
-style DETAILED
-optimize 0
-draftCompile
So names can't be preserved. But is there a way to control how they are changed?
Clarification
Say, for example, you have a sort algorithm written in Java (or some other simple Maths utility). The method sort() takes an array of integers. and returns these integers in an array sorted. Say now, I have both Java and JavaScript applications. I want to write this method once, in Java, run it through the GWT compiler and either keep the method name the same, or have it change in a predictable way, so I can detect it and know how to change it back to sort(). I can then put that code in my JavaScript application and use it. I can also automatically re-generate it if the Java version changes. I have a very good reason technically for this, I understand the concepts of GWT at a high level, I'm just looking for an answer to this point only.
Conclusion
The answer to the main question is NO.
While method name can be somewhat preserved, its body is not usable. Method calls inside it are scattered throughout the generated file and as such, they can't be used in a JavaScript library which was the whole point of this topic.
Although you can set the compiler to output 'pretty' code, I suggest you write export functions for the classes you want to call from outside your GWT project. I believe somewhere in the GWT documentation it's detailed how to do this, but I couldn't find it so here an example I just created.
class YourClass {
public YourClass() {
...
}
public void yourMethod() {
...
}
public static YourClass create() {
return new YourClass();
}
public final static native void export() /*-{
$wnd.YourClass = function() {
this.instance = new #your.package.name.YourClass::create()()
}
var _ = $wnd.YourClass.prototype;
_.yourMethod = function() {this.instance.#your.package.name.YourClass::yourMethod()()}
}-*/;
}
EDIT
To elaborate, your code will get obfuscated like normal, but thanks to the export function, you can easily reference those functions externally. You don't have to rewrite anything from your Java class in JavaScript. You only write the references in JavaScript, so you can do this:
var myInstance = new YourClass();
myInstance.yourMethod();
Of course you have to call the static export method from somewhere in your GWT app (most likely in your EntryPoint) to make this work.
More info about referencing Java methods from JavaScript:
http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsJSNI.html#methods-fields
No - this isn't possible with the GWT compiler, since the GWT compiler is build to generate optimized and very performant JavaScript out of Java.
The big advantage is, that you can maintain your projekt in Java and compile it with GWT to JavaScript. So there is no need to prevent the variable-names and method-names in the JavaScript result, since all changes and work is done in the JAVA-sources.
Working in the JavaScript-output of GWT just isn't that easy and is really a lot of work!
Update:
By a hint of David, I found the Compiler-Option "-style". You can have a try with the following options:
-style=PRETTY -optimize=0
I have no idea if this will really generate "human readable" code. I think it won't, since the GWT framework will still be part of the resulting JavaScript and so it will be difficult to make changes to the JavaScript-result. Have a try and let us know ...
Maybe I can answer your second question: "If GWT compiler can't do this, can some other tool?"
I am using Java2Script for quite a while now, also on quite large projects. Integration with native JavaScript is fine, names are preserved, and after some time one can even match the generated JavaScript (in the browser debugger) with the original Java code with little effort.
Udo
You can "export" your function by writing inline JavaScript that calls it, and there is a tool gwt-exporter that does this automatically when you annotate classes and methods with #Export and similar. More information: https://code.google.com/p/gwtchismes/wiki/Tutorial_ExportingGwtLibrariesToJavascript_en
In java I can simply test classes directly with
public static void main()
I then just add quick code and under Eclipse "Run" the class. Is there anything similar in C++ .NET ?
Right now I have to create an empty project, reference the correct headers then set that project as start up project.
Unit tests. There's also the object test bench if you're using VS.
I do this in C# so I don't know if this will react any differently, but I set up an empty "test" class with the main method and then set the project to startup with that class file. You shouldn't have to create the file in a separate project.
I'm not terribly familiar with Eclipse but if you're just looking to run your objects in the IDE do the following.
Open up the Immediate window and just call whatever function you want. This will start execute the code you type. You will likely have to qualify the name. Ex: ClassLibrary1.MyClass.SomeMethod()
I like using TestDriven.NET for this. It allows you to execute any public method by rightclicking on the header and selecting "Run test".
I like making
public static void Test()
methods on dialog- and form-classes to use with this feature.
It supports C++/CLI, so if that is what you mean by C++.NET, it should work for you.
Edit: You should only do that for things that are not automatically testable - such as pure GUI classes. Otherwise I agree with the other commenters: use a unit test framework.
I maintain a Java Swing application.
For backwards compatibility with java 5 (for Apple machines), we maintain two codebases, 1 using features from Java 6, another without those features.
The code is largely the same, except for 3-4 classes that uses Java 6 features.
I wish to just maintain 1 codebase. Is there a way during compilation, to get the Java 5 compiler to 'ignore' some parts of my code?
I do not wish to simply comment/uncomment parts of my code, depending on the version of my java compiler.
The suggestions about using custom class loaders and dynamically commented code are a bit incredulous when it comes to maintenance and the preservation of the sanity of whichever poor soul picks up the project after you shuffle to pastures new.
The solution is easy. Pull the affected classes out into two separate, independent projects - make sure the package names are the same, and just compile into jars that you can then consume in your main project. If you keep the package names the same, and the method signatures the same, no problems - just drop whichever version of the jar you need into your deployment script. I would assume you run separate build scripts or have separate targets in the same script - ant and maven can both easily handle conditionally grabbing files and copying them.
Assuming that the classes have similar functionality with 1.5 vs. 6.0 differences in implementation you could merge them into one class. Then, without editing the source to comment/uncomment, you can rely on the optimization that the compiler always do. If an if expression is always false, the code in the if statement will not be included in the compilation.
You can make a static variable in one of your classes to determine which version you want to run:
public static final boolean COMPILED_IN_JAVA_6 = false;
And then have the affected classes check that static variable and put the different sections of code in a simple if statement
if (VersionUtil.COMPILED_IN_JAVA_6) {
// Java 6 stuff goes here
} else {
// Java 1.5 stuff goes here
}
Then when you want to compile the other version you just have to change that one variable and recompile. It might make the java file larger but it will consolidate your code and eliminate any code duplication that you have. Your editor may complain about unreachable code or whatever but the compiler should blissfully ignore it.
I think the best approach here is probably to use build scripts. You can have all your code in one location, and by choosing which files to include, and which not to include, you can choose what version of your code to compile. Note that this may not help if you need finer-grained control than per file.
You can probably refactor your code so that conditional compile really isn't needed, just conditional classloading. Something like this:
public interface Opener{
public void open(File f);
public static class Util{
public Opener getOpener(){
if(System.getProperty("java.version").beginsWith("1.5")){
return new Java5Opener();
}
try{
return new Java6Opener();
}catch(Throwable t){
return new Java5Opener();
}
}
}
}
This could be a lot of effort depending on how many version-specific pieces of code you have.
Keep one "master" source root that builds under JDK 5. Add a second parallel source root that has to build under JDK 6 or higher. (There should be no overlap, i.e. no classes present in both.) Use an interface to define the entry point between the two, and a tiny bit of reflection.
For example:
---%<--- main/RandomClass.java
// ...
if (...is JDK 6+...) {
try {
JDK6Interface i = (JDK6Interface)
Class.forName("JDK6Impl").newInstance();
i.browseDesktop(...);
} catch (Exception x) {
// fall back...
}
}
---%<--- main/JDK6Interface.java
public interface JDK6Interface {
void browseDesktop(URI uri);
}
---%<--- jdk6/JDK6Impl.java
public class JDK6Impl implements JDK6Interface {
public void browseDesktop(URI uri) {
java.awt.Desktop.getDesktop().browse(uri);
}
}
---%<---
You could configure these as separate projects in an IDE using different JDKs, etc. The point is that the main root can be compiled independently and it is very clear what you can use in which root, whereas if you try to compile different parts of a single root separately it is too easy to accidentally "leak" usage of JDK 6 into the wrong files.
Rather than using Class.forName like this, you can also use some kind of service registration system - java.util.ServiceLoader (if main could use JDK 6 and you wanted optional support for JDK 7!), NetBeans Lookup, Spring, etc. etc.
The same technique can be used to create support for an optional library rather than a newer JDK.
Not really, but there are workarounds. See
http://forums.sun.com/thread.jspa?threadID=154106&messageID=447625
That said, you should stick with at least having one file version for Java 5 and one for Java 6, and include them via a build or make as appropriate. Sticking it all in one big file and trying to get the compiler for 5 to ignore stuff it doesn't understand isn't a good solution.
HTH
-- nikki --
This will make all the Java purists cringe (which is fun, heh heh) but i would use the C preprocessor, put #ifdefs in my source. A makefile, rakefile, or whatever controls your build, would have to run cpp to make a temporary files to feed the compiler. I have no idea if ant could be made to do this.
While stackoverflow looks like it'll be the place for all answers, you could wehn no one's looking mosey on over to http://www.javaranch.com for Java wisdom. I imagine this question has been dealt with there, prolly a long time ago.
It depends on what Java 6 features you want to use. For a simple thing like adding row sorters to JTables, you can actually test at runtime:
private static final double javaVersion =
Double.parseDouble(System.getProperty("java.version").substring(0, 3));
private static final boolean supportsRowSorter =
(javaVersion >= 1.6);
//...
if (supportsRowSorter) {
myTable.setAutoCreateRowSorter(true);
} else {
// not supported
}
This code must be compiled with Java 6, but can be run with any version (no new classes are referenced).
EDIT: to be more correct, it will work with any version since 1.3 (according to this page).
You can do all of your compiling exclusively on Java6 and then use System.getProperty("java.version") to conditionally run either the Java5 or the Java6 code path.
You can have Java6-only code in a class and the class will run fine on Java5 as long as the Java6-only code path is not executed.
This is a trick that is used to write applets that will run on the ancient MSJVM all the way up to brand-new Java Plug-in JVMs.
There is no pre-compiler in Java. Thus, no way to do a #ifdef like in C.
Build scripts would be the best way.
You can get conditional compile, but not very nicely - javac will ignore unreachable code. Thus if you structured your code properly, you can get the compiler to ignore parts of your code. To use this properly, you would also need to pass the correct arguments to javac so it doesn't report unreachable code as errors, and refuse to compile :-)
The public static final solution mentioned above has one additional benefit the author didn't mention--as I understand it, the compiler will recognize it at compile time and compile out any code that is within an if statement that refers to that final variable.
So I think that's the exact solution you were looking for.
A simple solution could be:
Place the divergent classes outside of your normal classpath.
Write a simple custom classloader and install it in main as your default.
For all classes apart from the 5/6 ones the cassloader can defer to its parent (the normal system classloader)
For the 5/6 ones (which should be the only ones that cannot be found by the parent) it can decide which to use via the 'os.name' property or one of your own.
You can use reflection API. put all your 1.5 code in one class and 1.6 api in another. In your ant script create two targets one for 1.5 that won't compile the 1.6 class and one for 1.6 that won't compile the class for 1.5. in your code check your java version and load the appropriate class using reflection that way javac won't complain about missing functions. This is how i can compile my MRJ(Mac Runtime for Java) applications on windows.