I need develop a "launcher" for a java application. This launcher need be able to:
check if main application is up-to-date;
if not, download a update;
run this application and self terminate.
Something like this:
public final class Launcher {
public static void main(String[] args) throws Exception {
String jarName = args[0];
if (jarHasUpdate(jarName)
refreshJar(jarName);
executeJar(jarName);
}
}
What better way of develop the step 3?
I'm trying 2 distinct ways:
1- Run another instance of Java
With the code:
Runtime.getRuntime().exec("java -jar mainApp.jar");
Problem: the launcher still running until mainApp have finished.
2- Using ClassLoader to load .jar at runtime
Like this:
public final class Launcher {
#SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.out.println("Invalid number of arguments.");
System.exit(1);
}
Refresh.refreshFile(args[0]);
// args[0] .jar name
// args[1] class with main function
File file = new File(args[0]);
try (URLClassLoader cl = new URLClassLoader(new URL[] { file.toURI().toURL() });) {
Class cls = cl.loadClass(args[1]);
Method method = cls.getDeclaredMethod("main", new Class[] { String[].class });
Object params = new String[] {};
method.invoke(cls, params);
}
}
}
Problem: if "mainApp.jar" has dependencies, this isn't loaded.
Related
I was trying to read all methods and their return types from already complied .class files from the external path to see the structure of the file. If the compiled file is in your System or can be imported (eg String.class) then it's easy we can simply call this method and get the result. But is there a way to solve this problem for an externally compiled .class file? EDIT: with latest comment I used URLClassLoader but it is giving Exception in thread "main" java.lang.NoClassDefFoundError: MyClassFile (wrong name: a/b/MyClassFile)
public class JavaMethodsNameGeneration {
public static void main(String[] args) {
URL classUrl;
File file = new File ("C:/Users/myPath");
classUrl = file.toURI().toURL();
URL[] classUrls = { classUrl };
URLClassLoader ucl = new URLClassLoader(classUrls);
Class myClass = ucl.loadClass("MyClassFile");
System.out.println(generateMethodNameToFile(String.class));//Write the output string to file
}
public static String generateMethodNameToFile(Class className){
Method[] methods = className.getMethods();
StringBuilder stringBuilder = new StringBuilder();
Arrays.stream(methods).forEach(method -> {
stringBuilder.append(method.getName()).append("(");
Class<?>[] parameterTypes = method.getParameterTypes();
if(parameterTypes.length>0){
Arrays.stream(parameterTypes).forEach(p->{
stringBuilder.append(p.getSimpleName()).append(",");
});
}
else{
stringBuilder.append(" ");
}
stringBuilder.setLength(Math.max(stringBuilder.length()-1,0));
stringBuilder.append(")").append(" : ").append(method.getReturnType().equals(Void.class)?"void": method.getReturnType().getSimpleName());
if(method.getExceptionTypes().length>0){
stringBuilder.append(" throws ").append(Arrays.stream(method.getExceptionTypes()).map(Class::getSimpleName).collect(Collectors.joining(", ")));
}
stringBuilder.append(System.lineSeparator());
});
return stringBuilder.toString();
}
}
public class TestResourceBundle {
private static final Path frZoo = Paths.get("./src/Zoo_fr.properties");
private static final Path enZoo = Paths.get("./src/Zoo_en.properties");
private static void createFiles() {
try {
Files.createFile(frZoo);
Files.createFile(enZoo);
try (BufferedWriter enWriter = Files.newBufferedWriter(enZoo);
BufferedWriter frWriter = Files.newBufferedWriter(frZoo);) {
enWriter.write("hello=Hello\nopen=The zoo is open");
frWriter.write("hello=Bonjour\nopen=Le zoo est ouvert");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void createBundle() {
Locale us = new Locale("en", "US");
Locale france = new Locale("fr", "FR");
ResourceBundle usBundle = ResourceBundle.getBundle("Zoo", us);
ResourceBundle frBundle = ResourceBundle.getBundle("Zoo", france);
System.out.println(usBundle.getString("hello"));
System.out.println(frBundle.getString("hello"));
}
}
In the main function, if I run the following, it will throw java.util.MissingResourceException
public static void main(String[] args) {
createFiles();
createBundle();
}
but if I run these two functions separately (in two programs), it works and does not have any problem.
First run
public static void main(String[] args) {
createFiles();
// createBundle();
}
then run the following, in this case, it works
public static void main(String[] args) {
// createFiles();
createBundle();
}
I don't know why, please help
The problem is that you are trying to load a bundle that is not present in the classpath the application knows about.
When you call ResourceBundle.getBundle it will try to load the resource bundle from the application classpath. But the application classpath was already defined at the application startup, so your brand new files are not listed there.
Two options I can think of: Load the bundle from a file input stream or, define your own classloader to load the files.
1. Load the bundle from a File Input Stream
Create a new PropertyResourceBundle from a FileInputStream that loads each file directly.
Warning: Stream closing and exception handling omitted for brevity.
FileInputStream enFileStream = new FileInputStream("./src/Zoo_en.properties");
FileInputStream frFileStream = new FileInputStream("./src/Zoo_fr.properties");
ResourceBundle usBundle = new PropertyResourceBundle(enFileStream);
ResourceBundle frBundle = new PropertyResourceBundle(frFileStream);
2. Create a URL ClassLoader to load the new files
This is a more scalable approach. Create a new URLClassLoader and use that class loader as an argument for getBundle.
Warning: Stream closing and exception handling omitted for brevity.
File bundleRootPath = new File("./src");
URL[] urls = new URL[]{bundleRootPath.toURI().toURL()};
ClassLoader classLoader = new URLClassLoader(urls);
ResourceBundle usBundle = ResourceBundle.getBundle("Zoo", us, classLoader);
ResourceBundle frBundle = ResourceBundle.getBundle("Zoo", france, classLoader);
Hope that helps.
So it might seem like a trivial question, but I cannot find any information out there that answers my question. Nonetheless, it is a very general coding question.
Suppose you have a java program that reads a file and creates a data structure based on the information provided by the file. So you do:
javac javaprogram.java
java javaprogram
Easy enough, but what I want to do here is to provide the program with a file specified in the command line, like this:
javac javaprogram.java
java javaprogram -file
What code do I have to write to conclude this very concern?
Thanks.
One of the best command-line utility libraries for Java out there is JCommander.
A trivial implementation based on your thread description would be:
public class javaprogram {
#Parameter(names={"-file"})
String filePath;
public static void main(String[] args) {
// instantiate your main class
javaprogram program = new javaprogram();
// intialize JCommander and parse input arguments
JCommander.newBuilder().addObject(program).build().parse(args);
// use your file path which is now accessible through the 'filePath' field
}
}
You should make sure that the library jar is available under your classpath when compiling the javaprogram.java class file.
Otherwise, in case you don't need an utility around you program argument, you may keep the program entry simple enough reading the file path as a raw program argument:
public class javaprogram {
private static final String FILE_SWITCH = "-file";
public static void main(String[] args) {
if ((args.length == 2) && (FILE_SWITCH.equals(args[0]))) {
final String filePath = args[1];
// use your file path which is now accessible through the 'filePath' local variable
}
}
}
The easiest way to do it is using -D, so if you have some file, you could call
java -Dmy.file=file.txt javaprogram
And inside you program you could read it with System.getProperty("my.file").
public class Main {
public static void main(String[] args) {
String filename = System.getProperty("my.file");
if (filename == null) {
System.exit(-1); // Or wharever you want
}
// Read and process your file
}
}
Or you could use third a party tool like picocli
import java.io.File;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
#Command(name = "Sample", header = "%n#|green Sample demo|#")
public class Sample implements Runnable {
#Option(names = {"-f", "--file"}, required = true, description = "Filename")
private File file;
#Override
public void run() {
System.out.printf("Loading %s%n", file.getAbsolutePath());
}
public static void main(String[] args) {
CommandLine.run(new Sample(), System.err, args);
}
}
You can pass file path as argument in two ways:
1)
public class Main {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("File path plz");
return;
}
System.out.println("File path: " + args[0]);
}
}
2) Use JCommander
Let's go step by step. First you need to pass the file path to your program.
Lets say you execute your program like this:
java javaprogram /foo/bar/file.txt
Strings that come after "javaprogram" will be passed as arguments to your program. This is the reason behind the syntax of the main method:
public static void main(String[] args) {
//args is the array that would store all the values passed when executing your program
String filePath = args[0]; //filePath will contain /foo/bar/file.txt
}
Now that you were able to get a the file path and name from the command-line, you need to open and read your file.
Take a look at File class and FileInputStream class.
https://www.mkyong.com/java/how-to-read-file-in-java-fileinputstream/
That should get you started.
Good luck!
Why does my code (compiles fine) gives me the following error?
Main method not found in class ImageTool, please define the main method as: public static void main(String[] args)
Code:
public class ImageTool {
public static void main(String[] args) {
if (args.length <1) {
System.out.println("Please type in an argument");
System.exit(-1);
}
if (args[0].equals("--dump")) {
String filename = args[1];
int[][] image = readGrayscaleImage(filename);
print2DArray(image);
} else if (args[0].equals("--reflectV")) {
String filename = args[1];
int[][] image = readGrayscaleImage(filename);
int[][] reflect = reflectV(image); //reflectV method must be written
String outputFilename = args[2];
writeGrayscaleImage(outputFilename,reflect);
}
}
Your main method looks fine.
1) Probably your .class file does not correspond to your .java file.
I would try to clean up my project (if I was using an IDE and getting this).
That is: delete the .class file, regenerate it from the .java file.
2) Seems you're not running ImageFile but some other class,
even though you think you're running ImageFile. Check what
your IDE is running behind the scenes.
I hope one of these two suggestions would help.
Frankly, I do not know even it is possible or not.
But what I am trying to do is just like below.
I made a class file from ClassFile.java via javac command in terminal.
Then I want to get an instance from .java file or .class file.
Next, I made another project in eclipse, As you guess this project path and upper file path are completely different. For instance, ClassFile.java/class file can be located in '~/Downloads' folder, the other hand, new eclipse project can be in '~/workspace/'.
So I read file which referred in step 1 by FileInputStream.
From here, I just paste my code.
public class Main {
private static final String CLASS_FILE_PATH =
"/Users/juneyoungoh/Downloads/ClassFile.class";
private static final String JAVA_FILE_PATH =
"/Users/juneyoungoh/Downloads/ClassFile.java";
private static Class getClassFromFile(File classFile) throws Exception {
System.out.println("get class from file : [" + classFile.getCanonicalPath() + " ]");
Object primativeClz = new Object();
ObjectInputStream ois = null;
ois = new ObjectInputStream(new FileInputStream(classFile));
primativeClz = ois.readObject();
ois.close();
return primativeClz.getClass();
}
public static void main(String[] args) throws Exception {
getClassInfo(getClassFromFile(new File(CLASS_FILE_PATH)));
}
}
just like your assumption, this code has errors.
For example, it shows :
java.io.StreamCurruptedException: invalid stream header : CAFEBABE
this there any way to get object instance from .class file or .java file?
P.S.
I wish do not use extra libraries.
private static final String CLASS_FOLDER =
"/Users/juneyoungoh/Downloads/";
private static Class getClassFromFile(String fullClassName) throws Exception {
URLClassLoader loader = new URLClassLoader(new URL[] {
new URL("file://" + CLASS_FOLDER)
});
return loader.loadClass(fullClassName);
}
public static void main( String[] args ) throws Exception {
System.out.println((getClassFromFile("ClassFile"));
}