Inner classes not being included in jar file - java

I hava made a runnable jar file out of six classes:
Main: Contains the main method, and specified in the manifest (I included a new line)
Main$1 and Main$2: 2 anonymous inner classes that are in the main class. (Main$2 is in the main method, but I don't think that really matters.)
Form
Form$1: An anonymous inner class in Form
WrapLayout
I specify these inner classes when making the jar file, but when I look inside it (I am on mac) the inner classes are not in the jar! So when I run it, I get this:
Exception in thread "main" java.lang.NoClassDefFoundError: Main$2
at Main.main(Main.java:64)
Caused by: java.lang.ClassNotFoundException: Main$2
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 1 more
I can't figure out what's wrong. Can somebody please help?
EDIT: I figured it out! Turns out, you need an escape character (\) in front of the dollar signs for the command to recognize them.

You already found your specific answer, but here's a more general one.
As your modify your program, the set of classes with automatically generated names (e.g., Main$2) will change. Also, if you move your classes into a named package, your jar file will have to have a parallel directory structure. You don't want to have to update your makefile or build script every time this happens. Instead, you should use javac -d to specify a destination directory for the compiled class files, and then jar up this entire hierarchy.

Whilst creating or updating the jar, you can wrap inner class/ anonymous class names in single quotes to avoid the shell interpretting the $ in their names.

Related

NoClassDefFoundError when running Jar

I have this Problem. When i run my code in Intellij it works fine, but if i do an artifact and build the jar, it doesnt work. I think its caused by an extern library. Heres my output:
Exception in thread "main" java.lang.NoClassDefFoundError: com/mindfusion/scheduling/Calendar
at GUI.<init>(GUI.java:75)
at Logfiles.main(Logfiles.java:13)
Caused by: java.lang.ClassNotFoundException: com.mindfusion.scheduling.Calendar
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:168)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 2 more
I know which Class it is but i dont know how to solve the Problem. Im really just a beginner. Could you please help me and explain it simple. Thank you
Edit:
After i build the artifact with extracted Libraries this Error comes : Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
This error simply means the class file is not present in the jar.
One possible solution is you can download jd-gui which is used to look at jars. You can use this to check if the class is present.
Another solution is you can grep search the class in the jar with this simple command.
grep -l "<class-name>" <jar-name>.jar
if the class is not present in the jar file. you can add the class using jar command.
jar -cvf <jar-absolute-location> <class-path>
eg : jar -cvf GUI.jar com.mindfusion.scheduling.Calendar
The easiest way to understand this issue, it to read the Javadoc for that class. From the Javadoc:
Thrown if the Java Virtual Machine or a ClassLoader instance tries to
load in the definition of a class (as part of a normal method call or
as part of creating a new instance using the new expression) and no
definition of the class could be found.
The searched-for class definition existed when the currently executing class was compiled,
but the definition can no longer be found.
That means that NoClassDefFoundError can be thrown when that particular class is present during compile time but somehow not available during runtime. This could be due to missing JAR file, permission issues, or incorrect classpath on runtime.
Normally I see these issues when developers neglect to define the classpath for used libraries. They forget that your IDE has its own file defining the classpath (i.e. Eclipse has the .classpath file) so running the application from the IDE works fine (class is present during compile time), but after the application is compiled and the classpath is not defined in the machine hosting the application, NoClassDefFoundError is thrown (class "missing" at runtime).
My suggestion is figured out first if the classpath is correct. More times than none, this is the issue. If the classpath is correct, make sure all permissions are set correctly.

In java runtime, class not found exception

I am building the jar and I'm using this jar in one the my .war. When I run the program I am getting the below exception. But in that jar file, that particular class is there.
Error: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class com.itc.zeas.custominputformat.CustomTextInputFormat not found
at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2195)
at org.apache.hadoop.mapreduce.task.JobContextImpl.getInputFormatClass(JobContextImpl.java:174)
at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:749)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341)
at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:168)
at java.security.AccessController.doPrivileged(Native Method)
at
A quick search turned this up.
Your classpath is broken (which is a very common problem in the Java world).
Depending on how you start your application, you need to revise the argument to -cp, your Class-Path entry in MANIFEST.MF or your disk layout.
Maybe you should post more information? Which tools are you using to develop the program, which parameters when compiling, etc..

Workaround NoClassDefFoundError for wrong directory structure

I am attempting to get a custom classloader to work with loading random .class files that could be anywhere on the filesystem. I wrote my class loader to extend ClassLoader, overrode the findClass() and loadClass() methods, and read in the byte stream of the class file. The issue arises when trying to invoke ClassLoader.defineClass()
The exact error I get is:
Exception in thread "main" java.lang.NoClassDefFoundError: Test (wrong name: com/foo/bar/Test)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
I know that the problem is that the native classloading function doesn't like the fact that Test.class doesn't live in /someDir/com/foo/bar/. Is there any way I can make this work? My classloader already has code to check that the defined class conforms to a particular package. I really don't see why the native method would disallow this (other than security, which I don't need in this use case, and event then, let me shoot myself in the foot).
Native class loader, i.e. ClassLoader.defineClass1, does not know anything about directory structure. It just loads a byte array.
The error message says that the binary name passed as an argument to defineClass does not match the actual name discovered from the class data bytes. The easiest workaround is to set name=null when calling defineClass.
Note: you cannot change a package of a class by simply moving it to a different directory. The package name is embedded in class file data. You have to either recompile sources with proper package directive or modify class files bytes with bytecode instrumentation framework while loading.

Java: Two jars in project with same class.

I have a java project that is using two imported jars with the same class (com.sun.mail.imap.IMAPFolder). Is there a way to explicitly say which jar to use when importing the class? Using:
import com.sun.mail.imap.IMAPFolder;
would seem to use the class in order of build path order but this does not seem to be the case for some reason causing
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: java.lang.NoSuchMethodError: com.sun.mail.imap.IMAPFolder.idle()V
at com.woodbury.GCM.HelperGmailMonitor.doEmail(HelperGmailMonitor.java:104)
at com.woodbury.GCM.Launch.listen(Launch.java:16)
at com.woodbury.GCM.Launch.main(Launch.java:10)
... 5 more
at runtime. I am building the project in eclipse.
When a class is loaded, the first implementation that matches the requested fully qualified name that is visible to the relevant ClassLoader is what gets returned. Any other implementations with the same fully qualified name are effectively hidden to that ClassLoader.
What this means in a standard Java SE application is that the first code base (e.g. a jar) listed on the classpath with the required class, provides it, and all other code bases' implementations of the same fully qualified class are hidden.
Example:
Assume that A.jar contains the compiled class
package com.stackoverflow.example;
public class Hello {
public static String getGreeting(){
return "Hello, A!"
}
}
Assume that B.jar contains the compiled class
package com.stackoverflow.example
public class Hello {
public static String getGreeting(){
return "Hello, B!"
}
}
Note that in both of the above classes have the same fully qualified name.
Assume main class is
import com.stackoverflow.example.Hello;
public class ExampleMain {
public static void main(String[] args){
System.out.println(Hello.getGreeting());
}
}
If I were to invoke my program with
java -cp A.jar:B.jar ExampleMain
the output is: Hello, A!
If I reverse the classpath like so
java -cp B.jar:A.jar ExampleMain
the output is: Hello, B!
You cannot do what you ask just in your Java source. Java was not designed for that.
This is a bad situation which can only be handled reliably with custom class loaders, each providing one of the jars you need. Since you are asking this question in the first place this is probably not the way you should go yet since that opens up a LOT of new time consuming problems.
I would strongly suggest you find out why you have two different versions of the same jar in your classpath and rework your program so you only need one version.
Yes, there is a way to fix the issue. In my scenario, I have two classes with same name and same path and eclipse always imports the wrong one. What I have done is changing the jar order in the build path and eclipse will pick the first one in the build path.
If you are using an IDE, you can set the order of exporting the files to the class loader.
I work on eclipse and I use maven. When I install the project using maven, it produced many extra jars (which i hadnt defined in my dependencies) and there was a file org.w3c.dom.Element which was present in 2 jar files and 3rd instance of the same file was also in JRE7.
In order to make sure the correct file is picked up, all I had to do was to go to Java Build Path -> Order and Export. Select the Jar file I wanted the classloader to give more preference and move it up with the button "Up".
This is how it looks.
Please note that this image is for eclipse. But for other IDEs there would definitely be a similar way to work this out.
1) In general: Yes you can have the same class in different .jar files: you just disambiguate them with a fully qualified package name. The "Date" class (present in java.util and java.sql) is a good example.
2) If you have two DIFFERENT .jar files that have the SAME fully qualified package names ... chances are, you've got a conflict. Even if you can hack around the InvocationTargetException by playing with the class loader, you might still encounter other problems. In this case, it sounds like maybe your two .jar files have two different implementations of the JavaMail API. I don't know.
3) The safest bet is to satisfy all your program's references WITHOUT risking a conflict. I believe if you took took the "official" .jar's from Oracle's JavaMail web page, you can do this:
https://java.net/projects/javamail/pages/Home
'Hope that helps!

Issues linking external jar file, despite many trials

So I'm pretty sure I looked as well as I could before asking this question, so here goes.
I am writing a Java class for RC4 encryption, I'd like to make use of the Files class in Google Guava. I am compiling using javac on the Ubuntu command line. I am trying to link the jar file, guava-10.0.1.jar" to my class to no success.
This is a snippet from the top:
import java.util.*;
import java.io.*;
import com.google.common.io.*;
class rc4 {
private static int S[] = new int[256];
private static int kLen;
public static void main(String[] args) {
...
The line specific to what I am calling is as follows, fully in a try block:
byte plain[] = Files.toByteArray(file);
I then compile using this:
$ javac -cp FULL/FILE/PATH/guava-10.0.1.jar rc4.java
It compiles, but when I try to run java rc4 with the options I defined to access the function, I get the error:
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/common/io/Files
at rc4.main(rc4.java:58)
Caused by: java.lang.ClassNotFoundException: com.google.common.io.Files
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 1 more
I've tried a few different calls, and have checked the jar to make sure its not a jar, in a jar, in a jar etc. I then tried using a manifest file:
Manifest-Version: 1.0
Created-By: me
Main-Class: rc4
Class-path: /FULL/FILE/PATH/guava-10.0.1.jar
And then create a jar as such:
jar cvf0m rc4.jar manifest.txt rc4.class
and then run it with:
java -jar rc4.jar
to which I get the same error as above, but it's saying "rc4" can not be found instead.
So, I'm a little lost to what I'm missing. I am still a lil fresh to Java so if I'm missing some huge obviously basic necessity I sincerely apologize for the oversight, but if anyone can offer me some help in this, I would really appreciate it.
Compiling does not package referenced libraries into your jar. You must either extract the libraries into your jar file or pass in the guava classpath at runtime.
To test that your code actually works you can try manually specifying the classpath:
java -cp yourProject.jar:/path/to/guava-10.0.1.jar rc4
Note that you need to specify both project and lib on the classpath like that or rc4 which is from your project JAR will not be found! (As an aside: consider using packages in your project.)
Then if that works it is time to check your JAR manifest:
Is it located in a directory inside the JAR file called META-INF
Is it called MANIFEST.MF
Does the Class-Path contain your classpath, with proper case and so on? Note your attribute is called Class-path instead.)

Categories