Strange Applet Problem involving Enums

R

Rhino

I'm having an odd problem in a JApplet and I need some help.

The applet, which is written using Java 1.5.0, works perfectly in the
Eclipse 3.1.1 AppletViewer. However, it gives me an odd error when I am
running in IE6 on Windows XP (SP2). This is the output from the Java console
in IE6:

==============================================================
Java Plug-in 1.5.0_06
Using JRE version 1.5.0_06 Java HotSpot(TM) Client VM
User home directory = C:\Documents and Settings\Rhino

java.lang.NoClassDefFoundError:
com/foo/resume/ResumeConstants$EmploymentHistoryFormats
at com.foo.resume.ResumeConstants.<clinit>(ResumeConstants.java:245)
at com.foo.resume.ResumeApplet.init(ResumeApplet.java:105)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Exception in thread "thread applet-com.foo.resume.ResumeApplet.class"
java.lang.NullPointerException
at sun.plugin.util.GrayBoxPainter.showLoadingError(Unknown Source)
at sun.plugin.AppletViewer.showAppletException(Unknown Source)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

==============================================================

This is line 105 of ResumeApplet, it is the first non-comment line in the
method and the class implements an interface named ResumeConstants:

getContentPane().setBackground(BEHIND_TAB_COLOR);

The ResumeApplet implements an interface named ResumeConstants and
BEHIND_TAB_COLOR is one of the constants in the interface.

This is line 245 of ResumeConstants:

static final EmploymentHistoryFormats DESIRED_EMPLOYMENT_HISTORY_FORMAT
= EmploymentHistoryFormats.LIST_FORMAT;

It is preceeded by this line:

static enum EmploymentHistoryFormats {LIST_FORMAT, PARAGRAPH_FORMAT};

I'm trying to figure out why an enum that is clearly present in
ResumeConstants would cause a ClassDefNotFound error in IE6 but not in the
AppletViewer. ResumeConstants.class is definitely present in the jar that
contains the ResumeApplet.

If anyone could shed some light on this, I would be very grateful!

The only glimmer of insight I've got is that the enum can be defined static
but not final in the interface; if I try to make it static _and_ final, I
get tis message: Illegal modifier for the member enum
EmploymentHistoryFormats; only public, protected, private, static, abstract
are permitted. This affects line 244 which possibly impacts line 245 but I'm
darned if I can see exactly how; after all, I've removed the final again and
now the interface is clean as whistle. I am not ignoring a single compiler
condition at all: every condition is set to either Error or Warning.

So, what am I doing wrong and why doesn't it affect the AppletViewer?

--

Just for interest sake, I just tried the applet in Mozilla Firefox 1.0
Preview and Opera 7.5.4.

Opera gave me the exact same error as IE6.

Firefox drew a puzzle symbol in the applet area with the words "Click here
to download plugin". I clicked it but the Plugin Finder Service quickly
reported that "No suitable plugins were found." I can't recall if I tested
this applet in Firefox or Opera before; I thought I did but I can't recall
since it was a while back.

I'm not sure if that gives anyone any further insight into my problem. This
is very puzzling; the applet was working fine in IE6 for quite some time.
I've made some minor changes recently, including the addition of lines 244
and 245 of the ResumeConstants interface, so I assume they are culprits; I
just don't see why they are messing things up....
 
Z

zero

ResumeConstants.class is definitely present in the jar that
contains the ResumeApplet.

The class that can't be found is not ResumeConstants.class, it's
ResumeConstants$EmploymentHistoryFormats.class Is that one in the jar? Is
it in the correct subdirectory for the relevant package? Is the path to
the file (including the path *inside* the jar) maybe too long?

These are just a few ideas off the top of my head, maybe they can help you
locate the problem.

As an aside, you should not use an interface to define constants. Use a
non-instantiable (for example abstract) and preferably final class with
static members as constants.
 
R

Rhino

zero said:
The class that can't be found is not ResumeConstants.class, it's
ResumeConstants$EmploymentHistoryFormats.class

Here again are lines 244 and 245 of ResumeConstants.java:

static enum EmploymentHistoryFormats {LIST_FORMAT, PARAGRAPH_FORMAT};
static final EmploymentHistoryFormats DESIRED_EMPLOYMENT_HISTORY_FORMAT
= EmploymentHistoryFormats.LIST_FORMAT;

As you can see, EmploymentHistoryFormats is an enum _within_
ResumeConstants, not a separate class. The $ within the name
ResumeConstants$EmploymentHistoryFormats should confirm that. There is no
separate class file name ResumeConstants$EmploymentHistoryFormats; as far as
I know, that's exactly the way things _should_ be, right? Or are enums
defined _within_ interfaces or classes supposed to have separate class files
generated for them?
Is that one in the jar?

ResumeConstants.class is in the jar. I _assume_ that
ResumeConstants$EmploymentHistoryFormats.class is within
ResumeConstants.class but I could be wrong; how can I confirm that it is?
Is
it in the correct subdirectory for the relevant package? Is the path to
the file (including the path *inside* the jar) maybe too long?
Is there a limitation on the length of a path within a jar? This is the
first I've heard of that. What is the limitation? In any case, I don't think
that my path name is unusually long; I've seen longer ones in examples that
didn't seem to be a problem.
These are just a few ideas off the top of my head, maybe they can help you
locate the problem.
I appreciate the help, I really do! This problem has got me quite confused.
As an aside, you should not use an interface to define constants. Use a
non-instantiable (for example abstract) and preferably final class with
static members as constants.

I have to admit that this is the first time I've heard this suggestion in
several years of coding Java. One of the first Java books I bought actually
suggested using interfaces for constants and I've been doing it ever since.
I've never had a problem with it before and I don't recall ever seeing
anyone insist that interfaces shouldn't be used for constants. But maybe I
just wasn't paying attention when the gurus announced this recommendation.

Why exactly are interfaces composed entirely of constants a bad idea? And,
just for interest sake, when was this recommendation first made? I've been
writing Java since 1997....
 
Z

zero

There is
no separate class file name ResumeConstants$EmploymentHistoryFormats;
as far as I know, that's exactly the way things _should_ be, right? Or
are enums defined _within_ interfaces or classes supposed to have
separate class files generated for them?

As I understand it, enums are in fact a kind of inner class. Inner classes
have a separate class file called Outer$Inner.class - however, I did a test
with enums and there indeed was no such file, so I suppose your situation
is indeed normal.
Is there a limitation on the length of a path within a jar? This is
the first I've heard of that. What is the limitation? In any case, I
don't think that my path name is unusually long; I've seen longer ones
in examples that didn't seem to be a problem.

I honestly don't know if there is a limitation. I do know that the total
path length to a file on windows is limited. You mentioned that it works
in AppletViewer but not in IE, so I thought that might be a problem. A
simple test could prove me wrong.

Like I said these are just wild guesses, I really don't know what could be
causing this problem.
Why exactly are interfaces composed entirely of constants a bad idea?
And, just for interest sake, when was this recommendation first made?
I've been writing Java since 1997....

An interface is normally used to add abilities to a class. For example,
implementing Comparable means you add the ability to compare objects of
your class. Interfaces with only constants don't follow this pattern -
they add no extra abilities to your class.

Suppose you have a class defined as:

public class MyList implements List, MyConstants

where MyConstants is an interface with only constants. Now it makes
perfect sense to refer to a MyList object as an object of type List. But
what's the sense in referring to it as a MyConstants object? It is
perfectly legal and common to refer to objects through an interface they
implement, but for constants interfaces this makes no sense.

Lastly, if you have a class that implements a constants interface, all its
subclasses are littered with the same constants, even if they don't need
them. So you're polluting the whole class tree.

Using an abstract class instead of an interface gives you all the benifits,
and none of these disadvantages.

I believe it was Joshua Bloch who first recommended against constants
interfaces in his classic Effective Java.
 
T

Thomas Hawtin

Rhino said:
As you can see, EmploymentHistoryFormats is an enum _within_
ResumeConstants, not a separate class. The $ within the name
ResumeConstants$EmploymentHistoryFormats should confirm that. There is no
separate class file name ResumeConstants$EmploymentHistoryFormats; as far as
I know, that's exactly the way things _should_ be, right? Or are enums
defined _within_ interfaces or classes supposed to have separate class files
generated for them?

Enums are classes. Nested enums should have a class file in the same way
as nested classes and interfaces do. Enum constants that override method
will also need their own class files. There can only be a single class
or interface of any description in one class file.
ResumeConstants.class is in the jar. I _assume_ that
ResumeConstants$EmploymentHistoryFormats.class is within
ResumeConstants.class but I could be wrong; how can I confirm that it is?

That could be your problem.

You can list the files in a jar with "jar tf myapp.jar". Alternatively
use your favourite zip tool to have a look.
I have to admit that this is the first time I've heard this suggestion in
several years of coding Java. One of the first Java books I bought actually
suggested using interfaces for constants and I've been doing it ever since.
I've never had a problem with it before and I don't recall ever seeing
anyone insist that interfaces shouldn't be used for constants. But maybe I
just wasn't paying attention when the gurus announced this recommendation.

The problem is not interfaces only containing constants. Interfaces are
much better than using classes in that situation. You can drop the
"public static final" noise.

The problem is with implementing those interfaces. The constants become
part of your class interface and are indiscriminately imported into your
code. From 1.5 static imports allow specifying which constants to
import, although using it willy-nilly is not a good idea.

Tom Hawtin
 
R

Rhino

zero said:
As I understand it, enums are in fact a kind of inner class. Inner
classes
have a separate class file called Outer$Inner.class - however, I did a
test
with enums and there indeed was no such file, so I suppose your situation
is indeed normal.


I honestly don't know if there is a limitation. I do know that the total
path length to a file on windows is limited. You mentioned that it works
in AppletViewer but not in IE, so I thought that might be a problem. A
simple test could prove me wrong.
What do you have in mind? I can't think of any particularly simple tests to
see when path lengths become a problem unless Windows or the JVM actually
give you very clear messages when you exceed the limit - if there is one.
But I think this is academic now; read on....
Like I said these are just wild guesses, I really don't know what could be
causing this problem.
I understand that and appreciate your suggestions.

For what it's worth, I've made the enum problem go away by simply making
sure each of my enums was in a separate source file, just like a public
class or interface. For some reason, the JVM has trouble finding enums when
they are imbedded within an interface or a class! I had one of each, i.e.
one enum defined in an interface and one defined in a class, and both of
them gave me ClassDefNotFound errors when I tried to access them in applets
running in a browser, although they worked fine in the Eclipse AppletViewer
and as applications in Eclipse.

I think I'm going to have to get in the habit of putting each enum in a
separate source file if I want to avoid problems in the future....
An interface is normally used to add abilities to a class. For example,
implementing Comparable means you add the ability to compare objects of
your class. Interfaces with only constants don't follow this pattern -
they add no extra abilities to your class.

Suppose you have a class defined as:

public class MyList implements List, MyConstants

where MyConstants is an interface with only constants. Now it makes
perfect sense to refer to a MyList object as an object of type List. But
what's the sense in referring to it as a MyConstants object? It is
perfectly legal and common to refer to objects through an interface they
implement, but for constants interfaces this makes no sense.

Lastly, if you have a class that implements a constants interface, all its
subclasses are littered with the same constants, even if they don't need
them. So you're polluting the whole class tree.

Using an abstract class instead of an interface gives you all the
benifits,
and none of these disadvantages.

I believe it was Joshua Bloch who first recommended against constants
interfaces in his classic Effective Java.

Okay, fair enough. I guess I'll change my interfaces into abstract classes
and write my constants that way from now on.

Thanks for filling me in on this development (and for your suggestions about
what the problem might be)!

Rhino
 
R

Rhino

Thomas Hawtin said:
Enums are classes. Nested enums should have a class file in the same way
as nested classes and interfaces do. Enum constants that override method
will also need their own class files. There can only be a single class or
interface of any description in one class file.
Well then, I wish the enum article in the 1.5 API had bothered to mention
that; I don't recall seeing that enums had to be - or ought to be - in
separate files. I would also have expected to get compiler warnings if I
defined my enums right in my other classes or interfaces - but this doesn't
happen either. It makes for a bit of a rude surprise when you only find it
is a problem when you're actually trying to implement the code :)

That could be your problem.

You can list the files in a jar with "jar tf myapp.jar". Alternatively use
your favourite zip tool to have a look.

I did the 'jar tf' when I first got the error about
ResumeConstants$EmploymentHistoryFormats.class and the jar contained only
ResumeConstants.class, not ResumeConstants$EmploymentHistoryFormats.class or
just EmploymentHistoryFormats.class. That made me wonder if the folks at Sun
had figured out someway to include an embedded enum within
ResumeConstants.class; my question was about a tool to determine if
ResumeConstants.class might conceivably contain EmploymentHistoryFormats
within it, somehow. In the cold light of day, it now seems a pretty
improbable notion that an inner class might conceivably be imbedded within
its outer class as of Java 1.5.0 but it seemed distantly possible when I
asked the question.
The problem is not interfaces only containing constants. Interfaces are
much better than using classes in that situation. You can drop the "public
static final" noise.

The problem is with implementing those interfaces. The constants become
part of your class interface and are indiscriminately imported into your
code. From 1.5 static imports allow specifying which constants to import,
although using it willy-nilly is not a good idea.
You and Zero have convinced me; I'm going to change my constants-only
interfaces into abstract classes.
 
T

Thomas Hawtin

Rhino said:
Well then, I wish the enum article in the 1.5 API had bothered to mention
that; I don't recall seeing that enums had to be - or ought to be - in
separate files. I would also have expected to get compiler warnings if I
defined my enums right in my other classes or interfaces - but this doesn't
happen either. It makes for a bit of a rude surprise when you only find it
is a problem when you're actually trying to implement the code :)

I mean each nested class has its own class file, not .java source file.

Tom Hawtin
 
R

Roedy Green

Or are enums
defined _within_ interfaces or classes supposed to have separate class files
generated for them?

Have a look at my tutorial. I show decompiled enums. Enums are
classes and so are their values that have their own methods.

The one thing I am not sure of is whether an enum is really an inner
class or a nested class.

I suppose some experiments with access would clear that up.
 
Z

zero

What do you have in mind? I can't think of any particularly simple
tests to see when path lengths become a problem unless Windows or the
JVM actually give you very clear messages when you exceed the limit -
if there is one. But I think this is academic now; read on....

Well I was thinking of simply reducing the length of the paths that were
giving you problems. or the other way around, define classes with a very
long and a very short path, and see if they both work.

This wouldn't really *prove* anything, but it would be a good indication.
Thanks for filling me in on this development (and for your suggestions
about what the problem might be)!

no problem :)
 
C

Chris Uppal

Roedy Green wrote:

The one thing I am not sure of is whether an enum is really an inner
class or a nested class.

I suppose some experiments with access would clear that up.

Since enums clearly cannot depend on any particular instance of the
containing class -- since their instances are created too early -- you
can deduce that they are necessarily static. I presume the JLS3 also
makes this clear. Being static, they are nested classes (or member
classes as I vaguely remember the JLS putting it).

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top