SpacemanScott
SpacemanScott

Reputation: 1013

"Error: Package does not exist" ... Where does the JAR file belong?

I'm trying to import a self made package into a Java project. I got it to work once with some test class. So, when I tried to change it to an official, approved class name, the compiling stopped working. I can't explain why it worked, nor why the changes made it stop working.

This is super annoying. So, I've been digging for a few days.

I've search over a dozen posts here, plus many other sites, and cannot find an explanation of how this is supposed to be structured.

Finally I gutted everything and put together this example that should work according to everything I've searched, but it doesn't. It is a stripped down version of something that should import my own package and call a function. Minuscule code showing what I am trying to do, and what is failing.

In this minuscule example, I am building a package, as "com.company.functions" with a MyFunctions.java. All of one function inside to demonstrate it.

I do not have a classpath set up in my environment. Only a path to the JDK binaries. I do that so I can keep control and understanding at the command line level.

The "package" is located in folder JavaPackage. The folders are:

JavaPackage\
    com\
        company\
            functions\  (the MyFunctions.java is here)
    classes\

I compile it fine.

C:\JavaPackages\JavaPackage>javac -d classes -classpath classes com\company\functions\*.java

I create the JAR file fine

C:\JavaPackages\JavaPackage>jar cvf mypackage.jar  classes\com\company\functions\
added manifest
adding: classes/com/company/functions/(in = 0) (out= 0)(stored 0%)
adding: classes/com/company/functions/MyFunctions.class(in = 285) (out= 220)(deflated 22%)

I look in the JAR with 7-Zip,and everything looks fine. (I compared this 7-Zip autopsy to the package that was working, as mentioned at the beginning of this post, and the class names all line up correctly, from what I can understand. Everything looks correct)

Now, I am creating a test program. Called, for lack of a better name, Java_Test.

Java_Test\
    TestProgram\  (source files here)
    classes\

I move my jar file to Java_Test\classes

C:\JavaPackages\Java_Test>dir classes
11/11/2022  10:16 AM             1,325 mypackage.jar

I have two files in Java_Test\TestProgram: start.java and Test.java. Start is just the location of the static main, and it invokes the Test class. That's not any issue. It's the following compile failure.

I attempt to compile with

C:\JavaPackages\Java_Test>javac -d classes -cp classes  TestProgram\*.java

Which should specify that the output *.class files go into the folder "classes", and that the class path to import things is in the (same) folder "classes"

I get the following error

TestProgram\Test.java:3: error: package com.company.functions does not exist
import com.company.functions.*;
^

Well, it does exist. I can see it right there in the classes folder.

Maybe it's got something to do with the JAR name. Who knows? I can't find a good explanation of how this is supposed to work, so I even rebuilt the JAR file using the main name of the class: "functions"

So, now I have two JAR files of different names, but their contents are exactly the same. I figure the compiler should find one of them. The one it needs.

C:\JavaPackages\Java_Test>dir classes
11/11/2022  10:28 AM             1,325 functions.jar
11/11/2022  10:16 AM             1,325 mypackage.jar

However, the Java compiler still refuses to see it.

Can some please explain what is going on? This is frustrating, and making no sense. Since I come from the C/C++ world, linking to a lib is easy. Yet this package concept in Java is a confusing nightmare.

The full source files are below, not that it makes any difference, because it's the package that can't be found.

This is what is in MyFunctions.java for the package file

package com.company.functions;
public class MyFunctions {
    public int SomthingToDo() {
    int x = 1;
    return 0;
    }
}

Test program that should call the function from the package. Except fails at line 2

package TestProgram;
import com.company.functions.*; 
import java.io.*;

public class Test  {        
    public void Run() {
        m_functions = new MyFunctions();
        m_functions.SomthingToDo();
        System.out.println("Exiting");
    }
    private MyFunctions m_functions;
}

For your reading enjoyment, this is start.java, which is not significant to my issue:

package TestProgram;
public class start {
    public static void main(String args[]) {
        m_test = new Test();
        m_test.RunScanner();
    }
static private Test m_test;
}

Upvotes: 3

Views: 1950

Answers (2)

g00se
g00se

Reputation: 4292

goose@t410:/tmp/src$ find
.
./start.java
./MyFunctions.java
./classes
./Test.java
===========================================================================================
goose@t410:/tmp/src$ cat start.java 
package testprogram;

public class start {
    public static void main(String args[]) {
        m_test = new Test();
        //m_test.RunScanner();
        m_test.Run();
    }

    static private Test m_test;
}

===========================================================================================
goose@t410:/tmp/src$ head -n 1 *.java
==> MyFunctions.java <==
package com.company.functions;

==> start.java <==
package testprogram;

==> Test.java <==
package testprogram;
===========================================================================================
goose@t410:/tmp/src$ javac -d classes *.java
===========================================================================================
goose@t410:/tmp/src$ find
.
./start.java
./MyFunctions.java
./classes
./classes/testprogram
./classes/testprogram/Test.class
./classes/testprogram/start.class
./classes/com
./classes/com/company
./classes/com/company/functions
./classes/com/company/functions/MyFunctions.class
./Test.java
===========================================================================================
goose@t410:/tmp/src$ jar cvf functions.jar -C classes com/company/functions
added manifest
adding: com/company/functions/(in = 0) (out= 0)(stored 0%)
adding: com/company/functions/MyFunctions.class(in = 285) (out= 219)(deflated 23%)
goose@t410:/tmp/src$ 
===========================================================================================
goose@t410:/tmp/src$ jar cvfe mypackage.jar testprogram.start -C classes testprogram
added manifest
adding: testprogram/(in = 0) (out= 0)(stored 0%)
adding: testprogram/Test.class(in = 567) (out= 380)(deflated 32%)
adding: testprogram/start.class(in = 382) (out= 273)(deflated 28%)
===========================================================================================
goose@t410:/tmp/src$ java -cp mypackage.jar:functions.jar testprogram.start
Exiting

You can ignore any commands that are not java,javac or jar when you run them yourself. Other commands are informational. NB, you need to get your naming right. Two points: a) you'll notice I had to correct an error preventing the main class from running, and b) you'll need to use a semicolon instead of a colon for the java command on Windows. You'll notice that the whole classpath was needed for the java command. If you want to be able to use the -jar parameter, you'll need to use your own manifest. e.g.:

jar cvf functions.jar -C classes com/company/functions
================================================================================
(Creation of manifest - Unixes:)
================================================================================
echo -e "Main-Class: testprogram.start\nClass-Path: functions.jar" >manifest.txt
cat manifest.txt
================================================================================
(Creation of manifest - Windows: [untested])
================================================================================
echo  "Main-Class: testprogram.start" & echo "Class-Path: functions.jar" >manifest.txt
type manifest.txt
================================================================================
jar cvfm mypackage.jar manifest.txt -C classes testprogram
================================================================================
java -jar mypackage.jar

Upvotes: 1

Progman
Progman

Reputation: 19555

I create the JAR file fine

C:\JavaPackages\JavaPackage>jar cvf mypackage.jar  classes\com\company\functions\
added manifest
adding: classes/com/company/functions/(in = 0) (out= 0)(stored 0%)
adding: classes/com/company/functions/MyFunctions.class(in = 285) (out= 220)(deflated 22%)

It looks like it will place the files inside the JAR file in a sub directory classes/. The package path should begin at the root directory of the JAR file, not inside other directories like classes/. The ClassLoader will not be able to find the classes if you do. Create the JAR file in a way, that the .class files are in directories like com/company/functions/MyFunctions.class. Then the ClassLoader will be able to find the class com.company.functions.MyFunctions by checking the JAR file directory com/company/functions/.

I attempt to compile with

C:\JavaPackages\Java_Test>javac -d classes -cp classes  TestProgram\*.java

You have not specified the JAR file in your classpath. Java will not look randomly inside any JAR file. See How do I add jar files to the Classpath? on how to add a JAR file to the classpath. You might want to use something like

C:\JavaPackages\Java_Test>javac -d classes -cp classes\mypackage.jar  TestProgram\*.java

(with the fixed issue about the content of the JAR file above)

But you might need to add the current directory . to your classpath as well to find your other java files or classes, which are not in the JAR file.

Upvotes: 3

Related Questions