Skip to content

Commit

Permalink
Added support for automatically setting a module main class if module…
Browse files Browse the repository at this point in the history
…-info.java is part of the compilation operation and a main class was provided by the project.
  • Loading branch information
gbevin committed Aug 25, 2024
1 parent 9f9e8a9 commit fd1429f
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 4 deletions.
44 changes: 44 additions & 0 deletions src/main/java/rife/bld/instrument/ModuleMainClassAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2001-2024 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.instrument;

import rife.asm.*;

/**
* This utility class will modify a Java module {@code module-info.class} to add
* a module main class to its attributes.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 2.1
*/
public class ModuleMainClassAdapter extends ClassVisitor implements Opcodes {
private final String mainClass_;

/**
* Performs the actual modification of the module info class's bytecode.
*
* @param origBytes the bytes of the module class that should be modified
* @param mainClass the main class of the module
* @return the modified bytes
* @since 2.1
*/
public static byte[] addModuleMainClassToBytes(byte[] origBytes, String mainClass) {
var cw = new ClassWriter(0);
new ClassReader(origBytes).accept(new ModuleMainClassAdapter(mainClass, cw), 0);
return cw.toByteArray();
}

private ModuleMainClassAdapter(String mainClass, ClassVisitor writer) {
super(ASM9, writer);
mainClass_ = mainClass.replace('.', '/');
}

@Override
public ModuleVisitor visitModule(String name, int access, String version) {
var module_visitor = super.visitModule(name, access, version);
module_visitor.visitMainClass(mainClass_);
return module_visitor;
}
}
34 changes: 33 additions & 1 deletion src/main/java/rife/bld/operations/CompileOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package rife.bld.operations;

import rife.bld.BaseProject;
import rife.bld.instrument.ModuleMainClassAdapter;
import rife.bld.operations.exceptions.ExitStatusException;
import rife.tools.FileUtils;

Expand Down Expand Up @@ -34,6 +35,7 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
private final List<File> testSourceDirectories_ = new ArrayList<>();
private final JavacOptions compileOptions_ = new JavacOptions();
private final List<Diagnostic<? extends JavaFileObject>> diagnostics_ = new ArrayList<>();
private String moduleMainClass_;

/**
* Performs the compile operation.
Expand Down Expand Up @@ -135,6 +137,12 @@ protected void executeBuildSources(List<String> classpath, List<String> modulePa
diagnostics_.addAll(diagnostics.getDiagnostics());
executeProcessDiagnostics(diagnostics);
}
var module_info_class = new File(destination, "module-info.class");
if (module_info_class.exists() && moduleMainClass() != null) {
var orig_bytes = FileUtils.readBytes(module_info_class);
var transformed_bytes = ModuleMainClassAdapter.addModuleMainClassToBytes(orig_bytes, moduleMainClass());
FileUtils.writeBytes(transformed_bytes, module_info_class);
}
}
}

Expand Down Expand Up @@ -175,7 +183,8 @@ public CompileOperation fromProject(BaseProject project) {
.compileMainModulePath(project.compileMainModulePath())
.compileTestModulePath(project.compileTestModulePath())
.mainSourceFiles(project.mainSourceFiles())
.testSourceFiles(project.testSourceFiles());
.testSourceFiles(project.testSourceFiles())
.moduleMainClass(project.mainClass());
if (project.javaRelease() != null && !compileOptions().containsRelease()) {
compileOptions().release(project.javaRelease());
}
Expand Down Expand Up @@ -428,6 +437,18 @@ public CompileOperation compileOptions(List<String> options) {
return this;
}

/**
* Provides the main class to use if this compilation includes @{code module-info.java}.
*
* @param name the main class of the module
* @return this operation instance
* @since 2.1
*/
public CompileOperation moduleMainClass(String name) {
moduleMainClass_ = name;
return this;
}

/**
* Retrieves the main build destination directory.
*
Expand Down Expand Up @@ -565,4 +586,15 @@ public JavacOptions compileOptions() {
public List<Diagnostic<? extends JavaFileObject>> diagnostics() {
return diagnostics_;
}


/**
* Retrieves the main class to use if this compilation includes @{code module-info.java}.
*
* @return the main class to use for the module
* @since 2.1
*/
public String moduleMainClass() {
return moduleMainClass_;
}
}
6 changes: 3 additions & 3 deletions src/test/java/rife/bld/operations/TestRunOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ public static void main(String[] arguments)
var compile_operation = new CompileOperation()
.buildMainDirectory(build_main)
.compileMainClasspath(List.of(build_main.getAbsolutePath()))
.mainSourceFiles(List.of(source_file1, source_file2));
.mainSourceFiles(List.of(source_file1, source_file2))
.moduleMainClass("pkg.Source1");
compile_operation.execute();
assertTrue(compile_operation.diagnostics().isEmpty());

Expand All @@ -209,12 +210,11 @@ public static void main(String[] arguments)
.sourceDirectories(List.of(build_main))
.destinationDirectory(destination_dir)
.destinationFileName(destination_name)
.manifestAttribute(Attributes.Name.MAIN_CLASS, "pkg.Source1")
.execute();

var output = new StringBuilder();
var run_operation = new RunOperation()
.module("pkg/pkg.Source1")
.module("pkg")
.modulePath(new File(destination_dir, destination_name).getAbsolutePath())
.outputProcessor(s -> {
output.append(s);
Expand Down

0 comments on commit fd1429f

Please sign in to comment.