I am making software that will need to dynamically create java bytecode, and possibly even make it a runnable jar.
My current idea is to create a new .java file and compile it at runtime. I can create the file, but I'm not sure how to compile it at runtime, and make it a runnable jar. Any help would be greatly appreciated.
public static String generate(String filePath) {
try {
File file = new File("Test.java");
if(!file.exists())file.createNewFile();
FileWriter write = new FileWriter(filePath+".java");
BufferedWriter out = new BufferedWriter(write);
out.write(
"public class Test {\n\t" +
"public static void main(String[] args){\n\t\t"+
"System.out.println(\"Working\");\n\t"+
"}\n" +
"}"
);
out.close();
} catch (Exception e) {// Catch exception if any
return "Error: " + e.getMessage();
}
return "Test.java created!";
}
To compile Java code, you can use the Java Compiler API.
To generate byte code directly, you can use tools like ASM.
To generate an executable JAR, create a JarOutputStream with a manifest that declares the main class.
You can certainly use ASM and the like, but don't discount scripting languages on the jvm. ASM might be confusing if you're not very familiar with the vm and bytecode in general. You could generate groovy or jython (or whatever language you like) code to a file, and package that up with a main program in a jar file.
As an example, you create a main program which looks for a classpath resource and sends it off to the groovy scripting language:
Binding binding = new Binding();
// maybe set some binding variables here
GroovyShell shell = new GroovyShell(binding);
GroovyCodeSource source =
new GroovyCodeSource(
Thread.currentThread().getContextClassLoader().getResource("script.groovy"));
Object value = shell.evaluate(source);
Once you have that, it would be easy to package up the main class and the script in an executable jar. You could even unpack the groovy-all.jar and pack it up in your jar to make it a fully self contained executable jar file.
It all boils down to what you are trying to accomplish, and either approach would probably work for you.
Related
How can I change the current working directory from within a Java program? Everything I've been able to find about the issue claims that you simply can't do it, but I can't believe that that's really the case.
I have a piece of code that opens a file using a hard-coded relative file path from the directory it's normally started in, and I just want to be able to use that code from within a different Java program without having to start it from within a particular directory. It seems like you should just be able to call System.setProperty( "user.dir", "/path/to/dir" ), but as far as I can figure out, calling that line just silently fails and does nothing.
I would understand if Java didn't allow you to do this, if it weren't for the fact that it allows you to get the current working directory, and even allows you to open files using relative file paths....
There is no reliable way to do this in pure Java. Setting the user.dir property via System.setProperty() or java -Duser.dir=... does seem to affect subsequent creations of Files, but not e.g. FileOutputStreams.
The File(String parent, String child) constructor can help if you build up your directory path separately from your file path, allowing easier swapping.
An alternative is to set up a script to run Java from a different directory, or use JNI native code as suggested below.
The relevant OpenJDK bug was closed in 2008 as "will not fix".
If you run your legacy program with ProcessBuilder, you will be able to specify its working directory.
There is a way to do this using the system property "user.dir". The key part to understand is that getAbsoluteFile() must be called (as shown below) or else relative paths will be resolved against the default "user.dir" value.
import java.io.*;
public class FileUtils
{
public static boolean setCurrentDirectory(String directory_name)
{
boolean result = false; // Boolean indicating whether directory was set
File directory; // Desired current working directory
directory = new File(directory_name).getAbsoluteFile();
if (directory.exists() || directory.mkdirs())
{
result = (System.setProperty("user.dir", directory.getAbsolutePath()) != null);
}
return result;
}
public static PrintWriter openOutputFile(String file_name)
{
PrintWriter output = null; // File to open for writing
try
{
output = new PrintWriter(new File(file_name).getAbsoluteFile());
}
catch (Exception exception) {}
return output;
}
public static void main(String[] args) throws Exception
{
FileUtils.openOutputFile("DefaultDirectoryFile.txt");
FileUtils.setCurrentDirectory("NewCurrentDirectory");
FileUtils.openOutputFile("CurrentDirectoryFile.txt");
}
}
It is possible to change the PWD, using JNA/JNI to make calls to libc. The JRuby guys have a handy java library for making POSIX calls called jnr-posix. Here's the maven info
As mentioned you can't change the CWD of the JVM but if you were to launch another process using Runtime.exec() you can use the overloaded method that lets you specify the working directory. This is not really for running your Java program in another directory but for many cases when one needs to launch another program like a Perl script for example, you can specify the working directory of that script while leaving the working dir of the JVM unchanged.
See Runtime.exec javadocs
Specifically,
public Process exec(String[] cmdarray,String[] envp, File dir) throws IOException
where dir is the working directory to run the subprocess in
If I understand correctly, a Java program starts with a copy of the current environment variables. Any changes via System.setProperty(String, String) are modifying the copy, not the original environment variables. Not that this provides a thorough reason as to why Sun chose this behavior, but perhaps it sheds a little light...
The working directory is a operating system feature (set when the process starts).
Why don't you just pass your own System property (-Dsomeprop=/my/path) and use that in your code as the parent of your File:
File f = new File ( System.getProperty("someprop"), myFilename)
The smarter/easier thing to do here is to just change your code so that instead of opening the file assuming that it exists in the current working directory (I assume you are doing something like new File("blah.txt"), just build the path to the file yourself.
Let the user pass in the base directory, read it from a config file, fall back to user.dir if the other properties can't be found, etc. But it's a whole lot easier to improve the logic in your program than it is to change how environment variables work.
I have tried to invoke
String oldDir = System.setProperty("user.dir", currdir.getAbsolutePath());
It seems to work. But
File myFile = new File("localpath.ext");
InputStream openit = new FileInputStream(myFile);
throws a FileNotFoundException though
myFile.getAbsolutePath()
shows the correct path.
I have read this. I think the problem is:
Java knows the current directory with the new setting.
But the file handling is done by the operation system. It does not know the new set current directory, unfortunately.
The solution may be:
File myFile = new File(System.getPropety("user.dir"), "localpath.ext");
It creates a file Object as absolute one with the current directory which is known by the JVM. But that code should be existing in a used class, it needs changing of reused codes.
~~~~JcHartmut
You can use
new File("relative/path").getAbsoluteFile()
after
System.setProperty("user.dir", "/some/directory")
System.setProperty("user.dir", "C:/OtherProject");
File file = new File("data/data.csv").getAbsoluteFile();
System.out.println(file.getPath());
Will print
C:\OtherProject\data\data.csv
You can change the process's actual working directory using JNI or JNA.
With JNI, you can use native functions to set the directory. The POSIX method is chdir(). On Windows, you can use SetCurrentDirectory().
With JNA, you can wrap the native functions in Java binders.
For Windows:
private static interface MyKernel32 extends Library {
public MyKernel32 INSTANCE = (MyKernel32) Native.loadLibrary("Kernel32", MyKernel32.class);
/** BOOL SetCurrentDirectory( LPCTSTR lpPathName ); */
int SetCurrentDirectoryW(char[] pathName);
}
For POSIX systems:
private interface MyCLibrary extends Library {
MyCLibrary INSTANCE = (MyCLibrary) Native.loadLibrary("c", MyCLibrary.class);
/** int chdir(const char *path); */
int chdir( String path );
}
The other possible answer to this question may depend on the reason you are opening the file. Is this a property file or a file that has some configuration related to your application?
If this is the case you may consider trying to load the file through the classpath loader, this way you can load any file Java has access to.
If you run your commands in a shell you can write something like "java -cp" and add any directories you want separated by ":" if java doesnt find something in one directory it will go try and find them in the other directories, that is what I do.
Use FileSystemView
private FileSystemView fileSystemView;
fileSystemView = FileSystemView.getFileSystemView();
currentDirectory = new File(".");
//listing currentDirectory
File[] filesAndDirs = fileSystemView.getFiles(currentDirectory, false);
fileList = new ArrayList<File>();
dirList = new ArrayList<File>();
for (File file : filesAndDirs) {
if (file.isDirectory())
dirList.add(file);
else
fileList.add(file);
}
Collections.sort(dirList);
if (!fileSystemView.isFileSystemRoot(currentDirectory))
dirList.add(0, new File(".."));
Collections.sort(fileList);
//change
currentDirectory = fileSystemView.getParentDirectory(currentDirectory);
I have a jar file when unzipped looks like the following:
models/
com/
com/github/
com/github/
com/github/test/linux-x86_64/
com/github/test/config/
models/model.bin
com/github/test/Test.class
In the Test class, I'm using the path of model.bin inside the getResults method like so:
public class Test {
public List<Label> getResults(String text, int k) {
// Load model from file
loadModel("models/model.bin");
// Do label prediction
return results(text, k);
}
}
The loadModel method above is actually c++ method that looks like this. I am writing a Java Wrapper around a c++ library:
void Testtext::loadModel(const std::string& filename) {
std::ifstream ifs(filename, std::ifstream::binary);
if (!ifs.is_open()) {
throw std::invalid_argument(filename + " cannot be opened for loading!");
}
if (!checkModel(ifs)) {
throw std::invalid_argument(filename + " has wrong file format!");
}
loadModel(ifs);
ifs.close();
}
Currently, when I run this from an IDE, I get an error that says the model.bin file cannot be found. How do I determine the path of the model.bin within a jar file?
It sounds like whatever loadModel is (it is not part of standard java, so you'd have to elaborate) requires an actual file. Which your model.bin resource isn't (it's an entry in a jar).
Check if loadModel has an InputStream based method. It really should; if it doesn't, whatever library this is, does not follow java conventions, and is probably badly written.
If it does:
try (InputStream in = Test.class.getResourceAsStream("/models/model.bin")) {
loadModel(in);
}
will do the trick.
If it doesn't, oh boy. Either fix loadModel yourself, ask its authors to fix it, or if you must work around it, your only option is to copy the resource into an actual file, presumably in a temp dir, and then use that temporary file. This isn't pretty.
I'm facing some issues with jasper and I need to try to edit SmapUtil class inside jasper.jar file
However, I'm facing some problems to do so.
I've used jd-gui to decompile the jasper.jar file, took out the SmapUtil.java file, changed the
install method from
static void install(File classFile, byte[] smap) throws IOException {
File tmpFile = new File(classFile.getPath() + "tmp");
SDEInstaller installer = new SDEInstaller(classFile, smap);
installer.install(tmpFile);
if (!classFile.delete()) {
throw new IOException("classFile.delete() failed");
}
if (!tmpFile.renameTo(classFile)) {
throw new IOException("tmpFile.renameTo(classFile) failed");
}
}
to
static void install(File classFile, byte[] smap){
File tmpFile = new File(classFile.getPath() + "tmp");
SDEInstaller installer = new SDEInstaller(classFile, smap);
installer.install(tmpFile);
while (!classFile.delete());
while (!tmpFile.renameTo(classFile));
}
it's basically to keep trying to delete the file if it doens't work the first time.
Now it's where I'm facing my problem.
If I try to compile SmapUtil.java, I face a lot of missing sources.
I've tried using javac -classpath (original)jasper.jar SmapUtil.java, but I still have a lot of sources missings.
I've downloaded a jasper-sources.jar file from god knows where and used that as a -classpath, but the missing sources remains..
How should I do that? I don't think that it should that hard to change 2 lines of a file inside a jar..
Thankss
Compiling a large project such as Tomcat can be a fairly complicated endeavour. If you try decompiling/editing/recompiling without knowing this process you will probably run into a lot of issues.
It might easier (or at least predictable) to build the entire project from sources. Once you have managed to build it, you can try editing the sources.
You should be able to checkout the sources from the project's website.
If you need to patch this class because you feel it's not working correctly, it might be worth trying submitting a bugreport
In Python the global variable __file__ is the full path of the current file.
System.getProperty("user.dir"); seems to return the path of the current working directory.
I want to get the path of the current .java, .class or package file.
Then use this to get the path to an image.
My project file structure in Netbeans looks like this:
(source: toile-libre.org)
Update to use code suggested from my chosen best answer:
// read image data from picture in package
try {
InputStream instream = TesseractTest.class
.getResourceAsStream("eurotext.tif");
bufferedImage = ImageIO.read(instream);
}
catch (IOException e) {
System.out.println(e.getMessage());
}
This code is used in the usage example from tess4j.
My full code of the usage example is here.
If you want to load an image file stored right next to your class file, use Class::getResourceAsStream(String name).
In your case, that would be:
try (InputStream instream = TesseractTest.class.getResourceAsStream("eurotext.tif")) {
// read stream here
}
This assumes that your build system copies the .tif file to your build folder, which is commonly done by IDEs, but requires extra setup in build tools like Ant and Gradle.
If you package your program to a .jar file, the code will still work, again assuming your build system package the .tif file next to the .class file.
Is there a way to get the file path of the .java file executed or compiled?
For completeness, the literal answer to your question is "not easily and not always".
There is a round-about way to find the source filename for a class on the callstack via StackFrameElement.getFileName(). However, the filename won't always be available1 and it won't necessarily be correct2.
Indeed, it is quite likely that the source tree won't be present on the system where you are executing the code. So if you needed an image file that was stashed in the source tree, you would be out of luck.
1 - It depends on the Java compiler and compilation options that you use. And potentially on other things.
2 - For example, the source tree can be moved or removed after compilation.
Andreas has described the correct way to solve your problem. Make sure that the image file is in your application's JAR file, and access it using getResource or getResourceAsStream. If your application is using an API that requires a filename / pathname in the file system, you may need to extract the resource from the JAR to a temporary file, or something like that.
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(getPackageParent(Main.class, false));
}
public static String getPackageParent(Class<?> cls, boolean include_last_dot)
throws Exception {
StringBuilder sb = new StringBuilder(cls.getPackage().getName());
if (sb.lastIndexOf(".") > 0)
if (include_last_dot)
return sb.delete(sb.lastIndexOf(".") + 1, sb.length())
.toString();
else
return sb.delete(sb.lastIndexOf("."), sb.length()).toString();
return sb.toString();
}
}
I know that there is a plugin for ImageJ that handles NIfTI-1 files (http://rsb.info.nih.gov/ij/plugins/nifti.html).
But all its instructions on that page is to use ImageJ as a standalone program, however I am using its API. How can I know what methods are available in this jar file without its source?
I couldn't find the source code either.
For the supported archives in imageJ (such as DICOM) is quite easy :
public class ImageJTest {
public static void main(){
String path = "res/vaca.dcm";
FileInputStream fis;
ImageView image;
try {
fis = new FileInputStream(path);
DICOM d = new DICOM(fis);
d.run(path);
// Stretches the histogram because the pictures were being
// displayed too dark.
(new ij.plugin.ContrastEnhancer()).stretchHistogram(d, 0.1);
Image picture = SwingFXUtils.toFXImage(d.getBufferedImage(),
null);
// Makes the size standard for thumbnails
image = new ImageView(picture);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
How can I load the NIfTI-1 files in imageJ ?
Once you have the class files, which are embedded in the jar file (as #Alvin Thompson pointed out, these are just zip files by a different name), you can use the reflection API to mine the class files to get their methods. A sample follows for one class, cribbed from here:
Method[] methods = thisClass.getClass().getMethods(); // thisClass is an instance of the class you're working with
for(Method method : methods){
System.out.println("method = " + method.getName());
}
JAR files are just fancy ZIP files. You can rename the file to foo.zip, then use any unzip utility to expand its contents. You should be able to at least see what the class files are, and the javadocs may be bundled with it (unlikely these days but possible).
However, if you just want to know what methods are available, probably the best way is to add the JAR to the class path of a project in NetBeans, Eclipse, or IntelliJ and use their code completion features to figure out the API methods and classes.
you can do even a decompile of the jar and see the code that is behind each class using a decompiler.
A good one i found: Java Decompiler
JD-GUI home page: http://java.decompiler.free.fr
It does really good it's job. At least in the tasks i had.