When I was working with XCode and iOS, there was a simple way to check the application's current version by reading the plist.
Is there a similar way to do this in Java?
XCode stores that version value in a resource file that is distributed with your application. In Java the equivalent would be your Manifest file, which is packed inside your JAR/WAR/EAR archive.
A Manifest file is just a metadata text file named MANIFEST.MF that stores some standard key/value pairs which are recognized by many tools and that is packaged inside a special folder named META-INF inside your java archive.
To get the Manifest file for your own JAR this question would give you some clues. Once you have your own Manifest instance then use either one of the next options to get that version value.
This way to get the Specification Version:
Manifest mf = .... // get the manifest file
String specVersion = mf.getAttribute("Specification-Version");
This way to get the Implementation Version:
Manifest mf = .... // get the manifest file
String specVersion = mf.getAttribute("Implementation-Version");
More info regarding the JAR manifests can be found here.
EDIT:
If you are getting null values for any of those properties that means that they haven't been configured in your MANIGEST.MF file. That's easy to check: unzip your JAR file (JAR files are just ZIP files with a different extension name) and go the META-INF folder to find the MANIFEST.MF file, since it's a text file you can print its contents to the console, if there is a Specification-Version or Implementation-Version attribute defined there and you are still getting null values then you might be loading a manifest file from a different JAR.
FOR THE RECORD:
To get that attributes in your Manifest file you would need to configure your build tool to do so. Maven would do it automatically (you can customize it though), with Ant you will need to use a specific Ant Task, with Eclipse you will need go through its docs (same with any other IDE).
As Alonso says, in Java, your code isn't automatically assigned a build version by the compiler. Java leaves that up to the build tool that your compiler is run by, e.g. ant or maven. If your app isn't using the manifest file, which is often the case, but using instead a version number suffix, e.g. my_app_1.2.3.jar then you could do this to get the jar name:
Class.getProtectionDomain().getCodeSource().getLocation()
If it has a GUI and the main purpose1 is 'update' use Java Web Start to deploy it.
For displaying the version to the user I would store the version number in the manifest of each Jar of the app., and show the Implementation-Versions in a JTable at run-time.
As an aside, to get better answers, put aside what you are trying to 'do' and instead name the 'feature' you are trying to achieve. The latter can be expressed as the application feature you would like to offer the user. It might be something like 'Can be expanded with plug-ins', 'Has free auto-upgrade for 24 months', 'Whiter, brighter, more suds'..
Related
I'm working on a multi project build where i need to get all .class files within a project and then load of all those through reflection by its file system location, given this project structure:
multi-project
|_ /app/
| |_ src/
|_ /notification/
| |_ /src/
|_ settings.gradle
In this multi project build my app project is dependent on notification project like this
dependencies {
implementation project(":notification")
// other dependencies
}
Although it may look like a gradle related question at this point, it's not, it's build tool agnostic.
Currently I'm working on app project, but i need to dynamically load all the classes located on notification project, i usually do this by inspecting the file location of a project, but i need to get the location of notification project from a class that's located in app project
I load all the classes of app project by using ClassLoader.getResources() in order to capture the path, but this class loader can not capture the path of the notification project
You can't. The classpath abstraction fundamentally doesn't have the "list resources" concept. It's just "get me resource X", that's all it has.
Hence, "I want to get a list of all classes so I can load them via reflection" is not possible without hackery.
Fortunately, there is an actual solution. resource-listing. Generally, by using the SPI (Service Provider Interface) system.
During compilation (during which, the compiler/build tool certainly does have a complete list of everything it is compiling), a text file is created. It contains the fully qualified class name of each and every relevant class, one such name per line. This text file is then included in the jar files. Now you can build up the process of 'give me an instance of each class of project X' just fine using just the API exposed by java's ClassLoader:
Load resource "/meta-inf/services/com.foo.YourInterface" and read it line by line.
Per line, run Class.loadClass(thatLine).getConstructor().newInstance(), cast it to com.foo.YourInterface and add it to a list.
return the list.
Voila. No 'list' directive (which doesn't exist) required. This is exactly how java itself works when finding e.g. SQL drivers, charset encoding drivers, implementations of crypto, etcetera.
The basics for how to do this depends on your buildsystem. The compilation step ("create a text file with all implementations") is build-dependent; you could write it by hand, or you can write your own build plugin, or you can use existing annotation processors that scan for an annotation and generate it automatically.
The runtime component (using the text file that is on the classpath, i.e. in the jar where the class files also are, load each and every class listed there, instantiate them, and return it to me as a list of instances) is baked into java itself: ServiceLoader.
I think i was not very clear as it was my first question, I just needed the file system path to the other project, I could find what i was looking for by using
System.getProperty("java.class.path")
It contains the path to the compiled jar of the project i need, it's not the path i needed, but i can still get the entries of that file which is as much as useful as the path itself
I have a question around addition of specific jars from a specific folder.
Scenario:
I have a lib folder which contains a number of jar files. Due to some issue, I have to give preference to a jar file over others.
Refer this issue: http://bugzilla.slf4j.org/show_bug.cgi?id=327
Now am trying to put a specific jar file to be loaded first here log4j-1.2.17.jar
One option is I simply hardcode this in my app script to make sure this jar is always added firstly in the classpath.
Problem in the approach:
Since the project is maven based, there is a chance that log4j version changes. And in that cases I am prone to same issue again, as I have to go and change the version in the script too.
Other option (for which I am searching the solution), there is some possibility like:
Example command (Expected, but this is not working though):
java -cp <path to my app>/lib/log4j*:<path to my app>/lib/* MainClass
The advantage I see here, even if log4j version changes, I will not have to change the script.
Need inputs how can I achieve approach 2?
Thanks
According to this: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/classpath.html
Class path entries can contain the basename wildcard character , which is considered equivalent to specifying a list of all the files in the directory with the extension .jar or .JAR. For example, the class path entry foo/ specifies all JAR files in the directory named foo. A classpath entry consisting simply of * expands to a list of all the jar files in the current directory.
So "*" is equivalent to all *.jar files in a directory. Maybe you could put the log4j in a lib/log directory? The following is working for me under Windows:
java -cp "lib\*;lib\log\*" MainClass
I downloaded an Open Source tool from www.openempi.org used to find duplicate patients. It is referred to as an EMPI tool (Enterprise Master Patient Index). I am a .Net programmer and not a Java programmer, but I have worked with other Java products where I receive a Jar file and run it like a Windows executable.
The zip file contained several Jar files but when I double-click on them I get Failed to load Main-Class manifest from.... After I Googled this term and reading a few posts about it, including several on this site, this seems to indicate that I should have done something different when creating the Jar file, but I didn't create the Jar file. Will I need to use Eclipse or some other tool to get past this, or is there something I'm doing wrong when try to load the Jar? Could it be a Java version issue?
The zip also contained a ./conf folder with several XML, CSV, and SQL files.
Greg
I don't think you want to execute the .jars found in that .zip file. Instead, you should try using the Application.html found after extracting from the openempi-webapp-web-versionhere.war.
Is it possible to get installed Minecraft version using Delphi?
The interesting part is that I need to read the
%appdata%\.minecraft\bin\minecraft.jar version.But without META-INF\MANIFEST.MF reading.
A Java program doesn't have a version unless it's specified in the Manifest file.
Maybe the developer left the version number in some readme text file or some other resource inside of the JAR file, which, as you know, is just a ZIP archive.
If none of those work, an alternative would be to build a catalog of Minefield versions, based on the file size. Use the System FileSize() function to get the file size of the JAR file and look it up in your catalog.
Depending on the circumstances, if the file size is not found in your catalog, you may be able to assume that it's newer than the latest version you have cataloged.
Even better than relying on the file size for you catalog would be to generate a hash. Even CRC32 would be sufficient.
I believe JAR files are actually just ZIP files, and I heard recent versions of Delphi have a unit with tools to access Zip files. I'm not familiar with the internal structure of JAR files, but if you are, and the version info you're looking for is present somewhere, you should be able to extract it this way.
Yes, it is possible. You can use this xml data provided by mojang.
For example:
<Contents>
<Key>11w47a/minecraft.jar</Key>
<LastModified>2011-11-24T13:20:06.000Z</LastModified>
<ETag>"2ad75c809570663ec561ca707983a45b"</ETag>
<Size>2242242</Size>
<Owner>...</Owner>
<StorageClass>STANDARD</StorageClass>
</Contents>
As you can see they provide version and file name in the <Key> tag. The md5 sum of the binary is stored in <ETag> tag. As long as you haven't modified your jar this should be enough to check the version.
Basically let me first explain what I am aiming to do. I have a dynamic ETL transformer app written in JAVA. Due to the dynamic nature of this app I have to be able to add plugins jars to the app in a location outside of the apps jar file.
Basically would like to have the following directory structure:
AppFolder
|- plugins/
|- configs/
|- mainApp.jar
If possible I would like to be able to use wildcards in my manifest to dynamically add jars located in the plugins folder.
Unfortunately all I have tried so far has failed. I have tried to use both relative paths and absolute paths neither have worked (with or without wildcard).
If I however include the plugins folder in the main app's jar file itself it works fine given that I don't use wildcards.
So my question is, is it actually possible to have dependencies outside of a jar or do they always have to be contained within.
The other question is regarding the usage of wildcards. i have looked at [the java documentation] (http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html) to no prevail unfortunately.
some examples of what I have tried so far:
../plugins/*
../plugins/plugin.jar
/abolute/path/to/plugins/*
/abolute/path/to/plugins/plugin.jar
and unfortunately none of them have done the trick so any help would be very much appreciated...
Yes you can have dependencies outside the jar. But wildcards are not supported for specify dependant jars.
The jars need to be explicitly specified in your manifest, and the location needs to be relative to where the application is run from
A better option for you may be to use the Extension Mechanism
java -Djava.ext.dirs=/abolute/path/to/plugins/ ......
If you have control of the code you could always add a JarClassLoader and load the jars dynamically.
http://java.sun.com/docs/books/tutorial/deployment/jar/jarclassloader.html