Specifying classpath for a jar - java

I am trying to configure the classpath of a JAR so that my ResourceBundle can pick up property files from it.
If I run it from the .class files and specify the -cp flag it works fine, and System.err.println(System.getProperty("java.class.path")); will print the path specified in the -cp flag.
If I try and create a jar file for it, System.err.println(System.getProperty("java.class.path")); always prints the path of the jar file, and the property files aren't picked up.
It seems if you are running it as a jar file you can't specify the -cp flag (which was what I was hoping, as it's common to switch which property files are being used). I've tried specifying it in the jar manifest instead, but it's still not working.
Here is the code and manifest from a test jar that doesn't seem to work:
public final class Test {
public static void main(final String[] args) {
System.err.println(System.getProperty("java.class.path"));
}
}
Manifest-Version: 1.0
Created-By: 1.6.0_20 (Sun Microsystems Inc.)
Main-Class: Test
Class-Path: /home/ajanuary/Projects/test/
edit
The original path was rather meaningless so I changed it. I want to point to a directory which the ResourceBundle can find the property files in.

If you use -jar, -cp is ignored:
-jar
Execute a program encapsulated in a JAR file. The first argument is the
name of a JAR file instead of a
startup class name. In order for this
option to work, the manifest of the
JAR file must contain a line of the
form Main-Class: classname. Here,
classname identifies the class having
the public static void main(String[]
args) method that serves as your
application's starting point. See the
Jar tool reference page and the Jar
trail of the Java Tutorial for
information about working with Jar
files and Jar-file manifests. When you
use this option, the JAR file is the
source of all user classes, and other
user class path settings are ignored.
Source: java - the Java application launcher

I would instead read a property in my Java application (that property could indicate from where resources should be loaded).
Example of how to execute the application would then be:
java -Dkey=value -jar application.jar

You can't use classpath wildcards in the manifest.
Take a look at Setting the classpath for more information on how classpath works:
class path wildcards are not honored
in the Class-Path jar-manifest header.

Yes, and for the shell, ~ means $HOME, but for java, it doesn't mean anything.

The problem was that I also had an index file. If you have an index file, the Class-Path will be ignored.

Related

jpackage how do you pass in the insatllation directory itself as an argument to the jar file?

my final jar file requires an argument to be passed to it at runtime. The argument is the installation directory itself. I can't modify jar file or any java code, only the argument to be passed to it in jpackage.
If it were located in C:\path\to\jar\ I would call the jar file through java -jar jarFile.jar "C:\path\to\jar", but since I'm making the msi installer with the --win-dir-chooser , the installation directory could be anything, so I don't know what to pass in --arguments.
My current solution involves a "middle man" jar file as the --main-jar. The .exe file calls the "middle man" jar which in turn calls the final jar with the needed argument(by finding the current directory through java code). However, this is seems daftly unnecessary and I would like to find a replacement for this.
Could anyone help me out? Is there a better way to do this? Any suggestions would be helpful.
Don't rely on the current directory as this could be wrong if you use shortcuts. Normally you would work out the installation directory of jpackage using System.getProperty("jpackage.app-path").
However as you are unable to change the code of the jar you can achieve the same result by defining fixed command line argument to your jar's main class by using --arguments parameter or arguments property in a launcher which references a special jpackage variable $APPDIR.
The value of $APPDIR variable is expanded at launch-time so will be filled in by the actual installation directory path to the app folder. There are three ways to hardwire the arguments to a generated EXE:
Command line flag - note that on Linux you must escape the values or the shell will fill in $APPDIR from its own environment variable:
jpackage ... --arguments $APPDIR\relpathto\yourjar.jar
With a configfile of parameters use jpackage #configfile with file configfile containing:
--arguments $APPDIR\\relpathto\\yourjar.jar
With a launcher properties file use jpackage ... --add-launcher yourappname=yourappname.properties with file yourappname.properties containing:
arguments=$APPDIR\\relpathto\\yourjar.jar
After installation your launcher definitions config RELEASEDIR\app\yourappname.cfg should contain something like:
[ArgOptions]
arguments=$APPDIR\relpathto\yourjar.jar
For above to work the jar must be packaged somewhere into the release structure such as with jpackage --input somedir and that you use the new main class or --main-jar to replace your wrapper Main - check inside the jars MANIFEST.MF.
Note that running the EXE with any command line args will replace the hardwired argument.

java load order of jars and other files in a folder

I have a file and a jar in same folder.
a.jar
env.properties
a.jar also contains env.properties file with different values.
When I use java -cp path_to_folder/* ClassName then java is reading the a.jar -> env.properties file content. When I use java -cp .:path_to_folder/* ClassName then java is reading env.properties file's content.
Can we determine the load order of files and jars used by java?
There are two things going on here: shell pathname expansion (aka "globbing") and then the java commands interpretation of the arguments that it sees.
Example 1:
java -cp path_to_folder/* ClassName
The shell turns that into
java -cp path_to_folder/a.jar path_to_folder/env.properties ClassName
Then java treats the path_to_folder/env.properties as if it was the class name, and fails.
Example 2:
java -cp .:path_to_folder/* ClassName
This one is a bit more tricky. The problem is that the shell tries to expand .:path_to_folder/* by interpreting .:path_to_folder/ as the name of a directory. (It doesn't know that it represents a colon-separated path.) That expansion fails, and what java sees is this:
java -cp .:path_to_folder/* ClassName
But java interprets a wildcard in the classpath as matching only JAR files. See Setting the Classpath
So the above is equivalent to this:
java -cp .:path_to_folder/a.jar ClassName
and the properties file is not on the effective classpath.
Solution:
If you want both the JAR and properties file on the classpath, you need to do this:
java -cp .:path_to_folder/a.jar:path_to_folder ClassName
Now both the JAR file and the folder containing the properties file are on the effective classpath, and the application will be able to read the properties file as a resource using the resource path /env.properties. (It should also read the JAR file as a resource as /a.jar.)
This is not a direct answer to your question but may solve your task:
You could try to read the properties in two steps:
Read your jar-internal env.properties as you do already from classpath.
Read your jar-external env.properties (which you should place then outside your classpath) via filesystem access:
Properties properties = new Properties();
properties.load(new FileInputStream(new File("./env.properties")));
And then decide (dependent of which is available) which properties to use.
java -cp path_to_folder/* ClassName
Yes, because this means the 'raw' env file (the one not in the jar) is not even on the classpath. The above line of code doesn't work at all except on windows (it should be put on quotes on all other platforms): That star needs to arrive unmolested by the shell as an argument straight to the java executable, and this means: all jars in this directory. Not the directory itself.
Hence, yes, of course, this means only the env file in the jar is on the classpath. By definition.
java -cp .:path_to_folder/* ClassName
Yes, now both are on the classpath. I think it then goes in order; ./env.properties works, so that wins, as . is the first entry in the classpath. Yeah, path_to_folder/foo.jar!/env.properties would also work, but classpath scanning stops on a hit, unless you are using a ClassLoader's findResources option (which would find both of them).

What does "Exception in thread \"main\" java.lang.NoClassDefFoundError" mean when executing java .class file?

Java and Gradle beginner's question.
I made a project directory for java and gradle test:
The directory hierarchy :
HelloWorld.java:
package foo.bar;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world");
}
}
build.gradle:
apply plugin:'java'
Then,gradle build this project and generated what i need.
As you see above, my problem is why doesn't this execute correctly? Even through I cd to .class path.
======================================================================
While, if I remove package foo.bar; in HelloWorld.java, and repeat gradle commands and execute at he.bak directory then the error remained the same.
But when I cd to the directory where HelloWorld.java placed. everything goes OK!Why? something related with CLASSPATH environment variables or other causes?
////////////////////////////////////////////////////////////////////
UPDATE
////////////////////////////////////////////////////////////////////
Thought you guys' warm replies, I know that I should combine the CLASSPATH and the period-separated executable .class file to figure out what's going on when executing java class file.
I experiment my thought resulting in 2 point to this question:
The -cp option path parameter A/B plus the executable file c.d.e.class finally form the A/B/c.d.e.class full path where the class is actually located.
If I specify the package in source code file with package d,I must split the full path in the form of java -cp A/B/c/d e.class. split in other ways all will result in errors.
something I am not sure here is :
When I specify my package path in my source code file, It determined the only classpath when executing corresponding executable, right?
If it is the truth, How does a project with lots of package and sources files work?
What's the root principle?
When in build/classes/main try java foo.bar.HelloWorld instead of java HelloWorld
The reason you need to specify foo.bar.HelloWorld is because you specified package foo.bar;. This tells java that the class should be in foo/bar/HelloWorld and the fully qualified name for HelloWorld is foo.bar.HelloWorld. If you want to execute the class from a different working directory however, you can specify the classpath explicitly using the -cp option, e.g., java -cp c:\myproject\build\classes\main foo.bar.HelloWorld.
By the way, the classpath default is the current working directory (i.e., .) but java -cp c:\myproject\build\classes\main foo.bar.HelloWorld will NOT have the classpath set to the current working directory if it is explicitly set using the -cp option. If you want to include the current working directory but explicitly set it, or even add more directories, you can chain them using semicolons like this: java -cp .;c:\myproject\build\classes\main foo.bar.HelloWorld. So this will include both the current working directory and the directory I specified.

Java 'ext' directory versus -Xbootclasspath/p:

I want to make use of the JSR166 facilities in Java 6. So I've downloaded the jar.
I'd like to make this process (relatively) painless. I was perplexed to discover that adding it to the ext directory in my Mac's JDK/JRE (or to /Library/Java/extensions) did not work.
Only -Xbootclasspath did the trick.
Why is this? Are exts somehow defined more narrowly?
Installing JAR's into the extension directory makes them just as available to use as including them via the -Xbootclasspath option. In terms of load order you have this:
Bootstrap class path. This is controlled by the JVM provider, and
can be overridden with the (non-standard) -Xbootclasspath command
line option.
Extension folder - JAR's in this folder are loaded and scoped with
the same availability as bootstrap classes.
User classes - User classes are loaded from the sources defined via
the class path property. This is by default specified by the
CLASSPATH environment variable but can be overridden by the
standard -cp command line option.
Any classes found in the bootstrap class path or loaded as an extension should be immediately available to your program.
You can easily verify this on your Mac. Compile the following:
public class Test {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
And in a command console:
javac Test.java
jar cvf test.jar Test.class
cp test.jar /Library/Java/Extensions
rm Test.class test.jar
java Test
And of course the result will be 'Hello World' printed to your console.
Check to make sure you were invoking the right class from your JAR, and that it was actually placed in the right extension folder.

How can I create a Class file and JAR file without main function?

How can I create the class file and jar file for this coding, when I compile this program its not working because there is no main function in the program. And also I am trying in command prompt but I don't know how to set the classpath? please help me
My Coding is here
public class NewLogFields implements ILogNotify
{
public void onLog(Level level, String comment, IMediaStream stream, String category,String event, int status, String context) {
if (category.equals(WMSLoggerIDs.CAT_session) && event.equals(WMSLoggerIDs.EVT_destroy))
{
Long csBytes = (Long)WMSLoggerFactory.getGlobalLogValue(WMSLogger IDs.FD_cs_bytes);
Long scBytes = (Long)WMSLoggerFactory.getGlobalLogValue(WMSLogger IDs.FD_sc_bytes);
System.out.println("disconnect: csBytes:"+csBytes+" scBytes:"+scBytes);
}
}
}
Once you compiled the coding in wowza media Serever the jar file is automatically created in the library folder,see your Installation Library folder.Still you have problem Gothrough this link Wowza Quick Guide
What do you want to do?
Create a class and an jar file out of this Java code so that you can use this in another Java program?
Then you have to compile it:
java NewLogFields.java
Looks like you are unable to compile it at all. This could be because the interface ILogNotify (or the jar that contains this) is not in the classpath.
You can include the path/jar containing this interface in the classpath by using:
javac -cp .;path_to_jar_or_class NewLogFields.java
where path_to_jar_or_class is the path to the folder or jar file that contains ILogNotify.
For example, this may be something like ./logNotify.jar or ./log/
You can set use switch -cp or -classpath with javac command.
for example javac -cp path and name of jat file or class file yourjavafile.java
create the class file using the compiler: javac NewLogFileds.java
create the jar file using the jar command: jar cvf stuff.jar NewLogFileds.class
You are correct that the program needs a main() function in order to run.
add:
public static void main(String args[]) {
// code here
}
With that you could run the code with or without the jar:
java NewLogFields
or
java -cp stuff.jar NewLogFields
There are ways of creating a MANIFEST file that tells java which class to run from the jar making the last line more simple.
The link that you provided tells you how to do it:
Compile your class in the normal way.
Create a JAR file containing your class in the normal way.
Copy the JAR file into the wonza installation's lib as described in the javadoc.
Edit the startup script to add the -Dcom.wowza.wms.logging.LogNotify=... option to JAVA_OPTS ... as described in the javadoc.
The "full-path-to-your-ILogNotify-class" is actually supposed to be the fully qualified class name of your class; it is obvious from the examples.
Edit WowzaMediaServerPro-Service.conf and log4j.properties as described in the javadoc.
Restart the server.
If you put your JAR file in the directory like the instructions tell you to, you won't need to modify the classpath by changing -cp argument.
Your class doesn't need a main method because it is not a free-standing application. Rather, it is a "plugin" class that gets dynamically loaded and instantiated by the Wowza core as required. The "-D..." option and the config file change tell the Wonza core which class to try to load.

Categories

Resources