I have following code:
class Key{
--Some Implementation
}
class A{
public void grpMap(ConcurrentMap<Key,List<Key> keyList){
--Some Implementation
}
}
public class B extends A{
--Edited
#Override -- [Made "O" capital case after kocko's reply]
public void grpMap(ConcurrentMap<Key,List<Key> keyList){
--Some Implementation
}
}
With above code i get following error in class B
The method grpMap(ConcurrentMap) of type B must override
or implement a supertype method
My problem is i can't change the way classes key, B and C are declared as these are legacy classes.
Any suggestion on how to get rid of this error?
EDIT---
JDK version used is 1.6.43
I am using eclipse which will auto generate annotations.
The annotation
#override
should be
#Override
↑
Also, check you Java version in the IDE - it should be 1.6, or newer, in order to get rid of the error.
Open Project properties -> Java compiler -> Set compliance level to 1.6 -> OK.
Related
We are having an interface with default methods and we implemented that interface in both Java and Kotlin classes and we provided the implementation for the non default methods.
When we run in debug mode (which doesn't have testCoverageEnabled = true) and the app works as expected. But when we run in different config with testCoverageEnabled = true, the app is crashing with below error
java.lang.NoSuchMethodError: No static method $$triggerInterfaceInit()V in class Lcom/ui/viewholders/CAViewContract$$CC; or its super classes (declaration of 'ui.viewholders.CAViewContract$$CC' appears in /data/app/SMCXbiLYvHb1Kk08Kee__g==/base.apk)
at home.c.CCFragment.<clinit>(Unknown Source:0)
at home.HomePageCardProvider.getFragment(HomePageCardProvider.java:17)
at home.HomeFragment.handleCardFragment(HomeFragment.java:172)
Note:
1. JaCoCo version: "0.8.0"
2. Operating system: Android with minSdk 21
If we change the minSdk to 24, with testCoverageEnabled = true itself, it is working. We are not able to figure out the exact problem.
This problem can occur if you want to invoke the default implementation of a method that hasn't a default implementation in the interface that your class explicitly implements it. (But has a default implementation in a base (parent, super) interface of that interface).
Example: Suppose these defenitions:
class A implements DerivedInterface /*, ...*/ {
#Override public void methodFromBaseInterface() {
DerivedInterface.super.methodFromBaseInterface(); // Error:
// NoSuchMethodError: No static method methodFromBaseInterface
}
// ...
}
interface DerivedInterface extends BaseInterface {
// ...
// `methodFromBaseInterface` hasn't overriden here.
}
interface BaseInterface {
default void methodFromBaseInterface() { /* ...*/ }
// ...
}
Then execute:
A a = new A();
a.methodFromBaseInterface(); // This cause above error!
And you get an error at mentioned point!
(Marginal note: You may need to define at least one method in DerivedInterface to avoid getting NoClassDefFoundError at runtime!)
This is similar to a bug! We used super keyword. Why expected static method?!! Another point is that the above code hasn't any problem and you can run it in any Java 8 compatible environment without any problem!
I think the problem is related to incomplete support of Java 8 language APIs in Android platform:
Android Studio 3.0 and later supports all Java 7 language features and a subset of Java 8 language features that vary by platform version.
Specially see Java 8 Language API and Compatible minSdkVersion table in that page:
java.lang.FunctionalInterface : API level 24 or higher.
Workarounds I found:
If you have access to the definition of DerivedInterface simply override methodFromBaseInterface and explicitly delegates it to its super interface:
interface DerivedInterface extends BaseInterface {
#Override default void methodFromBaseInterface() {
BaseInterface.super.methodFromBaseInterface();
}
// ...
}
Define a middle class that implements BaseInterface and derive A from it. Then run methodFromBaseInterface indirectly throw the middle class:
class MiddleClass /*extends B*/ implements BaseInterface {}
class A extends MiddleClass implements DerivedInterface {
#Override public void methodFromBaseInterface() {
super.methodFromBaseInterface(); // Indirectly from `MiddleClass`
}
// ...
}
Note: Uncomment /*extends B*/ if your A class previously has a super named B.
I have two inner classes and a method:
protected <A extends Obj1> void a(P<A> p)
{}
private static class P<Z extends Obj1>
{}
private static class Obj1
{}
It's compiling fine, but when I try in Eclipse Mars to change the method a's signature by giving it a second attribute this way
gives the following error:
Bound mismatch: The type A is not a valid substitute for the bounded
parameter <Z extends Test.Obj1> of the type Test.P<Z>
Now actually I have two questions about this. Why is this behavioural difference and what did I do wrong?
Strangely when I modify manually a to this:
protected <A extends Obj1> void a(P<? extends A> p)
{}
and try to change the signature the previously decribed manner I don't get that error. I have a feeling that this may be a bug either in Java or Eclipse, but don't really know where to start seaching. so I give you their versions too if it helps:
Eclipse Mars.2 (4.5.2)
Java 1.8.0.77
UPDATE:
So I've tried more different versions of Eclipse and Java 8, but the result is the same.
With this jdk code in ../java/lang/Override.java,
package java.lang;
import java.lang.annotation.*;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.SOURCE)
public #interface Override {
}
having just annotation declaration, java compiler is intelligent enough to detect error(compile time):
The method toString123() of type Example must override or implement a supertype method
in the below problem code.
package annotationtype;
public class Example {
#Override public String toString() {
return "Override the toString() of the superclass";
}
#Override public String toString123() {
return "Override the toString123() of the superclass";
}
public static void main(String[] args) {
}
}
Annotation declaration for Override just gets compiled to,
interface java.lang.Override extends java.lang.annotation.Annotation{
}
which is nothing more than an interface.
So,
How does interface java.lang.Override syntax help java compiler to detect above error at compile time?
The implementation that triggers the compile error doesn't lie in the annotation, it lies in the Java compiler.
If you want to write your own similar annotation processor, you would use the annotation processor API: http://docs.oracle.com/javase/7/docs/api/javax/annotation/processing/Processor.html
which is nothing more than an interface.
So,
How does interface java.lang.Override syntax help java compiler to
detect above error at compile time?
That's right. Override is nothing more than an interface. The actual work is done by the java compiler. How the compiler does this is not specified.
Here are some links that explain how to work with an AnnotationProcessor to implement something similar to #Override :
Processor Java doc
Java annotation processing tool
Code generation using AnnotationProcessor
Annotation Processor, generating a compiler error
Source code analysis using Java 6 API
Playing with Java annotation processing
As far as I understand the source compatibility and how you can easily show an example that would break source compatibility (change name of the method, remove method etc.), I am having a bit of a problem seeing how binary compatibility can be broken in practice. Does anyone have a simple example of preservation of source compatibility that would cause binary compatibility issues i.e. no code changes are required but recompilation is necesssary?
One example (and this is by no means the only one) would be if the signature of a method in a library changes, in a compatible way. For example, consider:
// Library.java v1
public class Library {
public static void print(String foo) {
System.out.println(foo);
}
}
// Client.java v1
public class Client {
public static void main(String[] args) {
Library.print("hello");
}
}
Compile and run:
$ javac Client.java Library.java
$ java Client
hello
Now change Library.java - note the type of the foo parameter:
// Library.java v2
public class Library {
public static void print(Object foo) {
System.out.println(foo);
}
}
Just recompile Library.java and try to rerun Client:
$ javac Library.java
$ java Client
Exception in thread "main" java.lang.NoSuchMethodError: Library.print(Ljava/lang/String;)V
at Client.main(Client.java:3)
First need to understand both compatibility.
Source compatibility - Program is source compatible with new version if Program can be compiled with that new version of code(library or api)
Binary compatibility - Program is binary compatible with new version of code if Program can be linked with that code without recompilation
Following link has more example for "Source compatible but Binary incompatible "
Specialising Return Types
Generalising Parameter Types
Primitive vs Wrapper Types
Read http://praitheesh.blogspot.com.au/2014/09/compatibility-and-api-evolution-in-java.html for more details.
If you import an interface with string constants.
(An anti-pattern in Java.)
Then the importing class copies the constants in the constant table, and uses those constants immediately. The import dependency to the interface then is missing.
When the string value of the constant in the interface is changed, the compiler does not see that it needs to recompile the class that will remain using the old value - as there is no longer an import to the interface.
The running is not broken, but the behaviour is - wrong value.
An example I met :
public class Class1 {
public void do() {
System.out.println("do!");
}
}
Client part :
public class Class2 {
public void callDo() {
Class1 c = new Class1();
c.do();
}
}
Now you change the return of do method :
public class Class1 {
public String do() {
System.out.println("do!");
return "done!";
}
}
If you run the client code without a recompilation you will get a NoSuchMethodError exception because the method signature has changed.
I have some code similar to this:
public class A<E> {
protected E value;
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
}
Then I have a class to extend this class, called B
public class B extends A<Boolean> {
// B has some other code, but doesn't edit the set/get methods
}
Then I compile these two classes to A.class, B.class and they're JARed.
Then I have the following code:
public class C {
// ... snip
B var = new B();
var.setValue(true);
if(var.getValue()) {
// etc
}
// ... snip
}
Attempting to compile this results in an error telling me that var.getValue returns as an Object. I KNOW it's a boolean, and when I include that C with the A/B java files and compile all at once, it works fine.
But when I compile A/B separately to C I get the issue that it believes var.getValue is an Object.
I've been reading about generics and Type Erasure, but I couldn't figure a way to solve it.
I'm trying to build A/B into a package that classes like C use, but if I have to cast all getValues then there is no point in generics.
Where am I going wrong?
(The actual code is in this github repo and the offending classes that are A and B are ModOption/ModBooleanOption. I don't have the C code in there, but it's obvious)
Edit: I'm using JavaSE6 compiling and obfuscating. The weird thing is that if I compile regularly and then try this example is also works fine. I'm beginning to suspect the obfuscator.
This problem is solved; I tested further and discovered that the obfuscator is breaking the generics, I have no idea how and don't care why. I'll be contacting the maintainers of it.
I was able to reproduce this only by setting my compiler to javac -source 1.4 while compiling C. If you're using an IDE, check the project that contains C to make sure your Java VM and source support is at 1.5 or above.