Workaround NoClassDefFoundError for wrong directory structure - java

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.

Related

How to get the java path in JSP?

This is my project structure in IntelliJ IDEA:
I can use below code to get the webapp path, but I don't know how to get the java path.
${pageContext.request.contextPath}
Someone know how to get the path?
The closest information you can have is the package of a class that you can get with Class.getPackage().
public Package getPackage()
Gets the package for this class. The class loader of this class is used to find the package. If the class was loaded by the bootstrap class loader the set of packages loaded from CLASSPATH is searched to find the package of the class. Null is returned if no package object was created by the class loader of this class.
Packages have attributes for versions and specifications only if the information was defined in the manifests that accompany the classes, and if the class loader created the package instance with the attributes from the manifest.
Returns:the package of the class, or null if no package information is available from the archive or codebase.
Of course this won't be the absolute path.
PS : Not sure what you want to do with this but this should be what you want.
I think you need to know some basic rules. JSP is used from front end, thus is used for client side. Although JSP in turn transforms into executable Java Servlets and itself interacts with server(dynamic pages), but you need to understand that if the JSP has a direct source code linkage, then what security will java provide. Anyone can write the malicious code and interact with the actual source code. Thats why it uses the byte code (compiled code) and have its own directory structure.
Hope that helps

How to plug custom distances with ELKI?

I've already read the tutorial at ELKI documentation ( http://elki.dbs.ifi.lmu.de/wiki/Tutorial/DistanceFunctions ).
Unfortunately, I'm not grasping how to plug the generated .class with MiniGUI (or bash script for the provided .jar). How it can be done?
Ps: I know it sounds absolutely noob, but when I try to "type" the class name, as suggested, I get the error "The following parameters could not be processed: HammingDistance", for example.
ELKI will load classes via the standard Java Classloader. Therefore, they must be on the class path or they cannot be loaded. An example call (assuming your classes are in the bin folder) is java -cp elki.jar:bin/ de.lmu.ifi.dbs.elki.application.ELKILauncher
Parameters are interpreted as follows:
If there is a class with this name (including the package name!) it is used.
Otherwise, ELKI tries prepending the package name of the expected interface. Which enables shortcut names.
Otherwise, known classes (from the service files) are checked for aliases. For example, the Euclidean distance has an alias name of l2, Manhattan has an alias l1.
The class must have a parameterless public constructor or a inner public static class Parameterizer.
Input assistance is built as follows:
.jar files on the classpath are checked for service files in META-INF/elki/<interface>
folders on the classpath put you in development mode, where a recursive list is performed and all .class files are inspected. This is much slower, but removes the need to edit the service files. Discovered classes show up below the ones listed in the service file.
Furthermore, the package de.lmu.ifi.dbs.elki.application.internal includes classes that will inspect everything on your classpath, and will report e.g. classes that do not have a parameterless public constructor, or a inner public static class Parameterizer.

java.lang.NoClassDefFoundError: Could not initialize class org.apache.axis.utils.XMLUtils

java.lang.NoClassDefFoundError: Could not initialize class org.apache.axis.utils.XMLUtils
I am getting this error. How to avoid this exception. Please suggest me a solution.
According to Oracle:
NoClassDefFoundError is 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.
In simple language, it means "At compile-time class was there but at run-time, it failed to find/load the class
Question comes : How come my code compile?
Answer maybe because you added jars using Eclipse. But Eclipse does not actually move those jars into you classpath.It just uses those referenced jars while compilation. So your code compiles fine.
After, you move your project to tomcat, when it tries to load some class inside those 'jars', it fails to find the class,because you never moved those jars to the classpath.
Solution:
Move all the libraries(jars) into your project's /WEB-INF/lib. Now all the libraries/jars under /WEB-INF/lib will come under classpath.
You can read more on Oracle's Docs & this article
NoClassDefFoundError means, a library that was available at the compile time, is not available at the runtime.
In this case it's the jar file containing the class org.apache.axis.utils.XMLUtils. Make sure it is available in your classpath.
This exception probably means that an instance has to be created by reflection, but the corresponding class is not in the execution classpath. Check your execution classpath.
It is also possible that the creation of the new instance depends on some configuration that is wrong or absent. Check your execution configuration files.
NoClassDefFoundError means the compiler trys to load the class at compile time but the required class is not available at compile time.
So add the required jar file to your program. Can you add this jar file: axis-1.2.jar

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!

Java class not found exception

I'm trying to run a Java program and somewhere along the execution, I get a
java.lang.NoClassDefFoundError: antlr/TokenStream
exception. I'm new to java programming so don't really know what this means. I've looked through some other questions about the same issues and they didn't really help me out - either I couldn't follow the answer or it didn't apply in my case.
Any ideas?
search for antlr.jar and place it to your classpath
java.lang.NoClassDefFoundError is thrown when a particular class referenced by your program is not available in the classpath. Classpath is the list of paths/directories that the runtime searches for the classes used in the class being run.
The error message you get means that antlr/TokenStream is not available in your classpath.
To include the corresponding jar (antlr.jar) to the classpath, you ca use the -cp flag while running:
java -cp .;path_to_antlr.jar yourClass
Or
java -cp .;path_to_antlr.jar -jar yourJar.jar
It is searching for the defn of the class, which it is not finding in the classpath.
From the JavaDoc's,
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.
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.
Take from here.
You have made reference to a java class but for some reason, that class does not exist in the execution image you are running. For example, if you instantiated a new class XYZ like:
XYZ xyz = new XYZ (), but no such class existed you would get an error similar to the above. In the past, I've received this kind of error if I misspelled a reference to a class or more typically, if the class to which I was referring somehow did not get included in my jar. Check the jar or the directory in which you are doing the execution. Do you see the class to which you are making reference there? I bet it is missing.
Elliott

Categories