How to generate bytecode of existing class at Runtime in Java?
My Existing class is say Foo.java
public class Foo {
public String saySomething() {
return "Hello World";
}
}
Now I want to generate byte code of this existing class Foo.java and probably use it in another instance of JVM. Please understand I am not creating a class at runtime since I already have an existing class called Foo.java. Open to any libraries such as ASM or ByteBuddy etc.
[Edited following the clarification in the comments]
The following article describes how to compile a class from source code at runtime, using ToolProvider.getSystemJavaCompiler().
You do not need a library for that, any class file is just a resource just like any other file which can be located by Foo.class.getResource("Foo.class"). You can open a stream of this resource and read its byte just as of any other resource.
If you are already using Byte Buddy, you can get hold of the bytes by: ClassFileLocator.ForClassLoader.read(Foo.class) but if that is all you need, using a library would be an overkill.
Related
First of all some context, to thoroughly explain the methods I've already tried:
I'm working in a java-based programming platform on windows which provides access to custom java functions with several other extensions. Within the source code of this modelling platform, there is a class "CVODE" which grants access to native library "cvode" to import the functionality of a C++ library CVODE.
//imports
public class CVODE {
static {
Native.register("cvode");
}
public static native int ... //methods
}
I created shared libraries from the CVODE library, which resulted in 2 files: sundials_cvode.dll and sundials_nvecserial.dll.
Adding the first library to my java path obviously resulted in
Unexpected Exception UnsatisfiedLinkError: Unable to load library 'cvode': The specified module could not be found.
as the names were not compatible. Therefore I changed the name of sundials_cvode.dll to cvode.dll and retried. Resulting in an error indicating that not all methods are present in the library sundials_cvode.dll:
Unexpected Exception UnsatisfiedLinkError: Error looking up function 'N_VDestroy_Serial': The specified procedure could not be found.
This convinces me that the library is being found and loaded correctly, but not all methods are available. Examining the dll's in question led me to the conclusion that the CVODE class requires functions from both the sundials_cvode.dll and sundials_nvecserial.dll libraries. Therefore I tried changing the platform source-code to
public class CVODE {
static {
Native.register("sundials_cvode");
Native.register("sundials_nvecserial");
}
public static native int ... //methods
}
which still results in
Unexpected Exception UnsatisfiedLinkError: Error looking up function 'N_VNew_Serial': The specified procedure could not be found.
I have confirmed this method is present in both the class file and in the dll:
So I can only guess the error results from calling the Native.register() twice. resulting in the 2nd library not being loaded or an error down the way. I'd appreciate some insight in what I'm doing wrong or how I can gain a better overview of what's going wrong.
As far as I know, you can only load one dll per class, i.e. split the classes into two, each providing the methods the particular dll provides.
See also here: https://stackoverflow.com/a/32630857/1274747
I'm developing an android test app and i'm going to access all internal class of android.view package. android.view is a package that is present in jar file. I tried by loading package name but it doesn't display the classes if any one tried
this already, please help.
Here's what I tried so far:
public static void main() throws ClassNotFoundException{
Class o =Class.forName("android.view");
Class[] C=o.getDeclaredClasses();
for(int i=0;i<C.length;i++) {
Classname = C[i].getName();
ClassesDisplayActivity.your_array_list3.add(Classname);
Log.i("Ramu","classname "+ C[i].getName());
}
}
}
It is not possible to determine at runtime all of the classes that are in a package using a standard class loader.
You might have some luck with this library though:
https://code.google.com/p/reflections/
Package is not a class. You cannot call Class.forName() for package and access classes that belong to class using getDelcaredClasses().
I do not know what do you really need, so I'd recommend you to explain this in separate question. probably you will receive better solutions.
However if you really need this you have to do the following:
Get your classpath by calling System.getProperty(java.class.path)
split this property to its elements by colon
iterate over the list and read each resource. If resource is jar you can use ZipInputStream, if it is a directory use File class.
filter list of resources you got at #3.
Fortunately you can use 3rd party library named Reflections that helps you to do all this without writing code.
I have in an input stream the complete source code of a class. Is it possible to use Javassist to create a new CtClass object for this class ?.
I know that with the name of the class is possible to create a new CtClass object with something like:
ClassPool.getDefault().makeClass("name_of_the_new_class");
But in my case I do not know the name of the class in advance, but just its complete source code (of course I could get the name of the class parsing the source code, but please do not tell me that this is part of the solution :-) )
If you want to compile a source file on-the-fly, have a look at the tools API as well as ToolProvider.getSystemJavaCompiler(). From there you can compile .class files from source and load them using a classloader if you need to.
You could also then use Javassist to create a CtClass from the bytes of the created class file using ByteArrayClassPath with a new ClassPool.
I've got a problem for you.
I've got a bunch of Java files (.java) sitting around and they all contain a class declaration and an array of strings. I need to do stuff with the array. What is the best way to access it?
I tried using JavaCompiler class, but that didn't seem to work - so should I use regex or something?
Here's a sample of what the files look like:
package com.mypack.costmgr;
public class Cost_en extends java.util.ListResourceBundle {
static final Object[][] contents = new String[][] {
{"ACTIVE", "ACTIVE"},
{"Joe", "asfag"},
{"lolcats", "cheezburger"},
{"HELP", "OH GOD NOT THE BEES"},
{"asdfffff", "hacks"}
};
public Object[][] getContents() {
return contents;
}
}
And there's probably a hundred of these files.
So, to summarize: what is the best way to gain access to that data?
(Obviously, I cannot simply compile them with my project.)
You have to compile the .java files and make them .class files. Then you put those .class files on your classpath. At this point you can now make a reference to the contents of each of those files. Since contents is static you can get a reference to it by doing the following:
class MyAwesomeClass
{
Object[][] myArray = Cost_en.contents;
}
Resource bundles
Spring Roo has an interesting Java language parser and manipulation framework for their plugins. It's used to extract info from user created .java files as part of the code supporting AspectJ. Maybe you can create a Roo plugin to handle what you're trying to do?
class HelloObject {
void speak() {
System.out.println("Hello (from object)!");
}
}
class HelloTester {
public static void main(String[] args) {
HelloObject object = new HelloObject();
object.speak();
}
}
When I change the "HelloTester" class name to something like "HelloTester2", the program suddenly works. The class file is called ClassesBegin.java.
Why does the java program not work when I try to change the name of the class?
EDIT: Sorry I should have clarified more. I changed the class name to HelloTestera and this is the error I get:
Exception in thread "main" java.lang.NoClassDefFoundError: HelloTester
But it works even when the file name has nothing to do with a class name. It works with HelloTester when the file name is ClassesBegin.java
You need to change the file name, not just the class name.
In Java, the .java and .class names have to be identical to the class name.
Hence, each class has to go to a separate file with its name so that a separate .class file is created.
Putting two different classes in the same file is a C++ practice that works with its compilation model, not with Java.
Edit: User ended up clarifying what caused his error, so obviously my answer here is not relevant. All the above applies to public classes. You can pull that off for package-level classes though I have to say that I consider that a horrible practice. If you're going to have something used by multiple classes in your package, give it its own file. If it's used just by one class, make it an inner class...
"EDIT: Sorry I should have clarified more. I changed the class name to HelloTestera and this is the error I get: Exception in thread "main" java.lang.NoClassDefFoundError: HelloTester But it works even when the file name has nothing to do with a class name. It works with HelloTester when the file name is ClassesBegin.java"
The file name and the class name must match if the class is public.
If you chagned the class name to "HelloTestera" but ran "java HelloTester" (which is what java.lang.NoClassDefFoundError: HelloTester would indicate) then the issue is that you passed the wrong class name to "java".
But save yourself a lot of time and name the class and the file the same thing and keep it at one top level class per file. A simple way to "force" that is to make all of your classes public for now (you can only have one public class per file). This will really save you from making some mistakes.
You are allowed to have as many non-public classes in your ClassesBegin file as you like in terms of compilation. But only the public (ClassesBegin in this case; until you change the name of the file) is able to be used externally.
In particular, the main() method must be public, and in a public class to be able to be found by java. Rename your file to HelloTester to make it work.
Or - rename the HelloTester class in your IDE, which probably is relaming the file automatically, since it has a main method, and the IDE knows that it needs to be the public class...
The easiest way to do this is:
1) only one top level class per file
2) the name of the class and the name of the file must match (name and CasE)
This makes it easier to find you classes (the name of the class is the name of the file) and you don't wind up with some odd issues where the compielr cannot find all of the classes to copmpile.
Java also has a restriction where the name of a public class 100% must be the same as the name of the file. The restriction is only on public classes (or interfaces or enums). You can have as many non-public types as you want in a file... but don't do that - stick with one top level class/interface/enum per file.
You write:
I changed the class name to HelloTestera and this is the error I get: Exception in thread "main" java.lang.NoClassDefFoundError: HelloTester
It seems you are not actually running the renamed class but the old one. Did you call Java with the new changed class name? Did you recompile the file before running the class?
After renaming the class, you should first run:
javac ClassesBegin.java
And then:
java HelloTestera
Which for me yields:
Hello (from object)!
Usually, when using an IDE, these issues are handled for you (compile before running).