Eclipse is adding #Override annotations when I implement methods of an interface. Eclipse seems to have no problem with this. And our automated build process from Cruise Control seems to have no problem with this. But when I build from the command-line, with ant running javac, I get this error:
[javac] C:\path\project\src\com\us\MyClass.java:70: method does not override a method from its superclass
[javac] #Override
[javac] ^
[javac] 1 error
Eclipse is running under Java 1.6. Cruise Control is running Java 1.5. My ant build fails regardless of which version of Java I use.
The #Override annotation spec changed in Java 1.6. In Java 1.5, the compiler did not allow the #Override annotation on implemented interface methods, but in 1.6 it does. First search result I found is a blog post here.. It was not well documented, but it did change.
Eclipse is adding it because your Eclipse is set for 1.6 compliance. You should try to keep your build and eclipse environments on the same version of Java. It's unclear to me by your specifying Cruise Control is running Java 5 on whether or not it is compiling using a separate JDK6 or not.
Separate from the above 1.5 vs 1.6 #Override annotation rules, remember that Eclipse has its own compiler implementation (not javac) and will occasionally have different behavior. Whenever something compiles in Eclipse, but not Ant or Maven, you will need to find a way to make both compilers happy.
I can't really explain the problem you're seeing but it seems to be related to the fact that JDK 5 will not allow #Override on implemented methods of an interface, only on overridden methods present in a super class.
JDK 6 will allow #Override on any of them.
If your ant build fails it may be passing a source parameter to javac, asking for JDK 5 compliance.
The direct answer to the question "Why" an error is raised by javac when #Override is used in the context of a method implementation is actually in the java specifications:
"The rationale for this is that a concrete class that implements an interface will necessarily override all the interface's methods irrespective of the #Override annotation, and so it would be confusing to have the semantics of this annotation interact with the rules for implementing interfaces."
See http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.6.1.4
But apparently someone changed his mind for java 1.6 and 1.5 u21...
#Override tags for implemented methods are new to Java 1.6. In Java 1.5 #Override is only correct when overriding a method in a base class. Read more here and here.
A lot of people, including me, got busted by this. See here for a bigger SO discussion
Eclipse would be pointing to 1.6 version of Java rather than 1.5.
See here for configuring java version in eclipse.
Ensure that there is only one definition of that interface.
Example:
HttpServletRequest
This is an interface with different specs depending on provider.
Compare pax-web-jetty and apache-felix-jetty. They have different methods.
I have had the same problem when building a project with ANT. The solution to the problem was to change the following property inside the build.properties file:
javac.compiler=org.eclipse.jdt.core.JDTCompilerAdapter
to:
javac.compiler=modern
That solved the problem and the project got compiled and deployed successfully.
Related
Consider the following self-contained sample:
package bloopers;
import java.lang.annotation.Annotation;
public final class Blooper5
{
interface Converter<T,F>
{
T convert( F from );
}
interface Identifier<T>
{
}
static class ConvertingIdentifier<F,T> implements Identifier<F>
{
ConvertingIdentifier( Converter<T,F> converter )
{
}
}
static final class AnnotationIdentifier
{
Identifier<Annotation> I1 = new ConvertingIdentifier<>(
a -> a.annotationType() );
Identifier<Annotation> I2 = new ConvertingIdentifier<>(
Annotation::annotationType ); //<-- ERROR
Identifier<Annotation> I3 = new ConvertingIdentifier<>(
(Converter<Class<? extends Annotation>,Annotation>)
Annotation::annotationType );
}
}
The code above compiles just fine under the following:
javac from the command line.
IntelliJ IDEA configured to use the javac compiler.
But it fails to compile with the following:
Eclipse
IntelliJ IDEA configured to use the Eclipse compiler.
Eclipse fails to compile the line marked with <-- ERROR, giving the following message:
The constructor Blooper5.ConvertingIdentifier<Annotation,Class<capture#5-of ? extends Annotation>>(Blooper5.Converter<Class<? extends Annotation>,Annotation>) is undefined
Admittedly, this code really pushes the generic parameter type inference capabilities of the compiler, but still, I would like to know precisely what the discrepancy is, no matter how small.
Some exposure of my methods in case someone manages to see something wrong that I fail to see:
The command I used to compile with javac was "c:\Program Files\Java\jdk1.8.0_40\bin\javac" Blooper5.java.
I have version 14.1 of IntelliJ IDEA. Under Project Structure/SDKs I only have "1.8" which points to C:\Program Files\Java\jdk1.8.0_40 and under Project Structure/Modules the specific module is configured to use the "Project SDK (1.8)" which lists as 1.8 (java version "1.8.0_40").
As for Eclipse, I am using Eclipse for RCP and RAP Developers - Version: Luna Release (4.4.0) - Build id: 20140612-0600. Under Preferences/Java/Installed JREs I only have jdk1.8.0_40, and it is the default. Under Execution Environments it is also checked as a "Compatible JRE" of "JavaSE-1.8". And in my Project/Properties/Java Build Path/Libraries the "JRE System Library" is [jdk1.8.0_40].
More noteworthy facts:
It is not just me; it also fails on a colleague's (very similar) eclipse installation.
IntelliJ IDEA says that the lambda expression a -> a.annotationType() can be replaced with a method reference, but if asked to do so, it does not convert it to Annotation::annotationType; instead, it converts it to (Converter<Class<? extends Annotation>, Annotation>) Annotation:: annotationType.
So, the question:
What is causing these discrepancies between Eclipse and the others, and what can be done to eliminate these discrepancies?
(Obviously, the goal is to eliminate the unfortunately too frequently occurring scenario where one developer commits code which fails to compile on another developer's IDE.)
EDIT: When I originally posted this question I thought that IDEA using the Eclipse compiler also compiled fine, but I was wrong. It turns out that it is possible to get IDEA to fail to compile the above code by selecting the Eclipse compiler. Still, the question is why there is a discrepancy between eclipse and javac.
The answer to "why is there a discrepancy" is straightforward but perhaps not very satisfactory: because compilers have bugs and are furthermore open to interpretation of a very complex language specification. Determining whether it's a bug in javac or Eclipse is a difficult task; I've seen such discrepancies end up being declared both ways, sometimes as Eclipse compiler bugs, sometimes as javac bugs. That determination, especially when it involves generics and new language features (such as lambdas), can get quite tedious and arcane. For example, look at this one that turned out to be a javac bug but did uncover a related issue in Eclipse's compiler: https://bugs.eclipse.org/bugs/show_bug.cgi?id=456459
The best bet is to report it as an Eclipse bug as I did and see if the Eclipse compiler team can/will track it down.
In Eclipse, I did: Source > Clean up, and did a clean up according to these rules:
Change non static accesses to static
members using declaring type
Change indirect accesses to static
members to direct accesses (accesses
through subtypes)
Remove unused imports
Add missing '#Override' annotations
Add missing '#Deprecated' annotations
Remove unnecessary casts
Remove unnecessary '$NON-NLS$' tags
but I can't seem to compile it anymore. I get the following error:
Error preverifying class com.myapp.blackberry.Override
java/lang/NoClassDefFoundError: java/lang/annotation/Annotation
Error!: Error: preverifier failed: C:\eclipse\plugins\net.rim.ejde.componentpack6.0.0_6.0.0.29\components\bin\preverify.exe -d C:\DOCUME ...
Packaging project myapp failed (took 0.422 seconds)
When I hover over #Override, it gives me suggestion "Override cannot be resolved to a type"
I am not sure what to do at this point..
Blackberry development is built on top of j2me, which has the language features of Java 1.3. This means it doesn't support annotations. You can remove the #Override annotations and your code will work. Remember these are optional although recommended anyways.
What I do, is write //#Override instead. When/If annotations are added in the future it will be easy to do a regex replace and remove the comment marks.
Seems to be impossible:
The deal is Java ME uses version 1.4 of Java Language Specification.
You cannot use Java 5 language features.
Seems you'll have to do without annotations...
For some reason, putting #Override on methods overriding interface methods causes JSP compilation to fail in weblogic. Everything is definitely running off of JDK 1.6.0_14, but this Java 5'ism still persists.
Oddly, JSP compilation occasionally fails with a stacktrace pointing at code not necessarily obviously used by the JSP itself.
What's going on here?
The #Override is supposed to only be retained in source so shouldn't come up in byte code. There might an angle you can play in ensuring those classes are complied separately from the JSPs and simply available in the classpath -- rather than the source path.
If that's already the case then it might be a different issue than what is immediately showing.
Used to be the JSP complier was a separate library shipped with the server and not tied to the vm the server is running in. WLS used to use Javelin. Seems like they switched that in 10 to use the Java Compiler API. So it should work fine as long as you have Sun vm Java 1.6. But if there's 'javelin' anything in your stacktrace, definitely check that angle.
I've seen this a lot myself. In Java 6, it is (supposedly) permissible to use #Override on interface implementation methods. In Java 5, this is an error. However in my Java 6 code, sometimes #Override is accepted on interface implementation methods, and sometimes it is not.
To make things weirder, some IDEs (e.g. NetBeans) are fine with it, while IntelliJ IDEA is sometimes ok and sometimes not. I have found, however, that compiling the code in either IDE will ignore the alleged errors being reported by the IDE.
In other words, is the problem manifesting in your IDE? If so, compile the code directly (use the command-line if necessary) and see what happens. The IDE may be reporting spurious errors.
A possible workaround might be to precompile JSP using appc. This could at least allow to circumvent the issue.
Regarding the "real" question, my understanding is that you did upgrade domains, so maybe have a look at the following resources:
Web Applications, JSPs, and Servlets
Backwards Compatibility Flags
Procedure for Upgrading a WebLogic Domain
Select Upgrade Options (related to domain upgrade)
Backward Compatibility Flags
JSPCompilerBackwardsCompatible - Specifies whether to allow JSPs that do not comply with the JSP 2.0 specification
This is a wild guess but maybe some backward compatibility flag is activated and WebLogic keeps using the "old" approach.
I agree with your instinct and the other answers that WLS is using Java 5 somehere. The items below seem like useful tidbits from Oracle/WebLogic resources. I don't have a WebLogic Server 10.3 installation to confirm these:
Weblogic Server 10.3
According to this, at least Weblogic Server 10.3 is required to use Java 6, but I can't see anything the confirms this as authoritative info:
http://forums.oracle.com/forums/thread.jspa?threadID=884263
Re: WebLogic 10.0 supports Java 6?
Posted: Apr 9, 2009 12:26 PM in response to: user8324142
Hi,
Weblogic 10 will not support JDK6.
Please upgrade to Weblogic 10.3 to work with JDK 6.
Checking the Java version
http://download.oracle.com/docs/cd/E12840_01/common/docs103/install/postins.html#wp1090736
Determining Which JDK Version You Are Using
You can determine which version of the JDK you are using by issuing a command, as follows:
Open a command prompt window and go to the appropriate directory:
BEA_HOME\WL_HOME\server\bin (Windows)
BEA_HOME/WL_HOME/server/bin (UNIX)
In both pathnames, BEA_HOME represents the directory in which you have installed your software and WL_HOME represents the wlserver_< version >.
Make sure that your environment is set up properly by entering the following command at the prompt:
setWLSenv.cmd (Windows)
setWLSenv.sh (UNIX)
Enter the following command at the prompt:
java -version
Configuring Java version:
http://download.oracle.com/docs/cd/E12840_01/wls/docs103/perform/WLSTuning.html
Setting Java Parameters for Starting WebLogic Server
... Java parameters must be specified whenever you start WebLogic Server. ... Oracle recommends that you incorporate the command into a [startup] script ...
If you used the Configuration Wizard to create your domain, the WebLogic startup scripts are located in the domain-name directory where you specified your domain. By default, this directory is BEA_HOME\user_projects\domain\domain-name, where BEA_HOME is the directory that contains the product installation, and domain-name is the name of the domain directory defined by the selected configuration template. ...
Change the value of the variable JAVA_HOME to the location of your JDK. For example:
set JAVA_HOME=C:\bea\jdk150_03
...
In my mind, #Override makes sense on methods that are overriding methods, not implementing methods.
So if you have an interface:
public interface MyInterface {
public void doSomething();
}
A class that implements that interface is below (MyClassA):
public MyClassA implements MyInterface {
public void doSomething() {
System.out.println("This is from MyClassA");
}
}
Then, the below class extends MyClassA and overrides doSomething, and so then I'd add the #Override annotation.
public MyClassB extends MyClassA implements MyInterface {
#Override
public void doSomething() {
System.out.println("This is from MyClassB");
}
}
I wouldn't do the below (whether or not it is permissable) in any case, since it breaks the idea about overriding something - you're implementing, not overriding the interface:
public MyClassA implements MyInterface {
#Override
public void doSomething() {
System.out.println("This is from MyClassA");
}
}
Can you override method in java without using annotations? Because eclipse doesn't support it if you use JRE6, you need to switch back to 5 to use #Override annotation. Will this method be overriden if I remove the annotation?
#Override public String toString() {
return name + " [" + genre + "]";
}
Can you override method in java
without using annotations?
Yes, the #Override annotation is not required to override a method.
Just by the act of having a method definition with the same method signature of an ancestor class is enough to override a method.
The #Override annotation is just a reminder to the compiler that says that the method definition is intended to override a method.
If a method that has a #Override does not actually override a method, the compiler will throw a compiler error -- the annotation serves as an additional compile-time check to see whether the method definition does indeed override a method.
Because eclipse doesn't support it if
you use JRE6, you need to switch back
to 5 to use #Override annotation.
I happen to use Eclipse targeting Java 6, and am able to use the #Override annotation, so I'm not quite sure what can be causing this. Annotations has been supported from Java 5, and has been more tightly integrated into the language since Java 6.
Edit
From Andreas_D's comment to the question:
smile - this just indicates, that the
current source level for your project
is < 1.5. This setting is pretty
independant from the JRE, you actually
can use JRE 1.6 together with source
level 1.4 - and I guess, that's what
happened.
This sure seems to be one way a compile error can occur!
The way to check if the "compiler compliance level" is set to something under Java 5 is,
Go to the Properties of the Java project in Eclipse
Then, go to the Java Compiler menu
Check that the Compiler Compliance Level is set to 1.5 or higher.
Edit
Regarding to Gandalf StormCrow's screenshot, appears that the compiler compliance level is set lower than JDK 1.5. Clicking on the Change project compliance and JRE to 1.5 quick fix should fix up the current situation.
The issue is, annotations were introduced in Java 5.
It appears that the Java project in Eclipse is currently set so the source code can only contain features which were introduced prior to Java 5, therefore disallowing the use of annotations.
The way to fix the situation is tell Eclipse that features from Java 5 can be used, by setting the compiler compliance level to 1.5 or higher.
#override is just a way of ensuring that if you change the contract (the method overriden) this method will not compile. Without it, it will be considered as a different fonction.
As for the JRE6, i'm not sure what you mean : annotations are supported.
Try the jdk ?
You do not need to use the #Override annotation. However, if you do and the method fails to override a method in a superclass then the compiler will return an error.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does Eclipse complain about #Override on interface methods?
I have some Java code that was written using Eclipse and the Java 6 SDK, so methods that implement an interface are annotated with #Override - an annotation that is legal in Java 6, but not in Java 5.
I'd like to compile the same code using the Java 5 SDK (javac on Mac OS X 10.5). Everything compiles and runs fine except for the #Override annotations. Is there any way I can get javac to ignore the #Override annotations for this project, or is the only solution to remove them all?
Unfortunately, the only way is to actually remove the annotations.
If you do want to have your code compile and run with Java 5, you should develop targeting Java 5. Otherwise, you might accidentally rely on a Java 6 specific SDK methods and such.
Apparently you can upgrade to Java 1.5 u21 and this will fix the problem:
Why is javac failing on #Override annotation
You can use JDK6 to compile 1.5 code. Use -bootclasspath, -target, and -source. Alternatively, I believe the Eclipse compiler treats #Override the same (this might be wrong!).
1.5 has finished its End of Service Life period, and I suggest letting it rot.
#Override is valid in java 5 -> http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/lang/Override.html
I recommend that you check your project's compiler settings in Eclipse, perhaps at Project -> Compiler -> Error/Warnings -> Annotations?
Java 6 is available for OS X. Check software update. When you have it, set it to be the default java version, and then compile.