Java: Setting Classpath - java

I have a project due soon and everything is coming together really nicely, but java classpaths are getting seriously in the way. I'll try to explain the situation as clearly and thoroughly as I can.
So we are using Javacc to write a programming language. The javacc file compiles into several java files. The Parser.java file includes references and calls to the other generated java files. So, after generation, we compile the Parser.java file. The problem is we get many errors, including not being able to recognize the calls to the other java files as well as our own files. We asked on a classroom discussion board about our problem and the professor responded with "you need to have the class files in your classpath". Ok, great, so the question is, how do we do that? Basically we have a single directory with the generated java files and our other helper files.
So, what have we tried?
I have tried changing my .bashrc (Ubuntu) file to include the correct classpath but that doesn't work. i.e.
CLASSPATH=Home/project
(something like that I had the syntax right in the file)
I've tried on compilation executing
javac -cp . Parser.java
and
javac -cp "." Parser.java
neither works.
I have tried to edit the xml (I think xml) .classpath file in the directory of our files. Still doesn't work.
Somehow, I was able to compile Parser.java in one of the directories I have (we ended up making multiple directories with the same files in it in a futile effort to make something work) but when I try to run
java -cp . Parser.java
or
java Parser.java
It says it can not find the main and throws (I believe, its on my other computer) ClassNotFound or ClassNotDefined exception (something like that, it cannot find the main in the Parser file eventhough it IS there).
We have tried adding packages deceleration and import statements to our file, nothing seems to work.
BASICALLY: How can I successfully change the Classpath so that my java files (all in one directory and not jarred) can be compiled and run on my machine?
Thank you for your help. I greatly appreciate it.

I highly suggest you look into Ant. A simple build file can solve all these problems for you.
You don't need to edit your .bashrc or CLASSPATH.
From the command line you need to build ALL the java files together. I am not sure if JavaCC needs javacc.jar after it's generated your Lexer and Parser. But let's assume it does for some generic AST support.
javacc.jar is located in ~/javacc-5.0/lib/javacc.jar
Scenario 1: Simple directory structure, all Java files are in the root folder with no package.
root
| Parser.java
| Lexer.java
| Program.java
To compile these I need to run:
javac -cp ~/javacc-5.0/lib/javacc.jar Parser.java Lexer.java Program.java
then I can execute Program like so if Program has main
java -cp ~/javacc-5.0/lib/javacc.jar:. Program
Scenario 2: Medium directory structure, code in root but with packages.
root
| org
| myproject
| Parser.java
| Lexer.java
| Program.java
then you need to execute javac like so:
javac -cp ~/javacc-5.0/lib/javacc.jar org/myproject/Parser.java org/myproject/Lexer.java org/myproject/Program.java
and to execute
java -cp ~/javacc-5.0/lib/javacc.jar:. org.myproject.Program
Scenario 3: Complex directory structure, specific source directory with packages.
root
| src
| org
| myproject
| Parser.java
| Lexer.java
| Program.java
then you need to execute javac like so:
javac -cp ~/javacc-5.0/lib/javacc.jar -sourcepath src src/org/myproject/Parser.java src/org/myproject/Lexer.java src/org/myproject/Program.java
and to execute
java -cp ~/javacc-5.0/lib/javacc.jar:src org.myproject.Program

There is a difference between javac and java . You try to use them in wrong way. javac is a compiler which produces *.class files (in your case Parser.class). This *.class file must be then run by java.
So if I have file Parser.java
class Parser {
public static void main(String[] args) {
System.out.println("Hi");
}
}
I would go the directory where this files resides and run in shell:
javac Parser.java
Than run the compiled file
java Parser
And that's it. Note that the name of the class in java file must be same as the name of the file.

Create a Jar file of all your compiled classes. Refer to this tutorial on how to create a jar file.
Start you program with this command
java -classpath pathToJarFile com.abc.MainClass

Related

How to set the classpath correctly in java

I need to compile and run simple code using the gson library, but I can't use Maven, Gradle or the IDE.
The directory contains Main.java and gson-2.9.0.jar
javac -cp gson-2.9.0.jar Main.java works correctly and creates Main.class
But when I run java -cp ./*: Main, I get
Error: Could not find or load main class Main.
Caused by: java.lang.ClassNotFoundException: Main
I also tried the following commands:
java -cp gson-2.9.0.jar Main
java -cp gson-2.9.0.jar: Main
java -cp ./gson-2.9.0.jar:./* Main
But all these commands give the same result. I've never had to run code from the command line without Maven or IDEA before, so I think it's the classpath specification that's the problem. What am i doing wrong here?
If your main class is in a package (has a package ... declaration), you need to include the package name in the java call, e.g. java -cp ... mypackage.Main.
Additionally, the java documentation says about -cp / --class-path:
As a special convenience, a class path element that contains a base name of an asterisk (*) is considered equivalent to specifying a list of all the files in the directory with the extension .jar or .JAR.
Therefore, using * for .class files does not work; instead you have to specify the directory name. Based on your question it looks like you are using Linux, and that the .class file and the JAR are in the same directory, so the following should work in your case:
java -cp gson-2.9.0.jar:. Main
(note the . after the :, indicating to include the current directory for the classpath)

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 compiling from the command line

I am an experienced programmer, but haven't used Java in years - mostly C# - and used an IDE in the past. I'm trying to compile some code from the command line on my Mac, but can't get my test file to find my source code. I'm assuming the problem lies somewhere in the space of packages, file structure, classpaths, and import statements - but I've put a couple hours in (including hunting on Stack Overflow) and am still stuck.
Here's what I have:
Directory structure:
ProjectName
|
--src
|
--SourceClass
--test
|
--SourceClassTest
--external
|
--testng-6.8.7.jar
My SourceClass looks like this:
package ProjectName;
public class SourceClass<T>{
}
Very simple. Obviously, there will be more - but I wanted to start with making sure I had all this setup stuff correct before I actually did coding.
My test class looks like this:
package ProjectName;
import java.util.*;
import org.testng.Assert;
import org.testng.annotations.*;
public class SourceClassTest{
#Test
private void createEmptySourceClass(){
SourceClass<Object> sourceClass = new SourceClass<Object>();
Assert.assertTrue(sourceClass.isEmtpy());
}
}
The sourceClass compiles with no issue with "javac src/*.java", run from the "ProjectName" directory. I want to see this fail with an error along the lines of "SourceClass doesn't have an isEmpty() method", but instead I run javac like this from the "ProjectName" directory:
javac test/*.java -classpath external/testng-6.8.7.jar
and get this exception:
test/SourceClassTest.java:12: error: cannot find symbol
SourceClass<Object> tree = new SourceClass<Object>();
^
symbol: class SourceClass
location: class SourceClassTest
test/SourceClassTest.java:12: error: cannot find symbol
SourceClass<Object> sourceClass = new SourceClass<Object>();
^
symbol: class SourceClass
location: class SourceClassTest
2 errors
I've tried a lot of things -adding an import statement, adding a sourcepath to the javac command, compiing the sourceClass as a jar and putting it in the bin directory then adding that to the classpath, but I can't get the test to find the SourceClass symbols.
Any idea what I am missing here?
It works if you compile into a separate target directory. E.g,
mkdir target
javac -d target/ src/*.java
javac -classpath target/ test/*.java
When you do javac src/*.java, it will create the .class file in the src directory itself. By default, any classes you reference are assumed to be in the same package. So even if you add src/ to the classpath, it looks for src/ProjectName/SourceClass.class, which it does not find. When you pass the -d target/ option, it creates the proper package hierarchy, so and finds the class.
Relevant documentation from the javac official doc:
You should arrange source files in a directory tree that reflects
their package tree. For example, if you keep all your source files in
C:\workspace, the source code for com.mysoft.mypack.MyClass should be
in C:\workspace\com\mysoft\mypack\MyClass.java.
By default, the compiler puts each class file in the same directory as
its source file. You can specify a separate destination directory with
-d (see Options, below).
...
...
-d directory Set the destination directory for class files. The directory must already exist; javac will not create it. If a class is
part of a package, javac puts the class file in a subdirectory
reflecting the package name, creating directories as needed. For
example, if you specify -d C:\myclasses and the class is called
com.mypackage.MyClass, then the class file is called
C:\myclasses\com\mypackage\MyClass.class. If -d is not specified,
javac puts each class files in the same directory as the source file
from which it was generated.
Note: The directory specified by -d is not automatically added to your
user class path.
My guess is it can't find SourceClass because the file defining that class is under src, and you didn't mention that directory in your javac command line.
If I were you, I would change the file hierarchy to this:
ProjectName/src/ProjectName/SourceClass.java
ProjectName/src/ProjectName/SourceClassTest.java
ProjectName/external/testng-6.8.7.jar
Then run javac src/ProjectName/*.java -classpath external/testng-6.8.7.jar.
Or keep the file hierarchy the way it is, and run javac src/*.java test/*.java -classpath external/testng-6.8.7.jar
The accepted answer is correct, but it misses one critical point: when javac is asked to compile *.java (as opposed to foo.java, and then foo2.java ...) it treats them as a single package and accepts references between them.
That's the magic. Other languages do this less implicitly with header files.
Even after reading this post, it took me some time to figure that out, against my inherent assumption that a program running singly on files one after the other would (should) produce the same result as running that program on a group of files. My bad; the * is NOT a mere convenience, but critical.

CLASSPATH 101... (on Windows)

I'm new to working with Java from the command line and I don't get it. I read previous CLASSPATH questions but still didn't get my problem to work.
I have the following class in C:\Temp\a\b\c
package a.b.c;
public class Hello
{
public static void main(String args[])
{
System.out.println("Hello World!");
}
}
The package name is intentional.
I compiled it fine and I put the Hello.class file inside C:\Temp\a\target
Now in the command line I go to C:\Temp\ and execute the following:
java -cp .\a\target a.b.c.Hello
It complains that it cannot find the class a.b.c.Hello
Thanks in advance!!
and I put the Hello.class file inside C:\Temp\a\target
This is wrong. It should be placed in the same folder as the .java file. The source code itself is declared to be in the package a.b.c; so, the .class file should really be kept in \a\b\c folder.
Then, to execute it just do:
C:\Temp>java -cp . a.b.c.Hello
Avoid "putting" the classfiles anywhere. The following should work:
javac -d c:\temp c:\temp\a\b\c\Hello.java
# creates Hello.class in c:\temp\a\b\c
java -cp c:\temp a.b.c.Hello
To expand on BalusC's point: the classpath defines a "root". When java is looking for your classes, it will start at each root (or jar) in your class path and drill down through the directories to match the package strucutre. You still need to have you class in a directory structure that matches its package name. In your case, to execute
java -cp .\a\target a.b.c.Hello
you would move the file to
.\a\target\a\b\c\Hello.class
Years ago, I too found this baffling.
Java will try to search for a directory structure a\b\c from starting in target and as you notice, it wont work.
Move the whole directory into target and you'll be fine, it should look like:
C:\Temp\a\target\a\b\c\Hello.class
You may compile it with the -d option which tall the compiler where to put the class file.
Many project structures are like this.
C:\whatever\projectname\src
C:\whatever\projectname\classes
C:\whatever\projectname\bin
C:\whatever\projectname\lib
C:\whatever\projectname\doc
That way you can always step on your project directory and type:
javac -d classes src\*.java
Which will compile all the sources in the src directory and will place them in the classes directory.
Then execute your program:
java -cp classes a.b.c.Hello
You may optionally place required jars in lib
This works pretty fine for small programs ( < 10 src files and 2 - 3 jar libraries ) If it grows beyond that, you could probably use an IDE or ant
The good thing about following this project structure is that some IDES ( as IntellJ idea ) just pick them very easily when you create a new project. You select "Create project from existing sources" and then you can continue from there.
I like compiling and editing at the command line a lot!!

Package not found; javac

This is annoying.
I have a directory structure like this
-lib
--some jar files
-packageName
--Main.java
--SomeOtherPackage
--SomeOtherJavaClass.java
Main.java imports SomeOtherPackage. And both java files uses jars in the lib.
What I do is add the jar files independently in the CLASSPATH. And then run as:
javac packageName/Main.java
but it gives the error that Package not found SomeOtherPackage . Shouldn't it automatically realize the dependency and build SomeOtherPackage as well? What would be the javac command and the classpath for the above case?
Thanks
The normal practice is to add the package root to the classpath.
When you're already in the package root, use -cp .. E.g.
cd /path/to/all/packages
javac -cp . packageName/Main.java
If you want to include JAR files as well, use the ; (or in *nix, the :) as classpath path separator:
javac -cp .;lib/file.jar packageName/Main.java
To save the time in repeating all the typing of shell commands, use a .bat (or in *nix a .sh) file. Or just an IDE if you're already familiar with java/javac and so on.
You need to add packageName to the CLASSPATH so it can find SomeOtherPackage

Categories

Resources