Invece di scrivere un sacco di codice per avere Java essere eseguibile in formato sorgente, avete alcune opzioni:
Usa Scala! Sapevi che Scala è costruita fuori da Java? Ha un interprete e un compilatore. Puoi eseguire uno script, una shell o compilare ed eseguirlo. Scala e Java funzionano perfettamente insieme. Entrambi compilano lo stesso bytecode ed eseguono su una JVM. Sì, il linguaggio sarebbe strano perché Scala è come un incrocio tra Java, R e Python, ma la maggior parte del linguaggio principale è invariato e tutti i pacchetti Java sono disponibili. Fai un tentativo a Scala. Se sei su Linux, potresti anche guardare Spark, anche per una macchina.
Se si insiste a utilizzare solo Java, è possibile creare un programma ibrido che faccia due cose (l'ho già fatto prima): compila il codice ed eseguilo. L'eseguibile o anche uno script di bash può fare il lavoro di prendere i file sorgente e renderli eseguibili. Se si sta cercando di creare una shell Java, è necessario creare un compilatore/caricatore di runtime dinamico, ma è sufficiente utilizzare ciò che Java/Oracle ci offre già. Immagina di inserire la sintassi Java da un file in cui inserisco una dichiarazione di stampa. Potresti avere qualsiasi cosa lì dentro che volevi fintanto che compila. Vedere questo esempio:
package util.injection;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Compiler {
static final long t0 = System.currentTimeMillis();
public static void main(String[] args) {
StringBuilder sb = new StringBuilder(64);
String packageName = "util";
String className = "HelloWorld";
sb.append("package util;\n");
sb.append("public class HelloWorld extends " + Function.class.getName() + " {\n");
sb.append(" public void test() {\n");
sb.append(" System.out.println(\"Hello from dynamic function!\");\n");
sb.append(" }\n");
sb.append("}\n");
String code = sb.toString();
String jarLibraryFile = "target/myprojectname.jar";
Function dynFunction = code2class(packageName, className, code, jarLibraryFile);
dynFunction.test();
}
public static Function code2class(String packageName, String className, String code, String jarLibraryFile) {
String wholeClassName = packageName.replace("/", ".") + "." + className;
String fileName = wholeClassName.replace(".", "/") + ".java";//"testcompile/HelloWorld.java";
File javaCodeFile = new File(fileName);
string2file(javaCodeFile, code);
Function dynFunction = null;
try {
boolean success = compile(jarLibraryFile, javaCodeFile);
/**
* Load and execute
* ************************************************************************************************
*/
System.out.println("Running... " + (System.currentTimeMillis() - t0) + " ms");
Object obj = load(wholeClassName);
// Santity check
if (obj instanceof Function) {
dynFunction = (Function) obj;
// Run it
//Edit: call dynFunction.test(); to see something
}
System.out.println("Finished... " + (System.currentTimeMillis() - t0) + " ms");
} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) {
exp.printStackTrace();
}
return dynFunction;
}
public static boolean compile(String jarLibraryFile, File javaCodeFile) throws IOException {
/**
* Compilation Requirements
* ********************************************************************************************
*/
System.out.println("Compiling... " + (System.currentTimeMillis() - t0) + " ms");
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
// This sets up the class path that the compiler will use.
// I've added the .jar file that contains the DoStuff interface within in it...
List<String> optionList = new ArrayList<>(2);
optionList.add("-classpath");
optionList.add(System.getProperty("java.class.path") + ";" + jarLibraryFile);
Iterable<? extends JavaFileObject> compilationUnit
= fileManager.getJavaFileObjectsFromFiles(Arrays.asList(javaCodeFile));
JavaCompiler.CompilationTask task = compiler.getTask(
null,
fileManager,
diagnostics,
optionList,
null,
compilationUnit);
fileManager.close();
/**
* *******************************************************************************************
* Compilation Requirements *
*/
if (task.call()) {
return true;
/**
* ***********************************************************************************************
* Load and execute *
*/
} else {
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
System.out.format("Error on line %d in %s%n",
diagnostic.getLineNumber(),
diagnostic.getSource().toUri());
System.out.printf("Code = %s\nMessage = %s\n", diagnostic.getCode(), diagnostic.getMessage(Locale.US));
}
}
return false;
}
public static void string2file(File outputFile, String code) {
if (outputFile.getParentFile().exists() || outputFile.getParentFile().mkdirs()) {
try {
Writer writer = null;
try {
writer = new FileWriter(outputFile);
writer.write(code);
writer.flush();
} finally {
try {
writer.close();
} catch (Exception e) {
}
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
public static Object load(String wholeClassName) throws IllegalAccessException, InstantiationException, ClassNotFoundException, MalformedURLException {
// Create a new custom class loader, pointing to the directory that contains the compiled
// classes, this should point to the top of the package structure!
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()});
// Load the class from the classloader by name....
Class<?> loadedClass = classLoader.loadClass(wholeClassName);
// Create a new instance...
Object obj = loadedClass.newInstance();
return obj;
}
}
..
package util.injection;
public class Function {
private static final long serialVersionUID = 7526472295622776147L;
public void test() {
System.out.println("Hello from original Function!");
}
public int getID() {
return -1;
}
public void apply(float[] img, int x, int y) {
}
public double dot(double[] x, double[] y) {
return 0;
}
}
Ahh modo con Java i file .class dovranno essere conservati altrove e fa riferimento l'eseguibile ancora? –
Sì, è corretto e dovresti assicurarti che il percorso di classe fosse corretto prima di eseguirlo. Quindi è più pratico usare solitamente uno sh script. –
È interessante. Non sapevo che potresti passare argomenti anche dopo lo shebang.Immagino sia quello che ottengo per essere autodidatta haha. Risposta approvata! –