Windows 10 1803 64-bit, Java JRE 8. No JDK installed.
I have a .jar in a folder:
c:\users\myuser\KickAssembler\KickAss.jar
Under System environment variables I have the CLASSPATH as:
c:\users\myuser\KickAssembler\
At a command prompt the CLASSPATH is set (checked with ECHO).
At a prompt when I try:
java -jar KickAss.jar
It returns:
Error: Unable to access jarfile KickAss.jar
If I CD into the directory first, then run it, it works fine. So it looks like CLASSPATH is not being used somehow. I have added the location into the standard Windows PATH also, still doesn't work.
Different combinations of casing for the filename doesn't work. Windows is set to show hidden files. It can't be a permissions issue because it works when I change into the directory first.
Anything else I can try?
CLASSPATH is used to define the path from which Java will load classes. CLASSPATH can contain folders and JAR files, such as: C:\mybin;c:\myjars\some.jar This classpath would load any fully qualified class file residing in or beneath c:\mybin and any fully qualified class within c:\myjars\some.jar. CLASSPATH will not allow JAVA to find your JAR file as you are expecting when using the -jar switch, it does not search for any JAR file along the classpath, it will only look in the ones explicitly stated in the CLASSPATH and then only for class files within them. Note, fully qualified means package + class, such as: com.myorg.somepackage.someclass, not just someclass.
As you observed, if you are in the folder where kickass.jar resides your command line works as the JAR file is present. If you fully reference the JAR file while executing the command from another folder the command line should work as well.
See https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html for more detail on how CLASSPATH works. It is important to have a solid understanding of CLASSPATH when using JAVA.
public class a {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
For the above code, I can run it by javac a.java, and then java a.
But if I add a package for it:
package hello;
public class a {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
I need add the classpath -cp in order to run it: java -cp ../ hello.a
Why I do not need to set the classpath in the first situation? When do I need to add -cp?
To answer your question
When should I set my classpath
Always, as you work on more complex projects you will find that your classpath will almost always need to be set. This will either be done manually like you have done with -cp command or by your IDE.
To answer your second question
Why I do not need to set the classpath in the first situation
I first need to explain a little bit about classpaths. In short classpath exist to tell the VM where to look for your files. In the first situation since you didnt have a package the default location was used to find your class so no classpath was needed. However when you complicated things and added a package at this point a classpath is needed
The classpath is where java (the program) looks for classes. The default contains a bunch of system-wide things (for the JDK), and then also the current directory: ..
Without the package line, your class was in the "default package," which is basically no package. This means its full name is a (more or less), and java will look for it in a file called $CP_ELEM/a.class for each element CP_ELEM in the classpath. In the default case, that amounts to ./a.class, which is fine because that file exists.
With the package line, your class is in the hello package, and its full name is hello.a. That means that java will look for it in $CP_ELEM/hello/a.class, which amounts to ./hello/a.class -- which doesn't exist. But if the directory you're in happens to be called "hello", then java -cp .. hello.a, which amounts to looking in ../hello/a.class, will work.
Classpath is like telling the system where to find my classes:
If you don't have a classpath the java will try to load the class
from the default directory (Probably where you're running the command at).
Now let's say you put your compiled classes in folder "bin" and sources in "src" folder
To tell the system to load the classes from "bin" folder you have to give him the following parameter:
-cp bin;
Also i see you don't understand the packaging system in java so here's fast explain:
Packaging is like you the directory of your class for example:
If you set the class's package to package a; and your classpath directory is set to "bin"
You have to create folder called "a" in "bin" folder, and then move the compiled class there, do the same for the source file, but in "src" folder
Just saying you could use eclipse which is located at : http://www.eclipse.org
If this didn't help you, Then take a look at this: https://www3.ntu.edu.sg/home/ehchua/programming/java/J9c_PackageClasspath.html
I just noticed that for compiling I need to specify the exact path from my current location for the java source files that needs to be compiled, but to run the class file, all I need is the class qualified name.
Does the java command recursively look inside all the folders in my current directory to find the class and execute it?
if so why doesn't the javac work similarly but expects to have the absolute path?
From my project folder location,
javac -cp ".:/Users/page/.m2/repository/org/slf4j/slf4j-api/1.7.5/slf4j-api-1.7.5.jar:target/classes" src/main/java/app/Assignment04.java
java -cp ".:/Users/page/.m2/repository/org/slf4j/slf4j-api/1.7.5/slf4j-api-1.7.5.jar:target/classes" app.Assignment04
EDIT:
when I explicitly mentioned path like this;
java -cp ".:/Users/page/.m2/repository/org/slf4j/slf4j-api/1.7.5/slf4j-api-1.7.5.jar:src/main/java/com/scg/util/*:src/main/java/com/scg/domain/*:src/main/java/app/*" app.Assignment04
I get
Error: Could not find or load main class app.Assignment04
although I give src/main/java/app/ in my classpath
-cp ".:/Users/page/.m2/repository/org/slf4j/slf4j-api/1.7.5/slf4j-api-1.7.5.jar:target/classes"
is the important bit. When compiling the classpath argument is not considered for the source files themselves (only to resolve dependencies).
When running with java the named class is sought on the classpath, which includes the target directory explicitly as target/classes. Thus that location is also used to find the class in question.
I have a file which imports org.w3c.dom.Document. Compiling and running is fine, but I don't understand how it knows where to find this package and I'm just curious how it works. I used the locate command to try and find org.w3c.dom but I get nothing. Where are these packages located? It seems to me that the right place to look would the CLASSPATH environment variable since my search results seem to be suggesting that. Is this correct? In any case, I don't know how to find out what my CLASSPATH variable is. It doesn't seem to be an environment variable that my shell knows about.
That would be part of the core libraries (rt.jar), so it'd be wherever you installed the java JRE; specifically under $JAVA_HOME/jre/lib
You can look inside the .jar files using the jar command. To see the class you mention, you can do:
jar tvf rt.jar
This lists all the classes in that jar.
Note that this location is automatically searched by the JVM - it's not needed nor included in the CLASS_PATH environment variable. (You could add it, but it would simply be redundant)
Edit for clarity:
The JVM includes <Where_you_installed_jdk>/jre/lib and <Where_you_installed_jdk>/jre/lib/ext by default. Anything else has to be explicitly added by you via either passing it to java directly via the -cp option or adding it to the CLASS_PATH environment variable.
The relavent documentation can be found at: http://download.oracle.com/javase/6/docs/technotes/tools/findingclasses.html
The JVM finds classes using classpath settings where alll paths to required packages are set. The classpath could be set with a number of ways. The first mentioned by you is CLASSPATH environment variable. It is optional and can be unset. The second way is an explicit option "-cp" for "java" executable.
Also some JRE runtime jars are added to classpath by default implicitly so you don't need to search and add standard packages by yourself (particulary the one you mentioned in your question).
try compiling messconvener.java like this from its own directory
javac -d ..\..\. -cp ..\..\. messconvener.java
-d - creates directory structure for your package
-cp - provides class path for user file, where it can find user defined classes
I was just reading this line:
The first thing the format() method does is load a Velocity template from the classpath named output.vm
Please explain what was meant by classpath in this context, and how I should set the classpath.
When programming in Java, you make other classes available to the class you are writing by putting something like this at the top of your source file:
import org.javaguy.coolframework.MyClass;
Or sometimes you 'bulk import' stuff by saying:
import org.javaguy.coolframework.*;
So later in your program when you say:
MyClass mine = new MyClass();
The Java Virtual Machine will know where to find your compiled class.
It would be impractical to have the VM look through every folder on your machine, so you have to provide the VM a list of places to look. This is done by putting folder and jar files on your classpath.
Before we talk about how the classpath is set, let's talk about .class files, packages, and .jar files.
First, let's suppose that MyClass is something you built as part of your project, and it is in a directory in your project called output. The .class file would be at output/org/javaguy/coolframework/MyClass.class (along with every other file in that package). In order to get to that file, your path would simply need to contain the folder 'output', not the whole package structure, since your import statement provides all that information to the VM.
Now let's suppose that you bundle CoolFramework up into a .jar file, and put that CoolFramework.jar into a lib directory in your project. You would now need to put lib/CoolFramework.jar into your classpath. The VM will look inside the jar file for the org/javaguy/coolframework part, and find your class.
So, classpaths contain:
JAR files, and
Paths to the top of package hierarchies.
How do you set your classpath?
The first way everyone seems to learn is with environment variables. On a unix machine, you can say something like:
export CLASSPATH=/home/myaccount/myproject/lib/CoolFramework.jar:/home/myaccount/myproject/output/
On a Windows machine you have to go to your environment settings and either add or modify the value that is already there.
The second way is to use the -cp parameter when starting Java, like this:
java -cp "/home/myaccount/myproject/lib/CoolFramework.jar:/home/myaccount/myproject/output/" MyMainClass
A variant of this is the third way which is often done with a .sh or .bat file that calculates the classpath and passes it to Java via the -cp parameter.
There is a "gotcha" with all of the above. On most systems (Linux, Mac OS, UNIX, etc) the colon character (':') is the classpath separator. In windowsm the separator is the semicolon (';')
So what's the best way to do it?
Setting stuff globally via environment variables is bad, generally for the same kinds of reasons that global variables are bad. You change the CLASSPATH environment variable so one program works, and you end up breaking another program.
The -cp is the way to go. I generally make sure my CLASSPATH environment variable is an empty string where I develop, whenever possible, so that I avoid global classpath issues (some tools aren't happy when the global classpath is empty though - I know of two common, mega-thousand dollar licensed J2EE and Java servers that have this kind of issue with their command-line tools).
Think of it as Java's answer to the PATH environment variable - OSes search for EXEs on the PATH, Java searches for classes and packages on the classpath.
The classpath is one of the fundamental concepts in the Java world and it's often misunderstood or not understood at all by java programmes, especially beginners.
Simply put, the classpath is just a set of paths where the java compiler and the JVM must find needed classes to compile or execute other classes.
Let's start with an example, suppose we have a Main.java file thats under C:\Users\HP\Desktop\org\example,
package org.example;
public class Main {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
And Now, suppose we are under C:\ directory and we want to compile our class, Its easy right, just run:
javac .\Users\HP\Desktop\org\example\Main.java
Now for the hard question, we are in the same folder C:\ and we want to run the compiled class.
Despite of what you might think of to be the answer, the right one is:
java -cp .\Users\HP\Desktop org.example.Main
I'll explain why, first of all, the name of the class that we want ro tun is org.exmaple.Main not Main, or Main.class or .\users\hp\desktop\org\example\Main.class ! This is how things works with classes declared under packages.
Now, we provided the name of the class to the JVM (java command in this case), But how it (JVM) will know where to find the .class file for the Main class? Thats where the classpath comes into picture. Using -cp flag (shortcut for -classpath), we tell the JVM that our Main.class file will be located at C:\users\hp\Desktop.. In fact, not really, we tell it to just go to the Desktop directory, and, because of the name of the class org.example.Main, the JVM is smart and it will go from Desktop to org directory, and from org to example directory, searching for Main.class file, and it will find it and it will kill it, I mean, it will run it :D .
Now lets suppose that inside the Main class we want to work with another class named org.apache.commons.lang3.StringUtils and the latter is located in a jar file named commons-lang3-3.10.jar thats inside C:\Users\HP\Downloads. So Main.java will look like this now:
package org.example;
import org.apache.commons.lang3.StringUtils;
public class Main {
public static void main(String[] args) {
System.out.println("Hello world");
System.out.println(StringUtils.equals("java", "java")); //true
}
}
How to compile the Main.java if we are always inside C:\ ? The answer is:
javac -cp .\Users\HP\Downloads\commons-lang3-3.10.jar .\Users\HP\Desktop\org\example\Main.java
.\Users\HP\Desktop\org\example\Main.java is because our .java file is there in the filesystem.
-cp .\Users\HP\Downloads\commons-lang3-3.10.jar is because the java compiler (javac in this case) need to know the location of the class org.apache.commons.lang3.StringUtils, so we provided the path of the jar file, and the compiler will then go inside the jar file and try to find a file StringUtils.class inside a directory org\apache\commons\lang3.
And if we want to run the Main.class file, we will execute:
java -cp ".\Users\HP\Desktop\;.\Users\HP\Downloads\commons-lang3-3.10.jar" org.example.Main
org.example.Main is the name of the class.
".\Users\HP\Desktop\;.\Users\HP\Downloads\commons-lang3-3.10.jar" are the paths (separated by ; in Windows) to the Main and StringUtils classes.
The classpath is the path where the Java Virtual Machine look for user-defined classes, packages and resources in Java programs.
In this context, the format() method load a template file from this path.
The classpath in this context is exactly what it is in the general context: anywhere the VM knows it can find classes to be loaded, and resources as well (such as output.vm in your case).
I'd understand Velocity expects to find a file named output.vm anywhere in "no package". This can be a JAR, regular folder, ... The root of any of the locations in the application's classpath.
Setting the CLASSPATH System Variable
To display the current CLASSPATH variable, use these commands in Windows and UNIX (Bourne shell):
In Windows: C:\> set CLASSPATH
In UNIX: % echo $CLASSPATH
To delete the current contents of the CLASSPATH variable, use these commands:
In Windows: C:\> set CLASSPATH=
In UNIX: % unset CLASSPATH; export CLASSPATH
To set the CLASSPATH variable, use these commands (for example):
In Windows: C:\> set CLASSPATH=C:\users\george\java\classes
In UNIX: % CLASSPATH=/home/george/java/classes; export CLASSPATH
Classpath is an environment variable of system. The setting of this variable is used to provide the root of any package hierarchy to java compiler.
CLASSPATH is an environment variable (i.e., global variables of the operating system available to all the processes) needed for the Java compiler and runtime to locate the Java packages used in a Java program. (Why not call PACKAGEPATH?) This is similar to another environment variable PATH, which is used by the CMD shell to find the executable programs.
CLASSPATH can be set in one of the following ways:
CLASSPATH can be set permanently in the environment: In Windows, choose control panel ⇒ System ⇒ Advanced ⇒ Environment Variables ⇒ choose "System Variables" (for all the users) or "User Variables" (only the currently login user) ⇒ choose "Edit" (if CLASSPATH already exists) or "New" ⇒ Enter "CLASSPATH" as the variable name ⇒ Enter the required directories and JAR files (separated by semicolons) as the value (e.g., ".;c:\javaproject\classes;d:\tomcat\lib\servlet-api.jar"). Take note that you need to include the current working directory (denoted by '.') in the CLASSPATH.
To check the current setting of the CLASSPATH, issue the following command:
> SET CLASSPATH
CLASSPATH can be set temporarily for that particular CMD shell session by issuing the following command:
> SET CLASSPATH=.;c:\javaproject\classes;d:\tomcat\lib\servlet-api.jar
Instead of using the CLASSPATH environment variable, you can also use the command-line option -classpath or -cp of the javac and java commands, for example,
> java –classpath c:\javaproject\classes com.abc.project1.subproject2.MyClass3
For linux users, and to sum up and add to what others have said here, you should know the following:
$CLASSPATH is what Java uses to look through multiple directories to find all the different classes it needs for your script (unless you explicitly tell it otherwise with the -cp override). Using -cp requires that you keep track of all the directories manually and copy-paste that line every time you run the program (not preferable IMO).
The colon (":") character separates the different directories. There is only one $CLASSPATH and it has all the directories in it. So, when you run "export CLASSPATH=...." you want to include the current value "$CLASSPATH" in order to append to it. For example:
export CLASSPATH=.
export CLASSPATH=$CLASSPATH:/usr/share/java/mysql-connector-java-5.1.12.jar
In the first line above, you start CLASSPATH out with just a simple 'dot' which is the path to your current working directory. With that, whenever you run java it will look in the current working directory (the one you're in) for classes. In the second line above, $CLASSPATH grabs the value that you previously entered (.) and appends the path to a mysql dirver. Now, java will look for the driver AND for your classes.
echo $CLASSPATH
is super handy, and what it returns should read like a colon-separated list of all the directories, and .jar files, you want java looking in for the classes it needs.
Tomcat does not use CLASSPATH. Read what to do about that here: https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html
Static member of a class can be called directly without creating object instance.
Since the main method is static Java virtual Machine can call it without creating any instance of a class which contains the main method, which is start point of program.