Creating new classes from code - java

Is there a way to create a new java class during execution? All the information about the class (name, modifiers, methods, fields, etc.) exists. Now I want to create that class. An idea was to create a new file and write the stuff to that file, c'est fini! But I think there are more elegant ways to do that, maybe with JDT?

Either use BCEL to create byte code and class files (the hard way) or create the source code in memory and use the Java 6 Compiler API (that's what I would do). But with Compiler API you need a Java SDK while running the application, a JRE is not sufficient.
Further Reading
The Java 6.0 Compiler API
(There a lot of tutorials on the web)

If you are writing an eclipse plugin and you want your tooling to generate code into a project, you can interact with JDT using the AST. There is also a method to call the Eclipse batch compiler from your runtime.
AST ast = AST.newAST(AST.JLS3);
CompilationUnit unit = ast.newCompilationUnit();
PackageDeclaration packageDeclaration = ast.newPackageDeclaration();
packageDeclaration.setName(ast.newSimpleName("example"));
unit.setPackage(packageDeclaration);
ImportDeclaration importDeclaration = ast.newImportDeclaration();
QualifiedName name =
ast.newQualifiedName(
ast.newSimpleName("java"),
ast.newSimpleName("util"));
importDeclaration.setName(name);
importDeclaration.setOnDemand(true);
unit.imports().add(importDeclaration);
TypeDeclaration type = ast.newTypeDeclaration();
type.setInterface(false);
type.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
type.setName(ast.newSimpleName("HelloWorld"));
// ....
Long winded :-) but you have access to the JDT java core model as you go.
If you need to generate files into your eclipse workspace, there are also template based options, like JET.
But if you want to dynamically generate and load a .class file in the runtime of a java application try #Andreas_D suggestions.

Look at code generation libraries,
http://cglib.sourceforge.net/
http://www.csg.is.titech.ac.jp/~chiba/javassist/

Related

Unable to use AbstractProcessor in IDEs

Motivation:
In our code we have a few places where some methods are run by their name. There are some big if-else-if blocks with each function name and call of the corresponding method (I use the term function to describe just names, for example function X01 might correspond to method SomeClass.functionX01). I've been looking into ways to improve that
Goal:
Write just methods that are annotated with some custom annotation, removing the need to update or even include if-else-if blocks in order to run specific function. Have access to any generated code if any code is generated.
What I did:
I've created first prove of concept using runtime annotations and it proved successful, but slower then if-else-if. Next attempt was with source annotation
I've followed this link for an example, however it did not seam to run in IntelliJ. What I wanted is to have - in this case PersonBuilder class generated, instead there was none. In some cases an error was raised Error:java: Bad service configuration file, or exception thrown while constructing Processor object: javax.annotation.processing.Processor: Provider BuilderProcessor not found
After some Googling and failing to find anything I've turned to book (Core Java, Volume II - Advanced Features - 9th Edition, Polish translation) and there was reccomended to run the following commands:
javac [AbstractProcessor implementation]
javac -processor [Compiled Processor] [other source files to compile]
This worked, however is unsatisfactory as it needs to happen inside IDE (NetBeans and IntelliJ to be specific) automatically during build. Code does not need to be generated on the fly, but programmer must have access to it after build (as in - be able to call methods of generated classes)
Question:
How to have and use generated code used in NetBeans and IntelliJ without the need of using external tools? Is it possible, or using reflection, runtime annotations or external tools is the only way?
Additional info (just in case):
Language level: Java 1.8
JVM versions: 12 and 13
IDEs: NetBeans and IntelliJ

Compiling java class from non-java file

I have a set of ruby files where I have some string of type:
#something = [Whatever.new('1rabbit'),
Whatever.new('2rabbit'),
Whatever.new('3rabbit')]
I would like to parse out this information from the ruby file during compilation phase (javac run with maven - but i think it is no difference how javac is run), and create a .class enum of type:
public enum Something {
1RABBIT,
2RABBIT,
3RABBIT
}
and store it into the target folder. Then, I can use this enum whatever I want (after this initial compilation). I looked into AnnotationProcessors, and bytecode generation, but the first requires annotations, and the second is done during runtime. And I cannot find out how to do it properly.
What is the correct tool to do this, and how?
mavens life cycle has a generate sources phase. There you cold use the exec-maven-plugin to run a script generating the enums.

java class method stubs with /* compiled code */

I just received a third party authentication library to use in my clients application. I didn't receive any documentation with it and am trying to dig through the source and see how it works. I'm very to new Java when i click Go To -> Declaration on methods in IntelliJ it sends me to a .class file and i see a bunch of stubbed methods with /* compiled code */ in the methods.
I'm fairly sure this is common in Java i just don't know what to search for to learn about what exactly is going on. Any clarification would be great.
This typically meant that you don't have the source code, and IntelliJ IDEA would just display /* compiled code */ as a placeholder for the source code you don't have. I believe this has now changed, and IntelliJ comes bundled with a full Java decompiler plugin, and will display the decompiled source code as standard.
To better see what's going on, the best would be to receive the actual source code of the third party library.
You should of course also get the documentation, as reading the source code and guessing how to use a library usually isn't the best way to learn.
The second best option would be use the decompiler plugin in IntelliJ, that will automatically decompile the Java class file (note that the license for your third party library may disallow you to do just that). This will never be a 100% solution, but in most cases it's better than nothing.
You should really search/ask for documentation. Javadoc usually is invaluable if the method does stuff you can't guess from its name. Otherwise use a decompiler such as JD-GUI.
.java sourcecode is compiled to .class bytecode by compilers such as javac. The compiler may optimise specific things, and a compilation-decompilation process if highly unlikely to yield the same source. Also, all comments should be deleted and if the code wasn't compiled in debug mode, even the variable names are lost. So: Decompilation is not a good alternative to handcrafted documentation.
If your library is build with sourceFiles:
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.sourceFiles//look at this line
}
Then you will see classes with /* compiled code */
If your library is build with srcDirs:
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from from android.sourceSets.main.java.srcDirs//look at this line
}
Then you will see classes with full source without /* compiled code */

Conditional Java compilation

I'm a longtime C++ programmer, new to Java. I'm developing a Java Blackberry project in Eclipse. Question - is there a way to introduce different configuration sets within the project and then compile slightly different code based on those?
In Visual Studio, we have project configurations and #ifdef; I know there's no #ifdef in Java, but maybe something on file level?
You can set up 'final' fields and ifs to get the compiler to optimize the compiled byte-codes.
...
public static final boolean myFinalVar=false;
...
if (myFinalVar) {
do something ....
....
}
If 'myFinalVar' is false when the code is compiled the 'do something....' bit will be missed out of the compiled class. If you have more than one condition - this can be tidied up a bit: shift them all to another class (say 'Config.myFinalVar') and then the conditions can all be kept in one neat place.
This mechanism is described in 'Hardcore Java'.
[Actually I think this is the same mechanism as the "poor man's ifdef" posted earlier.]
you can manage different classpath, for example, implement each 'Action' in a set of distinct directories:
dir1/Main.java
dir2/Action.java
dir3/Action.java
then use a different classpath for each version
javac -sourcepath dir1 -cp dir2 dir1/Main.java
or
javac -sourcepath dir1 -cp dir3 dir1/Main.java
In JDK6, you can do it by using Java's ServiceLoader interface.
Check it here.
If you want this specifically for BlackBerry, the BlackBerry JDE has a pre-processor:
You
can enable preprocessing for your
applications by updating the Eclipseâ„¢
configuration file.
In C:\Program Files\Eclipse\configuration\config.ini,
add the following line:
osgi.framework.extensions=net.rim.eide.preprocessing.hook
If you enable preprocessing after you
have had a build, you must clean the
project from the Project menu before
you build the project again.
Then you can do things in the code like:
//#ifdef SOMETHING
// do something here
//#else
// do something else
//#endif
For details see Specifying preprocessor defines
Can one call that a poor mans ifdef: http://www.javapractices.com/topic/TopicAction.do?Id=64?
No, Java doesn't have an exact match for that functionality. You could use aspects, or use an IOC container to inject different implementation classes.
You can integrate m4 into your build process to effectively strap an analogue to the C preprocessor in front of the Java compiler. Much hand-waving lies in the "integrate" step, but m4 is the right technology for the text processing job.
Besides Maven, Ant and other build tools that provide similar functionality, one would rather build interfaces in Java and switch the implementations at Runtime.
See the Strategy Pattern for more details
In opposite to C/C++ this will not come with a big performance penality, as Javas JIT-compiler optimizes at runtime and is able to inline this patterns in most cases.
The big pro of this pattern is the flexibility - you can change the underlying Implementation without touching the core classes.
You should also check IoC and the Observer Pattern for more details.
You could use maven's resource filtering in combination mit public static final fields, which will be indeed get compiled conditionally.
private static final int MODE = ${mode};
...
if (MODE == ANDROID) {
//android specific code here
} else {
}
Now you need to add a property to your maven pom called "mode", which should be
of the same value as your ANDROID constant.
The java compiler should (!) remove the if and the else block, thus leaving your android code.
Not testet, so there is no guarantee and i would prefer configuration instead of conditional compilation.
There are a couple of projects that bring support for comment-based conditional compilation to Java:
java-comment-preprocessor
JPSG
Example in JPSG:
/* with Android|Iphone platform */
class AndroidFoo {
void bar() {
/* if Android platform */
doSomething();
/* elif Iphone platform */
doSomethingElse();
/* endif */
}
}
In eclipse you could use multiple projects
Main (contains common code)
Version1 (contains version1 code)
Version2 (contains version2 code)
Main -> Select Project->Properties->Java Build Path->Projects tab
Select Add...
Add "Version1" xor "Version2" and OK back to the workspace.
Version1 and Version two contain the same files but different implementations. In Main you normally write e.g.
import org.mycustom.Version;
And if you included Version1/Version2 project as reference it will compile with the Version.java file from Version1/Version2 project.

Options for dynamic compilation in Java 5

Are there any options other than Janino for on-the-fly compiliation and execution of Java code in v5? I know v6 has the Compiler API, but I need to work with the v5 VM.
I essentially need to take a string containing a complete Java class, compile it and load it into memory.
What you want is something like Janino. We've used it for years. You give it (near standard) code and it gives you the classes so you can use them. It actually has quite a few different modes and supports the 1.5 syntactic sugar and auto-boxing and such.
If you call javac, not only will you have to be ready for anything it does, you'll then have to handle putting the class in the right place or making an additional classloader.
Janino is very easy. It should be exactly what you are looking for.
Invoking javac programatically:
http://www.juixe.com/techknow/index.php/2006/12/12/invoke-javac-at-runtime/
com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main();
String[] options = new String[]
{
"-classpath", classpath, "-d", outputDir, filename
};
javac.compile(options);
All app servers do this for JSP for ever, so obviously it is possible. Checkout tomcat source code maybe?

Categories

Resources