Main-Class can't be set to existing class - java

I have a build setup that requires that my classes be put into a folder in a subdirectory of my current directory. I.E., if I'm at '.', then the classes could be in './somewhere_else/'
The problem is that when I do this I can't set a value for Main-Class that can find the main class. I have no problem when I build the jar from files at '.', but all the following attempts for main class result in java.lang.NoClassDefFoundError's:
Main-Class: ClassName
Main-Class: FolderName.ClassName
Main-Class: FolderName/ClassName
What should I be using?

The classes inside your jar have to be in the same directory structure as your package structure.
So, if you want to have your class ClassName (without any package) to be the main class, it has to be in the root directory of your jar.
If you want to have the class in the directory FolderName, this same name has to be the package name, meaning the first (non-empty non-comment) line of your source file should be package FolderName;.
If your problem is only the build setup - this is not a problem, the folder-layout of your directories outside the jar does not necessarily have to be the same as the layout inside your jar. But it still helps if the folder-structure fits to the package-structure (with maybe additionally directories above).

I think you should reference Main-Class simply by the class name (without directory structure). What will help you solve this problem is what you put as the classpath. Make sure the directory of Main-Class is in the classpath.

If your ClassName resides in package FolderName, then, it should be:-
Manifest-Version: 1.0
Main-Class: FolderName.ClassName
Class-Path: <third-party>.jar <another-third-party>.jar
They are case-sensitive, by the way.

Related

How to add a class to classpath to not get import errors in Java [duplicate]

I have two classes:
MyApplication Library
The Library has already been compiled into Library.class and the source code is no longer available. I am now trying to compile MyApplication from source. MyApplication depends on the Library. The Library has a package name of org.myCompany. I tried setting my classpath to the following:
set CLASSPATH=C:\java\project\org\myCompany\Library.class;.
which produced the following javac compiler error message:
MyApplication.java:33: cannot find symbol
symbol: class Library
location: class MyApplication
Library theLibrary = new Library();
So I changed my classpath to be:
set CLASSPATH=C:\java\project\;.
which produced the exact same error message.
How do I set my Windows classpath to include the Library.class file? Should it point at the folder contains the org\myCompany subfolders? Or point directly to the class file? Or to the folder containing the class file (even though the class is in a package and belongs in a subfolder)?
I do an echo %CLASSPATH% after my set command and the classpath is being set correctly. I also made an ant build.xml file and encountered the same problem. In fact, ant -verbose confirmed that my classpath is being set correctly.
First of all: the use of the CLASSPATH environment variable is very strongly discouraged. The best thing is for you to forget that it exists. Use the -cp command line switch or similar methods to set the classpath.
Second, the classpath entries each represent a place where the classloader will start looking for .class according to the package hierarchy, i.e. it will look for the class org.myCompany.Library in a subfolder org/myCompany in any of the classpath entries.
Therefore, if
you add a classpath entry C:\java\project\
and there is a class file C:\java\project\org\myCompany\Library.class
which is actually part of a package org.myCompany (capitalization matters here!)
and your MyApplication class has an import org.myCompany.Library;
Then it really should work.
You cannot add a single class in your classpath like this. You have 3 solutions:
add this class in the path of your other compiled classes (respecting the package naming of your directories)
add the root directory of this class in your classpath (in your case "C:\java\project\")
add this single class into a jar and add this jar to the classpath
For your problem, the thrird choice is cleaner: external dependencies normally are packaged into jar files.
If your .class file isn't in jar file, point your classpath to the parent dir where package of class resides, e.g., for class org.myCompany.Library, point your CP to directory containing org/myCompany.
If your .class file included into some jar file, add full path to that jar to your classpath.
If you compiled the class files to a different directory, the classpath needs to point to where the .class file is.
set CLASSPATH=C:\java\project\;
is correct assuming that that the class file is in the same directory as the .java source file.
Is there a problem locating the Library to the same root project where is your MyApplication class
Example, if:
c:/project/org/company/MyApplication.class
Can you locate the Library class into:
C:/project/org/myCompany/Library.class
please notice, that the folders org/myCompany and org/company are located under the same folder c:/project/.
Please notices that this solution works for you if the Library Class is only used by your application.
Edited
Windows command prompt is tedious, after setting the classpath please close and re-open the Command Prompt, so it can see the new classpath's value.
For the classpath to work, you need to have a folder structure which matches the package hierarchy. So if your class is org.myCompany.Library, you must create a nested folder structure of C:\java\project\org\myCompany and place your Library class file in the myCompany folder. Then set the class path to C:\java\project\

Setting a path for the main-class in the manifest file

Say for example my manifest.txt file is saved in a parent directory of my bin directory where by classes are saved. Now, I want to be able to refer to my main-class in the manifest header so that I may create my JAR file from the parent directory directly.
So for example:
my manifest.txt is saved in the directory called project so:
-project(parent directory) contains:
bin(this contains my classes that are needed to run the application)
,src(folder)
and manifest.txt
So in a perfect world I would imagine my manifest.txt to look something like this:
Main-Class: bin/mainclass
but for some reason this doesn't work. Any ideas?
The Main-Class attribute must contain the fully qualified name of the main class. That has nothing to do with how your project is laid out. If the class is named Foo and is in package com.bar, the main class is com.bar.Foo.
If the class Foo is in the default package, which is a bad practice, then its fully qualified name is Foo. But the first thing you should do in that case is moving the class to a package.
When you execute java -jar path/to/myjar.jar, from whatever directory, java will inspect the jar, read the manifest file, look for the Main-Class, and load it from the jar.

Reference jars inside a jar

I have a jar whose content looks as shown below,
Below is my manifest file
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.7.0_06-b24 (Oracle Corporation)
Main-Class: org.sai.com.DerbyDemo
Class-Path: derby.jar derbyclient.jar derbynet.jar derbytools.jar
When i try to run the jar, it has thrown a ClassNotFoundExcception meaning it isn't referencing the jars inside the outer jar.
In the Class-Path attribute, how can I reference jars (derby.jar, etc) inside the actual jar?
You will need a custom class loader for this, have a look at One Jar.
One-JAR lets you package a Java application together with its dependency Jars into a single executable Jar file.
It has an ant task which can simplify the building of it as well.
REFERENCE (from background)
Most developers reasonably assume that putting a dependency Jar file into their own Jar file, and adding a Class-Path attribute to the META-INF/MANIFEST will do the trick:
jarname.jar
| /META-INF
| | MANIFEST.MF
| | Main-Class: com.mydomain.mypackage.Main
| | Class-Path: commons-logging.jar
| /com/mydomain/mypackage
| | Main.class
| commons-logging.jar
Unfortunately this is does not work. The Java Launcher$AppClassLoader does not know how to load classes from a Jar inside a Jar with this kind of Class-Path. Trying to use jar:file:jarname.jar!/commons-logging.jar also leads down a dead-end. This approach will only work if you install (i.e. scatter) the supporting Jar files into the directory where the jarname.jar file is installed.
You can't. From the official tutorial:
By using the Class-Path header in the manifest, you can avoid having
to specify a long -classpath flag when invoking Java to run the your
application.
Note: The Class-Path header points to classes or JAR files on the
local network, not JAR files within the JAR file or classes accessible
over internet protocols. To load classes in JAR files within a JAR
file into the class path, you must write custom code to load those
classes. For example, if MyJar.jar contains another JAR file called
MyUtils.jar, you cannot use the Class-Path header in MyJar.jar's
manifest to load classes in MyUtils.jar into the class path.
In Eclipse you have option to export executable jar.
You have an option to package all project related jars into generated jar and in this way eclipse add custom class loader which will refer to you integrated jars within new jar.
Default implementations of the classloader cannot load from a jar-within-a-jar: in order to do so, the entire 'sub-jar' would have to be loaded into memory, which defeats the random-access benefits of the jar format (reference pending - I'll make an edit once I find the documentation supporting this).
I recommend using a program such as JarSplice to bundle everything for you into one clean executable jar.
Edit: Couldn't find the source reference, but here's an un-resolved RFE off the Sun website describing this exact 'problem': http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4648386
Also, you could 'test' that your program works by placing the library jar files in a \lib sub-directory of your classes directory, then running from the command line. In other words, with the following directory structure:
classes/org/sai/com/DerbyDemo.class
classes/org/sai/com/OtherClassFiles.class
classes/lib/derby.jar
classes/lib/derbyclient.jar
From the command line, navigate to the above-mentioned 'classes' directory, and type:
java -cp .:lib/* org.sai.com.DerbyDemo
if you do not want to create a custom class loader. You can read the jar file stream. And transfer it to a File object. Then you can get the url of the File. Send it to the URLClassLoader, you can load the jar file as you want.
sample:
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("example"+ ".jar");
final File tempFile = File.createTempFile("temp", ".jar");
tempFile.deleteOnExit(); // you can delete the temp file or not
try (FileOutputStream out = new FileOutputStream(tempFile)) {
IOUtils.copy(resourceAsStream, out);
}
IOUtils.closeQuietly(resourceAsStream);
URL url = tempFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
urlClassLoader.loadClass()
...
Add the jar files to your library(if using netbeans) and modify your manifest's file classpath as follows:
Class-Path: lib/derby.jar lib/derbyclient.jar lib/derbynet.jar lib/derbytools.jar
a similar answer exists here
in eclipse, right click project, select RunAs -> Run Configuration and save your run configuration, this will be used when you next export as Runnable JARs

Class not found despite of classpath in MANIFEST

I have this jar:
/mybundle.jar/
de/mybundle/myclass.class
lib/mysql.jar
META-INF/MANIFEST.MF
With the following MANIFEST.MF
Manifest-Version: 1.0
Class-Path: lib/mysql.jar
Main-Class: de.mybundle.myclass
It all seems perfectly correct for me, but when I run
java -jar mybundle.jar
I get a NoClassDefFoundException when the class tries to instantiate one of the MySQL-Library classes.
What did I do wrong?
You can't bundle jar files in other jar files. The paths specified in the Manifest are relative to the location of the jar file you're calling, so in your case relative to the location of mybundle.jar.
You have two options:
Either put the MySQL jar in the lib directory outside of your mybundle.jar.
Create a fat jar, which contains all classes from the required jar files in addition to your own classes. This is available from within Eclipse or Maven.
If your mybundle.jar is in c:/foo, then your mysql.jar has be in c:/foo/lib. The Class-Path in the manifest is relative to the executable JAR the way you've written it.

Why classpath=/tomcat_lib/ doesn't work

HI guys,
There is an abc.jar under /tomcat_lib. I need use this in my def.java
I tired
javac -classpath /tomcat_lib/ -d
../classes def.java
but it doesn't work
But if it works if I use
javac -classpath /tomcat_lib/abc.jar
-d ....
Can anyone help explain it?
To add a jar to your classpath, you need to specify the path up to and including the .jar file.
Quoting the official Java SE 6 documentation at Oracle.com:
Each [item in your classpath] should
end with a filename or directory
depending on what you are setting the
class path to:
For a .jar or .zip file
that contains .class files, the class
path ends with the name of the .zip or
.jar file.
For .class files in an
unnamed package, the class path ends
with the directory that contains the
.class files.
For .class files in a
named package, the class path ends
with the directory that contains the
"root" package (the first package in
the full package name).
...and from the "Folders and Archive Files" section of the same documentation:
When classes are stored in a directory
(folder), like
c:\java\MyClasses\utility\myapp, then
the class path entry points to the
directory that contains the first
element of the package name. (in this
case, C:\java\MyClasses, since the
package name is utility.myapp.)
But when classes are stored in an
archive file (a .zip or .jar file) the
class path entry is the path to and
including the .zip or .jar file.

Categories

Resources