Skip to content

leng25/SourceRunner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 

Repository files navigation

SourceRunner

License: MIT

SourceRunner is a lightweight Java library that allows you to compile and run Java code directly from a string at runtime. It compiles source code in memory, loads the resulting bytecode using a custom class loader, and executes methods using reflection. This is useful for applications that need to execute dynamically generated or user-provided Java code without writing it to disk.

Architecture

The following diagram illustrates the architecture of SourceRunner:

graph TD
    subgraph "User Code"
        A[Source Code as String]
    end

    subgraph "SourceRunner Library"
        B[SourceRunner]
        C[InMemoryCompiler]
        D[InMemoryFileManager]
        E[Custom ClassLoader]
        F[InMemoryByteCode]
        G[Reflection API]
    end

    subgraph "Java Compiler API"
        H[javax.tools.JavaCompiler]
    end

    A --> B;
    B --> C;
    C --> H;
    H --> D;
    D --> F;
    D --> E;
    B --> E;
    B --> G;
Loading

How It Works

  1. Source Code Input: The user provides Java source code as a list of strings to the SourceRunner.
  2. Compilation: The SourceRunner passes the source code to the InMemoryCompiler.
  3. Java Compiler: The InMemoryCompiler obtains an instance of the system's JavaCompiler and uses it to compile the source code.
  4. In-Memory File Management: The InMemoryFileManager intercepts the output of the compiler. Instead of writing .class files to disk, it stores the compiled bytecode in InMemoryByteCode objects, which are held in a map in memory.
  5. Custom Class Loading: The InMemoryFileManager uses a custom ClassLoader to load classes directly from the in-memory bytecode. This allows the application to use the compiled classes without them ever existing on the file system.
  6. Instantiation and Execution: The SourceRunner uses the custom class loader to load the desired class. It then uses the Java Reflection API to instantiate the class and invoke its methods.

Handling Dependencies

SourceRunner can handle multiple source files with dependencies between them. When you provide a list of source code strings to the SourceRunner, it compiles all of them. The custom class loader can then load any of the compiled classes, resolving dependencies between them from the in-memory bytecode store.

For example, if you have two classes, ClassA and ClassB, where ClassA depends on ClassB, you can provide both of their source codes to the SourceRunner. The compiler will compile both, and when ClassA is loaded, the custom class loader will find and load ClassB from memory.

Features

  • In-Memory Compilation: Compiles Java source code from strings without creating .java files.
  • Dynamic Class Loading: Loads compiled classes on the fly.
  • Method Execution: Execute methods on the dynamically loaded classes using reflection.
  • No File I/O: The entire process from source to execution happens in memory.
  • Simple API: A clean and easy-to-use interface.

Requirements

  • Java 21 or higher (as specified in pom.xml).

Installation

To use SourceRunner in your Maven project, add the following dependency to your pom.xml:

<dependency>
  <groupId>com.leng25.sourcerunner</groupId>
  <artifactId>SourceRunner</artifactId>
  <version>1.1-SNAPSHOT</version>
</dependency>

Usage

Here is a simple example of how to use SourceRunner to compile and run a "Hello, World!" program.

import com.leng25.sourcerunner.SourceRunner;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // 1. Your Java code as a string
        String sourceCode = """
            package com.example;

            public class Greeter {
                public String greet(String name) {
                    return "Hello, " + name + "!";
                }
            }
        """;

        try {
            // 2. Create a SourceRunner instance with your source code
            SourceRunner runner = new SourceRunner(List.of(sourceCode));

            // 3. Instantiate your class
            Object greeterInstance = runner.instanciate("com.example.Greeter");

            // 4. Run a method on the instance
            String result = runner.run(greeterInstance, "greet", "World");

            // 5. Print the result
            System.out.println(result); // Outputs: Hello, World!

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Contributing

Contributions are welcome! If you have ideas for improvements or find a bug, please open an issue or submit a pull request.

  1. Fork the repository.
  2. Create a new branch (git checkout -b feature/YourFeature).
  3. Commit your changes (git commit -m 'Add some feature').
  4. Push to the branch (git push origin feature/YourFeature).
  5. Open a pull request.

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published