wood burning stoves 2.0*
The moose likes Servlets and the fly likes Strange NoClassDefFoundError with obfuscated build Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login

Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » Servlets
Bookmark "Strange NoClassDefFoundError with obfuscated build " Watch "Strange NoClassDefFoundError with obfuscated build " New topic

Strange NoClassDefFoundError with obfuscated build

Brian Daniel

Joined: Oct 10, 2001
Posts: 3
I run a DashO obfuscated web application in Tomcat 4.1.18 on Win2K, and I get the following:
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
at au.a(DashoA8050)
at com.project.servlet.LoginServlet.processRequest(DashoA8050)
at com.project.servlet.LoginServlet.doPost(DashoA8050)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
I run the same web application, but without the obfuscation, and no problems.
DashO, the build, and Tomcat are all run with the same Java, and are all using the same servlet.jar file. I have verified all classpaths, and the jar file does include the needed classes, and it is the only jar file that includes that package.
I don't see why HttpServletRequest would not be found, when it just found HttpServlet from the same package.
Any ideas?
Brian Daniel

Joined: Oct 10, 2001
Posts: 3
FYI - Discovered this cached post which helped me resolve the issue - I moved the jars from the tomcat/common/lib folder to the tomcat/lib folder and it worked fine. Not sure why it didn't work when I had the jar files referenced directly in the classpath.
[jcifs] More classloader issues
Glass, Eric eric.glass@capitalone.com
Fri, 13 Dec 2002 16:27:15 -0500
Previous message: [jcifs] More classloader issues
Next message: [jcifs] More classloader issues
Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
> I don't understand. If Webapp1 tries to access an SmbFile that will
> execute the static initializer in jcifs.Config which will add
> 'jcifs' to
> the java.protocol.handler.pkgs System property. The jCIFS
> classes should
> be available to the System class loader (that's our requirement). When
> the SmbFile constructor is called, the URL class (loaded from the
> System class loader) will see 'smb://' and try to find a handler. From
> the code you show below it should find jcifs.smb.Handler in the System
> class loader. Everything ok so far right?

This is correct -- with jCIFS loaded from the system classloader, a servlet
would be able to use SMB URLs properly as described above. This will solve
the MalformedURLExceptions when attempting to create SMB URLs under both
Tomcat and Resin (under just about any environment, actually). Tomcat's
issue is different, but somewhat related.

> >
> > The problem will arise under Tomcat when NtlmFilter is
> loaded; it will find
> > the implementation under the system classloader, but
> NtlmFilter will be
> > unable to find javax.servlet.Filter (which is loaded under
> the common
> > classloader). This will cause a NoClassDefFoundError, specifically:
> But the container will be trying to load classes in the Webapp class
> loader. So when accessing jcifs.http.NtlmHttpFilter it will fail as it
> will in the Shared and Common class loaders before
> successfully loading
> from the System class loader. Now when resolving the
> javax.servlet.Filter
> baseclass and other servlet classes will it try from the Webapp
> classloader again or degenerate to the classloader from which it just
> loaded jcifs.http.NtlmHttpFilter? I don't see the security risk in
> starting from the original context loader again.

It's not as much a matter of security as it is visibility; what happens is:
a) The container tries to load jcifs.http.NtlmHttpFilter via the webapp
b) The webapp classloader fails (since jCIFS is installed in the system
classloader); classloading is delegated to the parent (the "shared"
c) The shared classloader fails, and classloading is delegated to the parent
(the "common" classloader).
d) The common classloader fails, and classloading is delegated to the system
e) The system classloader successfully locates jcifs.http.NtlmHttpFilter,
and begins to define the class.
f) As part of the class definition process, the system classloader attempts
to locate and load the superclass (javax.servlet.Filter). This process is
independent of the loading of NtlmHttpFilter; the system classloader is
unaware of the existence of the descendant classloaders (common, shared, and
webapp). Since the system classloader is the defining classloader for
NtlmHttpFilter, that is where the search begins (and, as it turns out, ends
with a failure).
This is kind of a simplification; in reality only the webapp classloader
attempts to load the class before delegating to the parent (the normal JDK
behavior is to delegate to the parent first, and load the class only if the
parent cannot find it; the servlet spec reverses this behavior for the
webapp classloader to allow web applications to override container-wide
classes). But the end result is the same; webapp fails, and delegates to
shared, which delegates to common, which delegates to system, which
succeeds. While defining the NtlmHttpFilter class, system attempts to load
javax.servlet.Filter, and fails.
Basically each classloader is only aware of its parent, and has no means of
knowing if any child classloaders exist.

> Also getting jcifs.smb.Handler installed in the System class loader is
> a completely separate issue right? There's really no relation between
> the problems other than their both being "class loading" issues.

That is correct, with the caveat being that putting jcifs.smb.Handler in the
system classloader also puts NtlmHttpFilter in the system classloader (since
they are packaged together), which causes the Tomcat issue. To resolve it,
Tomcat users have to make sure that the core servlet classes are available
in either the same classloader as jCIFS or an ancestor; this involves
leaving jcifs.http.* under the webapp classloader (as a separate jar) or
moving "servlet.jar" into the system classloader with the jCIFS jar.

> Ok, this is good info but I don't think it will ever be necessary. Our
> requirement is that the jCIFS jar be available to the System
> classloader. This basically equites to putting it in the
> containers top
> level lib directory and possibly adding it explicitly to the container
> CLASSPATH. Whatever the case, the code will likely have AllPermission
> or similar.

Probably a safe assumption.

> I just need to establish the simplest "correct" installation
> procedure. So
> far, ensuring the jar is loaded by the System class loader
> and that it's
> codeBase has the necesary PropertyPermission should work. If
> anyone wants
> a more finely grained procedure they can be referred to these messages
> in the archive.

Possibly a note for Tomcat users to relocate the servlet.jar, or a note to
see the FAQ. Other than that, this should suffice.
Marty Hall
Ranch Hand

Joined: Jan 02, 2003
Posts: 111
I know you already posted the answer, but I'm puzzled as to why you want to use obfuscation anyhow. The clients have no access to any of the .class files or JSP source code, so what's the point of obfuscation?
- Marty

Java training and consulting
Mike Curwen
Ranch Hand

Joined: Feb 20, 2001
Posts: 3695

If you wanted to sell your web-application, you might want to hide how you implemented it from the client (the guy that bought the software, not the web browsing client).
wood burning stoves
subject: Strange NoClassDefFoundError with obfuscated build