Zamiast pisać dużo kodu Java mają być wykonywalny w postaci źródłowej, masz kilka opcji:
Zastosowanie Scala! Czy wiesz, że Scala jest zbudowana na Jawie? Ma interpreter i kompilator. Możesz uruchomić skrypt, powłokę lub skompilować i uruchomić go. Scala i Java współpracują ze sobą bezproblemowo. Obie kompilują się do tego samego kodu bajtowego i działają na maszynie JVM. Tak, język będzie dziwny, ponieważ Scala jest jak skrzyżowanie Javy, R i Pythona, ale większość podstawowego języka pozostaje niezmieniona i wszystkie pakiety Java są dostępne. Wypróbuj Scalę. Jeśli korzystasz z Linuksa, równie dobrze możesz spojrzeć na Sparka, nawet na jeden komputer.
Jeśli nalegasz na używanie tylko Java, możesz stworzyć hybrydowy program, który robi dwie rzeczy (robiłem to wcześniej): skompiluj kod i uruchom go. Skrypt wykonywalny, a nawet bash może wykonywać pracę polegającą na pobieraniu plików źródłowych i wykonywaniu ich. Jeśli szukasz powłoki Java, musisz utworzyć dynamiczny kompilator/program ładujący, ale musisz po prostu użyć tego, co już daje nam Java/Oracle. Wyobraź sobie wstawianie składni Java z pliku, w którym umieściłem instrukcję print. Możesz mieć wszystko, co chcesz, tak długo jak się kompiluje. Zobacz poniższy przykład:
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 tak z Java pliki .class będą musiały być przechowywane w innym miejscu i odwołuje wykonywalnego jeszcze? –
Tak, to prawda, a przed uruchomieniem tej opcji musisz się upewnić, że ścieżka klas jest poprawna. Dlatego bardziej praktyczne jest używanie skryptu sh. –
To interesujące. Nie wiedziałem, że potrafisz przekazywać argumenty po shebangu.Sądzę, że to jest to, co dostaję za bycie samoukiem haha. Odpowiedź zatwierdzona! –