Debosmit Ray
Debosmit Ray

Reputation: 5413

Run a java program with dependencies on other classes from shell

Say, the directory structure looks like this:

src/
- A.java
- A_b.java
- A_c.java

For beginner/amateur stages, a build system like maven or gradle is not used, and very rarely is a jar even built, to package all the classes, and make them exportable.

Contents of A_b.java:

public class A_b {
    public static void writeWords() {
        System.out.println("words");
    }
}

Contents of A_c.java:

public class A_c {
    public static void writeMoreWords() {
        System.out.println("more words");
    }
}

Contents of A.java:

public class A {
    public static void main(String[] args) {
        String name = "anonymous";
        for (int i = 0; i < args.length; i++)
            if (args[i].equals("-name"))
                name = args[i+1];

        System.out.println(String.format("Hello, %s!", name));
        System.out.println("Now A_b will write some words:");
        A_b.writeWords();
        System.out.println("Now A_c will write some more words:");
        A_c.writeMoreWords();
    }
}

When I try to do:

$ ls
data    src
$ javac src/A.java 

I get an error that says:

src/A.java:11: error: cannot find symbol
        A_b.writeWords();
        ^
  symbol:   variable A_b
  location: class A
src/A.java:13: error: cannot find symbol
        A_c.writeMoreWords();
        ^
  symbol:   variable A_c
  location: class A
2 errors
                                    ^

Upvotes: 1

Views: 1551

Answers (1)

Debosmit Ray
Debosmit Ray

Reputation: 5413

The reason for this is that the compiler does not know what other files are required for A.java to compile - this is referred to as the classpath. By default, most versions of the compiler will consider all java files residing at the same level to be a part of the classpath, which is why this works:

$ cd src
$ javac A.java

but this does not

$ java src/A.java

Now, to make sure that we can get this working from the top-level, we need to ensure that the classpath is set up correctly.

One way to achieve this is to be explicit about each of the dependencies, like so:

$ javac -cp . src/A.java src/A_b.java src/A_c.java

Alternatively, this works too:

$ javac -cp . src/*.java

There's also the CLASSPATH environment variable that can be set before javac is invoked, like so:

$ CLASSPATH=$(pwd)/src javac src/A.java 

To get the *.class files created in the current working directory, we have the -d flag:

$ CLASSPATH=$(pwd)/src javac -d . src/A.java 

Then, easy enough to run it:

$ java A -name world
Hello, world!
Now A_b will write some words:
words
Now A_c will write some more words:
more words

Upvotes: 1

Related Questions