Bug 36718 - Compiler should not generate references to classes not on the classpath
Summary: Compiler should not generate references to classes not on the classpath
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.1   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 2.1.1   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 13765 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-04-21 13:24 EDT by Sean Foley CLA
Modified: 2003-06-18 10:31 EDT (History)
1 user (show)

See Also:


Attachments
WSDD project illustrating problem (193.81 KB, application/octet-stream)
2003-04-21 13:30 EDT, Sean Foley CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sean Foley CLA 2003-04-21 13:24:31 EDT
Create a java source file for class C with an error in method M.  Do a "rebuild 
all" in eclipse.  The compiler will generate a class file for C with code that 
uses the reflection API to throw an error.  The problem is that the reflection 
API is not present in all editions of java, particularly J2ME.  See report 
below for details.
Comment 1 Sean Foley CLA 2003-04-21 13:25:19 EDT
Customer reported and provided the following case.  The project has a 
compilation error in one of the classes (missing catch clause).  The customer, 
not being familiar with WSDD, did not notice the red X's and proceeded to 
attempt a target build for Palm.  Somehow this caused the output below, in 
which jxelink is looking for java.lang.reflect.Constructor -- in a MIDP 
project.  As soon as I fixed the compilation error, the project built for the 
target correctly.

The PR is that WSDD gave the customer what was evidently a non-intuitive 
indication of the problem.  Perhaps users could be warned if they try to do a 
target build on a project that contains build errors.  (I would probably find 
that annoying myself, but wanted to document that the customer had reported 
this user-experience.)  In any case, one would hope that the Log Console would 
have provided a better indication of the problem.

C:\Program Files\IBM\Device Developer\wsdd5.0\ive\bin\jxelink -macro
JRE_LIB=C:/Program Files/IBM/Device
Developer/wsdd5.0/ive/lib/jclFoundation/classes.zip -macro PROJECT
RT-JNI=C:\Program Files\IBM\Device Developer\workspace\RT-JNI -macro
IVEHOME=C:\Program Files\IBM\Device Developer\wsdd5.0\ive -macro
JRE_SRC=C:/Program Files/IBM/Device
Developer/wsdd5.0/ive/lib/jclFoundation/source/source.zip -macro
JRE_SRCROOT= @C:\Program Files\IBM\Device
Developer\workspace\RT-JNI\palm68k\RTWrapper.jxeLinkOptions
IVEL0009(A) Loaded 2 class(es) in 1 seconds.
IVEL0049(A) Reduced to 2 class(es) in 0 seconds.
IVEL0023(W) In method
java/lang/Class/getConstructor([Ljava/lang/Class;)Ljava/lang/reflect/Constru
ctor;, return type java.lang.reflect.Constructor not found.
IVEL0018(W) In method com/palm/rtma/RTMAWrapper/RTMAWrapEx/startApp()V,
referenced method java.lang.Class/getConstructor(Class[]) not found.
IVEL0016(W) In method com/palm/rtma/RTMAWrapper/RTMAWrapEx/startApp()V,
referenced class java.lang.reflect.Constructor not found.
IVEL0054(A) Segment 0: 2 class(es) written, 5 resource(s) written, classes
and resources require 6914 bytes ROM, 664(no JIT)/800(JIT) bytes RAM.
IVEL0012(A) Generated "C:\Program Files\IBM\Device
Developer\workspace\RT-JNI\palm68k\RTWrapper.jxe" in 0 seconds.
IVEL0036(A) Summary: 0 error(s), 3 warning(s), 2 class(es) read, 2 class(es)
written, 4 resource(s) written.
IVEL0039(A) Summary: classes and resources require 6914 bytes ROM, 664(no
JIT)/800(JIT) bytes RAM.
C:\Program Files\IBM\Device Developer\wsdd5.0\ive\bin\jxe2prc RTMw RTWrapEx
-nologo -midp -translate -compress -scale C:\Program Files\IBM\Device
Developer\workspace\RT-JNI\palm68k/RTWrapper.jxe C:\Program Files\IBM\Device
Developer\workspace\RT-JNI\palm68k\RTWrapper.prc

------- Additional Comment #1 From Bill Russell 2003-02-07 00:23 ------- 
Created an attachment (id=619)
WSDD project that illustrates the problem

Unzip and import project into workspace.  Open wsddbuild.xml and hit "Perform
Build".  Observe warnings in Log Console.  Fix missing catch clause in
RTMAWrapEx.startApp() to make the problem go away.

------- Additional Comment #2 From Andrew Sandstrom 2003-04-20 20:37 ------- 
Any status?

------- Additional Comment #3 From sfoley 2003-04-21 11:51 ------- 
This one is still open.

Frankly, I am not sure what direction this should take.  With warnings such as 
the one below, the midlet might execute fine.  It will only fail if the 
relevant methods are called.  There is no way of knowing whether it will fail 
or not when it is used.

Secondly, how do the java classes compile in WSDD if 
java.lang.reflect.Constructor cannot be found?  Isn't there normally an error 
listed in the tasks view of WSDD?



------- Additional Comment #4 From Bill Russell 2003-04-21 12:22 ------- 
java.lang.reflect.Constructor isn't needed for this project.  In fact, the 
entire reflect package is non-existent in CLDC/MIDP. I don't know why jxelink 
becomes convinced that this is of interest.  It has nothing to do with the 
project in question.

Part of the problem is that this is what shows up in the jxelink console 
output.  It's totally out of left field, so it doesn't help the user at all and 
it even hurts by sending them on a wild goose chase.

We can't (necessarily) blame jxelink for weird behavior when what we've sent it 
isn't self-consistent (e.g. didn't build).  So we should probably warn the user 
when they try to send jxelink something that isn't self-consistent.  I agree 
that we should not prevent the build, but we should probably warn.  Optimally 
the user would be able to disable the warning in the preferences.


------- Additional Comment #5 From sfoley 2003-04-21 14:00 ------- 
I have tried this out and confirmed this strange behaviour.

Upon investigation, I have determined that this behaviour is caused by the 
compiler.  When the compiler fails to compile the startApp() method because of 
the missing catch or finally clause, it actually creates a new startApp() 
method that looks like:

protected void startApp() throws javax.microedition.midlet.MIDletStateChangeExce
ption
    0 JBldc 19 (java.lang.String) "java.lang.Error"
    2 JBinvokestatic 25 java.lang.Class.forName(Ljava.lang.String;)Ljava.lang.Cl
ass;
    5 JBiconst1
    6 JBanewarray 21 java.lang.Class
    9 JBdup
   10 JBiconst0
   11 JBldc 27 (java.lang.String) "java.lang.String"
   13 JBinvokestatic 25 java.lang.Class.forName(Ljava.lang.String;)Ljava.lang.Cl
ass;
   16 JBaastore
   17 JBinvokevirtual 31 java.lang.Class.getConstructor([Ljava.lang.Class;)Ljava
.lang.reflect.Constructor;
   20 JBiconst1
   21 JBanewarray 33 java.lang.Object
   24 JBdup
   25 JBiconst0
   26 JBldc 35 (java.lang.String) "Unresolved compilation problem:
        Syntax error on token "Display", "finally" expected
"
   28 JBaastore
   29 JBinvokevirtual 41 java.lang.reflect.Constructor.newInstance([Ljava.lang.O
bject;)Ljava.lang.Object;
   32 JBcheckcast 43 java.lang.Error
   35 JBathrow
   36 JBpop
   37 JBaconstnull
   38 JBathrow
   39 JBreturn

Exception Table
start   end   handler   catch type
-----   ---   -------   ----------
    0    36        36   java.lang.Exception

This can be translated into the following java code:

protected void startApp() {
	try {
		Class errorClass = Class.forName("java.lang.Error");
		Class params[] = new Class[] {
			Class.forName("java.lang.String")};
		Constructor constructor = errorClass.getConstructor(params);
		Object args[] = new Object[] {
			"Unresolved compilation problem..."};
		Error error = (Error) constructor.newInstance(args);
		throw error;
	}
	catch(Exception e) {
		throw null;
	}
	return;
}

So the compiler is creating a reference to java/lang/Class/getConstructor.  
Jxelink sees this reference and correctly warns the user that the reference 
cannot be resolved.

Jxelink is not at fault here.  What is provided to Jxelink is actually entirely 
consistent, a perfectly well-formed java class file.

Frankly, I cannot see why the compiler would not generate the following code 
instead, if it wanted to be so smart:

protected void startApp() {
	throw new Error("Unresolved compilation problem...");
}

The compiler seems to try to account for the possibility that the constructor  
java.lang.Error(java.lang.String) might not exist.  In so doing it assumes the 
existence of java.lang.reflect.Constructor.  Seems ridiculous to me, since the 
constructor java.lang.Error(java.lang.String) is present in all java editions 
and profiles while java.lang.reflect.Constructor is not!!

It seems to me that the compiler is really going out of its way to be generous 
to the user.  When it cannot compile the code, it goes out of its way to 
generate a method that will inform the user if the user tries to run the code 
anyway.  The problem is that it creates a method that is inconsistent with CLDC.

There are two other things worth noting here:

1.  I've discovered that the compiler will only generate a class file for the 
malformed class when selecting "rebuild all" in WSDD.  WHen doing "rebuild 
project", no class file is produced.

2.  If no class file is produced by the compiler, then when jxelink attempts to 
build the project, WSDD pops up a dialog box saying that warnings were 
generated during jxelink build phase, listing the warnings that the file 
RTMAWrapEx.class could not be found.  This is the kind of behaviour that is 
being requested.


This is really a compiler issue.  Either it should:
A) Generate code that is consistent with CLDC
B) Generate no class file at all.
Either way would be more informative to the user.

This needs to be assigned to the relevant person in the compiler team.

Comment 2 Sean Foley CLA 2003-04-21 13:30:14 EDT
Created attachment 4652 [details]
WSDD project illustrating problem

See comment above from Bill Russell regarding this attachment (comment
2003-02-07 00:23)
Comment 3 Olivier Thomann CLA 2003-04-21 15:20:07 EDT
We should improve the way we generate the problem methods. The methods are
really useful to prevent the user from having too many problems when one method
cannot be compiled successfully. All dependant classes can still refer to this
problem method because there is a class file for the type that contains this method.
The way we do it right now is related to the fact that the error sent at runtime
can be changed. If we consider that we want to throw a java.lang.Error all the
time, then we can simplify the code generation and get rid of the reflection call.
Comment 4 Philipe Mulet CLA 2003-04-22 05:29:04 EDT
At least we could special case a few well-known exception types...
If target exception is java.lang.Error, then inline it.

Please make this change.
Comment 5 Olivier Thomann CLA 2003-04-22 11:23:07 EDT
Now a problem method looks like this:
   throw new Error(problemMessage);
instead of a reflection call.

Fixed and released in HEAD contents.
Comment 6 Olivier Thomann CLA 2003-04-22 15:48:00 EDT
Backported to 2.1 maintenance stream.
Comment 7 David Audel CLA 2003-06-02 08:15:13 EDT
Verified.
Comment 8 David Audel CLA 2003-06-10 10:24:47 EDT
Verified for 3.0M1.
Comment 9 Philipe Mulet CLA 2003-06-18 10:31:39 EDT
*** Bug 13765 has been marked as a duplicate of this bug. ***