0

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.

user1870400
  • 6,028
  • 13
  • 54
  • 115
  • If the class does already exist, just load it? If it is not on the classpath then a new classloader might help. Or do you really need the bytes of that class (or the byte code), then explain for what. – CoronA Oct 18 '18 at 06:12
  • I really need bytes of that class. similar to this https://www.programiz.com/python-programming/methods/built-in/compile – user1870400 Oct 18 '18 at 06:14
  • This is contradictory. In the comment you present a function that transforms bytes to a class object, not a class to a byte object. maybe it would help if you explain for what you need this. – CoronA Oct 18 '18 at 06:19
  • Where? I always wanted an existing class to byte object at runtime. – user1870400 Oct 18 '18 at 06:21
  • yes I meant I need bytecode of my `Foo.java` class above at runtime – user1870400 Oct 18 '18 at 06:26
  • The `compile` function from python does exactly the other way yet. It transforms bytes to a class object. – CoronA Oct 18 '18 at 06:29
  • You may refer to https://dzone.com/articles/how-to-compile-a-class-at-runtime-with-java-8-and – Miller Cy Chan Oct 18 '18 at 06:33
  • @CoronA That's an incorrect statement. compile function in python takes the source code and compile to bytecode at runtime. I had done it so many times. – user1870400 Oct 18 '18 at 06:37
  • Better refer to https://stackoverflow.com/questions/21544446/how-do-you-dynamically-compile-and-load-external-java-classes – Miller Cy Chan Oct 18 '18 at 06:42
  • @MillerCyChan You got it! I am exactly looking for this. I wonder why this isn't part of standard Java package but anyways can you please tell me if this line `JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();` will invoke some external binary outside of JVM? or it is just a library function that takes a source and returns a bytecode? – user1870400 Oct 18 '18 at 06:48
  • JDK is required, so it will invoke javac outside of JVM according to https://stackoverflow.com/questions/46096598/toolprovider-getsystemjavacompiler-always-returning-null-using-jdk – Miller Cy Chan Oct 18 '18 at 06:55
  • @MillerCyChan Thanks a lot. Is there any way to do this without invoking an external binary like javac? I just need the bytecode IR representation right which is machine independent so does it really need to invoke javac? – user1870400 Oct 18 '18 at 06:59
  • At least the jre is required, please look up the words "First I used the jre again" from https://stackoverflow.com/questions/46096598/toolprovider-getsystemjavacompiler-always-returning-null-using-jdk – Miller Cy Chan Oct 18 '18 at 07:06

2 Answers2

0

[Edited following the clarification in the comments]

The following article describes how to compile a class from source code at runtime, using ToolProvider.getSystemJavaCompiler().

Yoav Gur
  • 1,366
  • 9
  • 15
  • `Loads a given file (presumably .class) into a byte array` This assume I already have a .class file but that is not the case I have a Foo.java so I need to be able to compile at runtime and get the bytecode at runtime. In python this is very easy. – user1870400 Oct 18 '18 at 06:12
  • See getClass(String name) in the same article, for getting the file name from the full class name – Yoav Gur Oct 18 '18 at 06:14
  • i need something like this https://www.programiz.com/python-programming/methods/built-in/compile – user1870400 Oct 18 '18 at 06:16
  • I edited the answer to answer the missing bits arising from your questions. – Yoav Gur Oct 18 '18 at 06:21
  • Hi, I am not sure if you follow my question. I want to go from existing Foo.java class to byte code at runtime Not bytecode to Class. – user1870400 Oct 18 '18 at 06:22
  • What do you mean by "at runtime"? If you are running a compiled java program, you have the .class already, otherwise, how is it 'runtime'? The code above shows you how to get the bytecode (as a byte array that can be turned into string) from a class at runtime. – Yoav Gur Oct 18 '18 at 06:24
  • I want the compilation to happen at runtime and get the bytecode as a result so I can print the bytecode on screen lets say. – user1870400 Oct 18 '18 at 06:28
  • I see. Take a look at this then: https://dzone.com/articles/how-to-compile-a-class-at-runtime-with-java-8-and – Yoav Gur Oct 18 '18 at 06:39
  • You got it! I am exactly looking for this. I wonder why this isn't part of standard Java package but anyways can you please tell me if this line JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); will invoke some external binary outside of JVM? or it is just a library function that takes a source and returns a bytecode? – user1870400 Oct 18 '18 at 06:49
  • ToolProvider is part of rt.jar, which is part of the JVM, but the compiler itself is provided by the platform. See: https://docs.oracle.com/javase/8/docs/api/javax/tools/ToolProvider.html#getSystemJavaCompiler-- – Yoav Gur Oct 18 '18 at 06:51
  • Reading from the comments above. Is there any way to do this without invoking an external binary like javac? I just need the bytecode IR representation right which is machine independent so does it really need to invoke external binary like javac? – user1870400 Oct 18 '18 at 07:01
  • The bytecode is machine independent, but you still need a some kind of compiler to get it from a source code, don't you? – Yoav Gur Oct 18 '18 at 07:03
  • yes but the question really is does the compiler have to be an external binary in this case? can it just be a library function? – user1870400 Oct 18 '18 at 07:05
  • From the decompiled code (see next comment), it does seem like a library, but I won't be surprised if this implementation is only available with a JDK, and not with a JRE. – Yoav Gur Oct 18 '18 at 07:09
  • public static JavaCompiler getSystemJavaCompiler() { return (JavaCompiler)instance().getSystemTool(JavaCompiler.class, "com.sun.tools.javac.api.JavacTool"); } – Yoav Gur Oct 18 '18 at 07:10
  • Can you please update your answer then? using JavaCompiler getSystemJavaCompiler() and getting the bytecode of class like Foo.java above – user1870400 Oct 18 '18 at 08:07
0

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.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192