Bug 536292 - [compile] Wrong annotation usage creates weird semi-compiled code
Summary: [compile] Wrong annotation usage creates weird semi-compiled code
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.7.3   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2018-06-26 06:41 EDT by Lukas Eder CLA
Modified: 2022-09-13 07:13 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Lukas Eder CLA 2018-06-26 06:41:06 EDT
Consider the following code:

------------------------------------------------------------
@X(abd = "")
class Annotated {
    static final String WORLD = "World";
}

class Annotations {
    public static void main(String[] args) {
        System.out.println("Hello, " + Annotated.WORLD);
    }
}

@interface X {
    String abc();
}
------------------------------------------------------------

The annotation usage of @X in Annotated is wrong. Yet, running the Annotations program works, printing "Hello, World". Probably because the WORLD constant is inlined in a compilation step. Preventing this inlining as follows...

------------------------------------------------------------
@X(abd = "")
class Annotated {
    static final String WORLD = new String("World");
}

class Annotations {
    public static void main(String[] args) {
        System.out.println("Hello, " + Annotated.WORLD);
    }
}

@interface X {
    String abc();
}
------------------------------------------------------------

... yields "Hello, null", as the constant has not been initialised successfully, due to Annotated not compiling.

When running main from the annotated class, nothing works anymore:

------------------------------------------------------------
@X(abd = "")
class Annotations {
    static final String WORLD = new String("World");
    public static void main(String[] args) {
        System.out.println("Hello, " + WORLD);
    }
}

@interface X {
    String abc();
}
------------------------------------------------------------

The above throws an exception, when run:

------------------------------------------------------------
Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	at Annotations.main(Annotations.java:4)
------------------------------------------------------------

I think that Eclipse's partial compiler should either:

- Ignore the wrong annotation and compile the class nevertheless
- Fail compilation also in the referencing class

The way it is now, I find the behaviour quite inconsistent, which can lead to hard to find problems in large projects where annotations may have been changed incompatibly
Comment 1 Stephan Herrmann CLA 2018-06-30 13:37:37 EDT
When partial compilation was first implemented, Java didn't have annotations, so the rule was simple: any code with errors is replaced with "throw new Error(theCompileErrorMessage)", so if you hit that code, you get an exception, otherwise the program can be executed OK.

Annotations make this a bit trickier, because there is not code to execute and hence we cannot just let it throw Error.

The last example demonstrates that the class with the erroneous annotation itself has a throw statement. Looking into the bytecode I see two variants:
- The constructor throws Error containing the actual compiler message
- The main method throws Error with only "Unresolved complation problem:"

A simple reference to a class with broken annotation does not trigger the exception, and frankly: why should it? Since the compiler knows nothing about the semantics of user-defined annotations, it cannot tell which level of using that class is broken by the broken annotation.

Strange, indeed, is the fact, that the broken annotation prevents the <clinit> method from being generated (which initializes static fields).

To make things consistent I see two options (at least):

- Continue generating regular <clinit> even in the presence of compile errors

- Let <clinit> throw Error (in which case the class simply cannot be loaded)

I'd need a good reason for deciding one way or the other.


OTOH, you aren't saying, you ship code with compile errors, are you? ;p
Running code with errors is intended just as a convenience during development.
When hunting for a bug, compile errors should be the first candidates to fix, no?
Comment 2 Lukas Eder CLA 2018-07-02 03:06:05 EDT
(In reply to Stephan Herrmann from comment #1)
> A simple reference to a class with broken annotation does not trigger the
> exception, and frankly: why should it? Since the compiler knows nothing
> about the semantics of user-defined annotations, it cannot tell which level
> of using that class is broken by the broken annotation.

That is a very philosophical question :) I personally think that the behaviour in the presence of a compilation error in a class annotation should be any of:

- Entire class doesn't exist
- Erroneous annotation is completely ignored

The same would be true for method annotations, which should, IMO, cause a method to either not exist (or throw the usual error), or the annotation be ignored.

I can live with either behaviour, as long as it is consistent.

> OTOH, you aren't saying, you ship code with compile errors, are you? ;p
> Running code with errors is intended just as a convenience during
> development.
> When hunting for a bug, compile errors should be the first candidates to
> fix, no?

I'm maintaining a source code generator and while changing that generator, the incremental compilation is very useful as I can focus on the change first and fix regressions in generated code later. The way I've been using Eclipse for this kind of task, it simply didn't occur to me that a NPE could be caused by a wrong annotation, so I didn't check the error view.

In my case, the regression was introduced because of some dependency changes, when suddenly, the javax.annotation.Generated annotation was pulled in from a buggy third party Tomcat dependency, which for some reason called the "comments" attribute just "comment". A really weird edge case.

Eclipse's incremental compilation is both a blessing and a curse :)
Comment 3 Eclipse Genie CLA 2020-08-03 15:21:29 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 4 Eclipse Genie CLA 2022-09-13 07:13:11 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.