Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[native-image] Any chance to support dynamic class loading if the JARs loaded by code is given at native-image compiling time? #461

Closed
cqjjjzr opened this issue Jun 11, 2018 · 18 comments

Comments

@cqjjjzr
Copy link

cqjjjzr commented Jun 11, 2018

From the "LIMITATIONS.md" I know the dynamic class loading is not supported.
But is there any way to support it if the JARs loaded is already known when compiling and can the native-image tool statically link it into the built program?
Also, can the tool just analyze the invocations to Class.forName and find out the class being loaded if it's invoked by a const string class name.(Like forcely loading JDBC database drivers)
The reason for supporting this is for plugin supports. Many JVM programs supports dynamic plugin loading or modding. If static linking can be supported it would be greatly helpful.
Thanks.

@cqjjjzr cqjjjzr changed the title [native-image] Any change to support dynamic class loading if the JARs loaded by code is given at native-image compiling time? [native-image] Any chance to support dynamic class loading if the JARs loaded by code is given at native-image compiling time? Jun 11, 2018
@cstancu
Copy link
Member

cstancu commented Jun 11, 2018

@cqjjjzr thank you for your comment. Yes, the features that you mentioned are not available yet, but we plan to implement them. They should be available soon.

@cstancu cstancu self-assigned this Jun 13, 2018
@cstancu
Copy link
Member

cstancu commented Jun 30, 2018

@cqjjjzr we added ClassLoader support. Please see #470 (comment) for details. (Please note that this does not include analyzing Class.forName() to automatically discover dynamically loaded classes, you still need to register the classes via the reflection configuration files.That feature is still under development as it is part of a bigger change set.)

@cstancu
Copy link
Member

cstancu commented Jul 26, 2018

@cqjjjzr 3c85875 improves native-image reflection support by automatically detecting reflective calls and intrinsifying them to the corresponding target elements statically. This includes analysis of Class.forName() as discussed above. Please read the updated REFLECTION.md for details.

@cstancu cstancu closed this as completed Jul 26, 2018
@behrangsa
Copy link

@cstancu does that mean GraalVM would eventually support scenarios like this:

Let's say I have a program that has a pluggable architecture. It has a Plugin interface that can be implemented by third parties:

package org.behrang.program;

public interface Plugin {

    String process(String input);

}

The entry point of the program looks for a CLI argument named --plugin, the fully qualified name of the implementation that the user wants to use:

package org.behrang.program;

public class Main {

    public static void main(String[] args) throws Exception {
        String pluginClassname = null;
        for (int i = 0; i < args.length; i++) {
            if ("--plugin".equals(args[i]) && args.length > i + 1) {
                pluginClassname = args[i + 1];
                break;
            }
        }

        if (pluginClassname == null) {
            System.err.println("--plugin is required");
            System.exit(1);
        }

        Class<?> pluginClass = Class.forName(pluginClassname);
        Plugin p = (Plugin) pluginClass.getDeclaredConstructor().newInstance();

        System.out.println(p.process("Hello, World!"));
    }

}

It then creates an instance of the plugin and invokes it:

Class<?> pluginClass = Class.forName(pluginClassname);
Plugin p = (Plugin) pluginClass.getDeclaredConstructor().newInstance();

System.out.println(p.process("Hello, World!"));

A third-party can implement a plugin by implementing this interface:

package org.behrang.plugin;

import org.behrang.program.Plugin;

public class SamplePlugin implements Plugin {
    @Override
    public String process(String s) {
        return "org.behrang.plugin.SamplePlugin: " + s;
    }
}

Finally, the user can put the JAR file for the plugin in the classpath and run the program:

$ java --class-path /path/to/program.jar:/path/to/plugin.jar \
                  org.behrang.program.Main \
                  --plugin org.behrang.plugin.SamplePlugin

org.behrang.plugin.SamplePlugin: Hello, World!

In real-world applications the plugin architecutre might use a class path and/or MANIFEST.MF scanner or another approach to load the plugin class.

There are many programs that work like this. For example in a static site generator a user can choose what library to use for processing markdown.

Will GraalVM support use cases like this? E.g.: a native image program that can load a custom library at execution time/runtime?

Or in this example, creating a native image of program.jar that can use a user's chosen plugin implementation in JAR (or binary/so) format?

@guizmaii
Copy link

Any answer to @behrangsa questions? We're many to like his comment. It seems there's a community interest in this possibility!

@Umartahir93
Copy link

I am also kind of interested in this feature. Right now, we are running jvm with in-built JIT which is kind of doing job for us on our machines. But due to some requirement, we need to provide our obfuscated jar to one of our clients who will run it on their machines.

I tried exploring different obfuscation types which would provide me ultimate security, one approach I came out was to provide "native exe" to client so that he can run it on their env and at the same time we save ourselves from reverse engineering techniques.

But right now, I think only graal provides facility to convert whole program to native-image. But here problem is that we cannot load a jar file dynamically. If something exists like that native-image can work with a dynamic jar that would resolve problem.

P/S client has some hashing logic in this jar which he wont provide so, I am kind of stuck here to come out with a little bit of better approach.

@ccwxl
Copy link

ccwxl commented Dec 8, 2021

I am also kind of interested in this feature. Right now, we are running jvm with in-built JIT which is kind of doing job for us on our machines. But due to some requirement, we need to provide our obfuscated jar to one of our clients who will run it on their machines.

I tried exploring different obfuscation types which would provide me ultimate security, one approach I came out was to provide "native exe" to client so that he can run it on their env and at the same time we save ourselves from reverse engineering techniques.

But right now, I think only graal provides facility to convert whole program to native-image. But here problem is that we cannot load a jar file dynamically. If something exists like that native-image can work with a dynamic jar that would resolve problem.

P/S client has some hashing logic in this jar which he wont provide so, I am kind of stuck here to come out with a little bit of better approach.

same scene

@ivanooi
Copy link

ivanooi commented Feb 22, 2022

that reminds me Excelsior Jet JVM which compile java into native code, at the same time they able to compile any downloaded jar into dll as well.

@DevSrSouza
Copy link

Any updates on this?

@ghost
Copy link

ghost commented Jul 19, 2022

Same need than behrangsa. We plan to fully migrate Reqchecker to the great Graal native feature, a basic plugin mechanism would be great.

@frank-dspeed
Copy link

frank-dspeed commented Sep 1, 2022

@khilogic @DevSrSouza @ivanooi @siaron @behrangsa

The answer is relativ simple as you produce Operating System dependend binarys you can use all IPC channels the Operating system provides depending on your performance usecase and data you can then choose what to use

a simple understand able example is named pipes

try {
  // Connect to the pipe
  RandomAccessFile pipe = new RandomAccessFile("\\\\.\\pipe\\testpipe", "rw");
  String echoText = "Hello word\n";
  // write to pipe
  pipe.write ( echoText.getBytes() );
  // read response
  String echoResponse = pipe.readLine();
  System.out.println("Response: " + echoResponse );
  pipe.close();
} catch (Exception e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

putting that with some kind of logic into your binarys and voila they can talk to each other and call each other

if you want something high performant

capnproto-java rocks more then the most people understand it is typed binary capability based Remote Function Invocation

same style used to drive Fuchsia OS Components by the way and it is a lot of faster then grpc or alternativ calling methods it is a module system for binary !!! Not only Java but in case of native image we can talk about binary :)

binary.exe <==> named pipe <==>  module.exe

@ivanooi
Copy link

ivanooi commented Sep 1, 2022

@khilogic @DevSrSouza @ivanooi @siaron @behrangsa

The answer is relativ simple as you produce Operating System dependend binarys you can use all IPC channels the Operating system provides depending on your performance usecase and data you can then choose what to use

a simple understand able example is named pipes

try {
  // Connect to the pipe
  RandomAccessFile pipe = new RandomAccessFile("\\\\.\\pipe\\testpipe", "rw");
  String echoText = "Hello word\n";
  // write to pipe
  pipe.write ( echoText.getBytes() );
  // read response
  String echoResponse = pipe.readLine();
  System.out.println("Response: " + echoResponse );
  pipe.close();
} catch (Exception e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

putting that with some kind of logic into your binarys and voila they can talk to each other and call each other

if you want something high performant

capnproto-java rocks more then the most people understand it is typed binary capability based Remote Function Invocation

same style used to drive Fuchsia OS Components by the way and it is a lot of faster then grpc or alternativ calling methods it is a module system for binary !!! Not only Java but in case of native image we can talk about binary :)

binary.exe <==> named pipe <==>  module.exe

this look like data sharing. how bout logic? means dynamically load a logic and execute it.

@ivanooi
Copy link

ivanooi commented Sep 1, 2022

In bytecode, I can dynamically load and execute a class from the jar file. I can change the logic any times. Client always download and execute the latest logic.

@ivanooi
Copy link

ivanooi commented Sep 1, 2022

I see... @frank-dspeed so, your solution is to compile the logic into another executable...

binary.exe <==> named pipe <==> module.exe

@frank-dspeed
Copy link

@ivanooi for logic you could maybe use espresso it is the JDK running on GraalVM that means you can compile a JDK into your binary that can do runtime evaluation. https://www.graalvm.org/22.0/reference-manual/java-on-truffle/

but at last to get a binary with fast runtime logic evaluation you need to embedded any engine at last i would go for JS as the es4x project did prove that this even outpferforms many java only stacks. https://github.com/reactiverse/es4x you can compile that to nativ via quarkus it got done successfull .

@ivanooi
Copy link

ivanooi commented Sep 2, 2022

image

point number 3, does it mean native executable? so...with espresso, i can dynamically load and execute java bytecode in the native image?

thanks! look promising! :-D

@ivanooi for logic you could maybe use espresso it is the JDK running on GraalVM that means you can compile a JDK into your binary that can do runtime evaluation. https://www.graalvm.org/22.0/reference-manual/java-on-truffle/

but at last to get a binary with fast runtime logic evaluation you need to embedded any engine at last i would go for JS as the es4x project did prove that this even outpferforms many java only stacks. https://github.com/reactiverse/es4x you can compile that to nativ via quarkus it got done successfull .

@oeresundsgruppen
Copy link

Wonder if this is working now - with dynamic classes ? forName(..) ?

@jeffecom
Copy link

jeffecom commented Jun 5, 2023

that reminds me Excelsior Jet JVM which compile java into native code, at the same time they able to compile any downloaded jar into dll as well.

I don't think Jet quite did that exactly .

Your basic app would be AOT compiled into .exe and .dll files, and additional classes encountered at runtime would be JIT compiled by the JVM Jet provided too. Best of both worlds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests