Read variable value from another jar - java

I want read variable value from another jar
Main.jar
public static int version = 2;
I already did add libraries navigate to Main.jar (lib/Main.jar)
then I do this from Loader.jar
int version = dummy.Main.version;
Do replace with a new one if there are update
Loader.jar
URL url = new URL("http://127.0.0.1/cn/Main.jar");
try (InputStream in = url.openStream()) {
Files.copy(in, Paths.get("lib/Main.jar"), StandardCopyOption.REPLACE_EXISTING);
}
catch (HeadlessException | IOException | NumberFormatException e) {
//do exception
}
}
But the problem is i can not replace file because the file is being used, since Main.jar is used by Loader.jar
How the solution to replace the file being used ?

Don't replace the JAR file, because you cannot safely force the other process to not be using it.
Instead, install the newer JAR file next to it, with the version number embedded in the JAR file name, and rewrite your other users of the JAR file to periodically scan for newer JAR files. When finding one, they should throw away the class loaders that loaded the old JAR files, and reload the new set.
Or, decide not to embed this information in a JAR file at all. Resource files are easier to read and dispose of than JAR files, and they are plain text files.

You have some options
close the program using it and try again after restarting.
create a new JAR file each time and load it in a different class loader each time.
read the contents of the class in the JAR using a byte code reader such as ASM.
instead of storing the version in code, store it in a file (or as well). You can easily read the file from a JAR without putting it on the class path.
run javap to dump the code for the static field and extract the value from the text.
I suspect the last option is easiest to code.

Related

How can I add file version detail on properties to a .jar?

I'm looking to add a product version number to appear in my .jar file information. Currently I'm using Maven in my Spring boot project for API Rest.
I have read a lot of solutions about the manifest versioning. There you have to decompress and access to the META-INF/MANIFEST.MF to check the Implementation-Version. That's too tedious for what I'm looking for.
Like for a .exe. where you can found it under right mouse click -> details -> "product version" or simply checking on File Version column as shown on image. Example of a file version description.
Also I read that JAR file is a file format based on the popular ZIP file format and is used for aggregating many files into one. Kinda that I'm looking to add a file version to .zip, but I want to ask anyway if that is possible.
Regards, Gaspar.
A JAR file itself can't have a version. But you're using Maven, and that means you can already access the Maven version:
try (InputStream inputStream = getClass().getResourceAsStream("/META-INF/maven/<groupId>/<artifactId>/pom.properties")) {
Properties properties = new Properties();
properties.load(inputStream);
// available properties:
// - artifactId=xxx
// - groupId=xxx
// - version=xxx
}
Note that this often doesn't work in unit tests (especially when run from IDEs) because the files are only added to the JAR file.
Just include a text file anywhere in your jar. Build systems of all stripes make this trivial. Then write in your code that you read out this text file with the version, and show it on screen.
In maven, gradle, etc, to include a plain text file in the jar, just put it in src/main/resources/version.txt and it gets included automatically.
To read it in java:
public class Main {
public static String getVersion() {
try (var in = Main.class.getResourceAsStream("/version.txt")) {
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
}
}
This:
Asks the classloader to load version.txt using the same systems that load .class files.
reads that inputstream fully, and turns it into a string using the UTF_8 encoding.
Uses try-with-resources because, it's a resource, you have to do that if you don't want leaks.

How to load txt file inside jar to string form

I am making a game and have text files inside of my resources folder that I use to store unit data. While running my game from my IDE, I have no problems with the code using Googles Guava to load the files to memory. However, when I tried to package it as a jar, loading text files using the Files methods causes crashes.
I have seen that input resource stream may be a solution to properly load text file data from txt files stored inside of the jar. Could someone please show me how to use the method properly to load from input resource stream directly to a String.
Thank you
String forestString = this.forestkinFileMap.get(forestKin);
URL url = Resources.getResource(forestString);
String text = null;
try {
text = Resources.toString(url, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
UnitTile unit = this.unitTileFactory.processUnitCodeComposite(forestString);
return unit;
Also, this is for the client program, but since its just a matter of loading text files inside the jar, this shouldn't be a relevant factor
The name of a resource must be an archive entry’s name.
A .jar file is actually a zip file, usually with some Java-specific zip entries in the archive. This means you can open a .jar file in any zip tool.
In Windows, you can make a copy of your .jar file, rename it so it has a .zip extension, and double-click it.
Of course, every JDK has a jar tool, so you can just use that tool to view the .jar file’s entries:
jar tf C:\path\to\program.jar | more
If you see this:
com/nbulgarides/game/data.txt
Then you have to use that path when loading a resource:
Resources.getResource("com/nbulgarides/game/data.txt")
The string argument is not a file name and you cannot just pass any file name to a getResource method. A resource path is always relative to the root of a .jar file (or, in theory, a directory that’s on the classpath, though no application is distributed to users that way). Also, resource paths always use forward slashes (/), on every platform, including Windows.
You don’t need a guava class to do this. Regular Java SE classes can do it:
String text;
try (InputStream textSource =
MyGame.class.getResourceAsStream("/com/nbulgarides/game/data.txt")) {
text = new String(textSource.readAllBytes(), StandardCharsets.UTF_8);
}

Jar is not loading resources file

I have a project with a folder "src/main/resources" where inside there is the hibernate configuration file, I load it using this line of code
HibernateUtil.class.getResource("/hibernate.cgf.xml").getPath()
From inside the IDE it is working well, but when I create the jar it doesn't file the file.
How can I load it properly in the jar file too?
Thanks
Could you please try this:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("fileName").getFile());
I cannot say for ceratin that this is the issue without knowing how exactly you use the path extracted by:
HibernateUtil.class.getResource("/hibernate.cgf.xml").getPath()
but I can tell you this:
Run from an IDE the above line of code will return:
/path/to/project/src/main/resources/hibernate.cgf.xml
which is a valid filesystem path. You can then use this path to, for example, create an instance of File class and then use that instance to read the file contents.
However the same line of code run from inside a jar file will return:
file:/path/to/jar/jar_name.jar!/hibernate.cgf.xml
which is not a valid filesystem path. If you create an instance of File class using this path and then try to read the contents of the file you'll get an exception: java.io.FileNotFoundExeption
To read the contents of the file from inside of a jar you should use method Class.getResourceAsStream(String), which will return an instance of class sun.net.www.protocol.jar.JarURLConnection.JarURLInputStream (or equivalent in non-Oracle or non-OpenJDK Java). You can then use this object to read the contents of the file. For example:
InputStream inputStream = HibernateUtil.class.getResourceAsStream("/hibernate.cgf.xml");
Scanner scanner = new Scanner(inputStream).useDelimiter("\\A");
String fileContents = scanner.hasNext() ? sscanner.next() : "";
Most likely, the file is absent from the jar you create. There's too little information in your question, but I will try a guess:
Your hibernate.cgf.xml resides in the same directory as the Java sourcefles, and you are using a build tool (be it IDE, maven, gradle or an ant script) that expects resources to be stored in a separate directory.
It's easy to check: try to unzip your jar and see if the file is there (use any tool, you can just change the extension from .jar to .zip). I think you will see the file is absent.
Then come back with a question: "how to pack my non-java resources into a jar, using XXX", where XXX will be the name of the techology you are using for building the jar.
Most probably the slash in "/hibernate.cgf.xml" is not needed, if the hibernate.cgf.xml is in the same package as you class HibernateUtil.
You can access the file actually also via the classloader using the full path. Yet you never add to it the first slash.
Here is some code demonstrating how you can access the file using different methods:
public static void main(String[] args) {
// Accessing via class
System.out.println(SimpleTests.class.getResource("hibernate.cgf.xml").getPath());
// Accessing via classloader from the current thread
String path = Thread.currentThread().getContextClassLoader()
.getResource("simple/hibernate.cgf.xml").getPath();
System.out.println(path);
// Accessing via classloader used by the current class
System.out.println(SimpleTests.class.getClassLoader().getResource("simple/hibernate.cgf.xml").getPath());
}
In the example above the package 'simple' should be replaced by the package where your hibernate.cgf.xml is. But you should never have the slash at the beginning of the package declaration.

How to read a file from a different folder than the project

I'm trying to read a txt file that is in a folder called "levels". The class where I'm using the Scanner is in src/anotherPackageName, if that's relevant. When I execute:
Scanner s = new Scanner(new File("levels/level0")); //adding .txt doesn't fix
it throws an exception. I don't want to use an absolute path, but rather relative to the project if possible. This is my folder structure:
D:\OneDrive\Folder\AnotherFolder\ProjectName
ProjectName
src
packageOne
ClassWhereImUsingScanner
OtherClasses
(...)
levels
level0
level1
(...)
So in order to access a file you could do something like this:
FileReader sourceFile = new FileReader("levels/level0.txt");
BufferedReader inStream = new BufferedReader(sourceFile);
String Line = inStream.readLine();
Then, you can use a tokenizer depending on your data and how you want to store it.
You could see this example: http://www.mkyong.com/java/how-to-read-file-from-java-bufferedreader-example/
Bear in mind that in most Java code, the end state of the project is not run from the IDE, but rather from some production system (e.g. an app or a server). In that case, your development source code structure won't be available.
There are two main ways to read text files or other resources in Java: either you can find the path to the actual file, in which case you need to deal with possibly not running out of your development source tree, or else you need to find a way to bundle the text file into your project.
Most Java projects end up getting compiled into some kind of archive, either a JAR file or a WAR file (for web applications) or something like an Android APK. In most cases you can add your own text files into the project archive. (For example, in a Maven project, if you just put your text file in the src/main/resources folder it should be included in the compiled JAR.)
However, in this case, the text file is no longer a separate file on disk, but rather a blob of data inside an archive. You could unzip the archive to get an actual File object, but that's wasteful if all you actually need is to read the bytes.
Thus, the most common way that text files like this are read is by using the existing ClassLoader mechanism, which is what is reading the .class files from disk (or from an archive, or over the network, or whatever). The ClassLoader already knows how to load bytes that are "alongside" your compiled code, so you can just make use of that.
In your case, you should be able to do something like this:
Scanner scanner = new Scanner(
getClass().getResourceAsStream("/path/to/file.txt"));
In this case, the /path/to/file.txt path is relative to the path your class was loaded from. E.g. if your class is named my.package.Foo then the actual class bytes will be in a folder (either a filesystem folder or in a JAR file or something) named my/package/Foo.class -- in this case, the path/to/file.txt and my/package/Foo.class will be relative to the same root.
See the documentation on resources for more information.
Usually the path is relative to your execution, but it also depends on your project setup on eclipse, could you send more information about you directory structure?
Based on you structure try something like this:
Scanner s = new Scanner(new File("../levels/level0"));

How to add resources into jar file

I need to add an exel file into my jar so it's portable. I know the answer is using getClass().getResource.... but i don't have a clue on how to go about using this code.
I have the exel file in the src folder with my class files, it works in netbeans but not when i open the jar file on another PC. i get filenotfound exception
here is the code i have used:
public class WindageLogic {
//....
public void GetValues() throws Exception
{
File exel=new File("src/Calculator/table1.xls");
Workbook w1; //reads from file
//reads from file
w1 = Workbook.getWorkbook(exel);
Can someone give me the code to implement which will allow me to access this file from the jar application, I've spent all weekend looking up stuff on the internet but i don't understand how i can use these getresource techniques.
thanks alot
If your excel file is a resource, then you can't use File to manipulate it but rather resources, and I believe that it is read-only -- are you sure that this is what you want to do? You could instead load a command line String that tells the program where to start looking for the file, or create a property file that tells where to first look.
Edit 1
If you are using JExcel then you can call Workbook.getWorkbook(java.io.InputStream is) and get your resource as a Stream via Class's getResourceAsStream(...) method.
e.g.,
public void GetValues() throws Exception {
Workbook w1; //reads from file
w1 = Workbook.getWorkbook(WindageLogic.class.
getResourceAsStream("/Calculator/table1.xls") );
//...
In order for the getClass().getResource() method to work the resource should be available in the classpath of the application (either packed in one of the jar files or simply on a folder on disk that is included in the classpath).
Depending on what IDE or code building tool you are using there are multiple ways of making sure it's done.
The simplest way is to put the src folder in the run classpath java -classpath src:%CLASSPATH% <your.class.name>

Categories