How to invalidate a super-interface method - java

First I want to clarify that I don't have any real business requirements for that, It's a purely theoretical question.
Assuming that we have these two Interfaces :
public interface SuperInterface {
void doSuperStaff();
void doComStaff();
}
public interface SubInterface extends SuperInterface {
// Something here to invalidate doSuperStaff()
}
Is there any way to invalidate / disable the doSuperStaff() for all classes that implement the SubInterface? So only the classes that directly implement SuperInterface can use that method and override it.
NB: I know that we can resolve that in a conceptual manner, but I want to know if there is a way to make that possible technically: using annotations for example ( like the #Deprectaed, which only instructs the compiler that the method is deprecated.)....

Limited, but the following helps a bit.
public interface SubInterface extends SuperInterface {
#Deprecated
void doSuperStaff();
}
Or even
public interface SubInterface extends SuperInterface {
#Deprecated
default void doSuperStaff() {
throw new UnsupportedOperationException("...");
}
}

UPDATE If it's purely theoritical and you are not stuck with a legacy design you can't change, then it's bad idea to try and remove Super interface methods on a sub-interface (or class). It's indicative the design is wrong (Dog -> Animal (useLegs, hasBody), Owl -> Animal (useLegs-??, hasBody). useLegs in this case doesn't belong in Animal.
But if you have legacy code you want to remove it from, and enforce it with Compile-time errors, this approach will work.
You can remove the method with Aspects. Create a pointcut that triggers when the method is called, add Around Advice which is triggered on that pointcut and throws an unsupported operation exception rather than proceed.
With AspectJ Spring syntax it looks something like this (Syntax details here -http://www.eclipse.org/aspectj/doc/next/adk15notebook/ataspectj-pcadvice.html)
#Around("call(* SubInterface.doSuperStuff())")
public Object removeMethod(ProceedingJoinPoint thisJoinPoint) {
throw new UnsupportedOperationException("...");
}
You can also use the native AspectJ language and it's Eclipse plugin to have Eclipse (or your build) show a compile error on the call site if any code attempts to use it. I think that would look something like this (https://eclipse.org/aspectj/doc/released/adk15notebook/annotations-decp.html)
declare error : call(* SubInterface.doSuperStuff())
: "Method doSuperStuff removed from SubInterface";

As you said the answer is NO.
This is simple illustration, why this feature cannot be added.
Firstly the meaning of Interface in Java is Behavior
Suppose if I create a new interface AdavancedComparable<T> which extends java.lang.Comparable<T> and if I deprecate the public int compareTo(T o); in my AdvancedComparable interface and add my own method like advancedCompare(T o);
public interface AdavancedComparable<T> extends Comparable<T> {
// invalidate/deprecate for compareTo method using requested feature somehow
public int advancedCompare(T o);
}
Any method which is accepting Comparable<T> type parameter will also accept AdvancedComparable<T> type parameter, but when the method tries to call compareTo, it will break if the feature you asked is implemented.
Suppose if compiler updated to recognize this issues and made to throw compile time error, that's fine, but it also has to support the legacy code. Remember the Generics case, many classes which altered to support generic type, supports Raw type too (Like List, Class etc). Just to support legacy code. But in our case it is difficult to do so, I feel.

Can not you use super Abstract Class which would implement doSuperStuff() and other concrete class could extend it to override other method.

You can always cast a subtype to a supertype, and invoke methods in the supertype.
However, there is a way to prevent overriding --
public interface SuperInterface
Object doSuperStaff(); // return value doesn't matter, can be null
public interface SubInterface extends SuperInterface
default Foo doSuperStaff() { ... }
Here, Foo is a package-private type. Subclasses of SubInterface (in different packages) have no way to override this method, because they can't access Foo.
It's also possible to use a private class Foo there.

Related

Why in both the code snippets '#Override' annotation work properly?

Although the class B implements the interface A, it does not provide the implementation of the method show(). Again, D extends C but in class D the implementation of displayNothing() is the same as the implementation of displayNothing() method in its superclass C.
But in both the cases #Override annotation work properly, why?
//code snippet 1
interface A
{
void show();
}
abstract class B implements A
{
#Override
abstract public void show();
}
//code snippet 2
class C
{
void displayNothing()
{
}
}
class D extends C
{
#Override
void displayNothing()
{
}
}
#Override is only bothered with whether your function name along with the data type is just the same as the method in your super class (with no Alphabetical error). In your case it is the same.Try changing void as int in your class D. It shows a compilation error. As for your abstract class method, it needn't define anything coz the name says it all, it is abstract.
The purpose of the #Override annotation is to prevent bugs. It's presence informs the compiler that there must be a inherited method with that same exact signature that this class is overriding. It does matter if there is an implementation of a method or not.
It is perfectly legal to not include an #Override annotation. The potential problem you might encounter, though, is if you accidentally had a typo or inadvertently changed the method signature, you would be overloading the method, not overriding it. The compiler would not be able to catch this bug. The program might crash or it might even run, but run incorrectly.
Because this might be a difficult bug to spot, especially with methods containing several parameters, the #Override annotation was created. The #Override annotation informs the compiler that this method is an override, not an overload and if the compiler fails to find a method to override, return a compilation error.
All these methods would compile and could be run but none would override the displayNothing() method.
void displayNothng();
void displaynothing();
void displayNothing(String value);
The #Override annotation "works properly" in both presented cases, because java reuses this annotation for interfaces and classes, even if you feel that the first and the second snippet of code do something different it's just not as important to introduce separated keywords/annotations to differentiate between overriding from an interface and from a class. Even an abstract class doesn't change things here.
The #Override indicates that a given method has a compatible representation in the super class/interface, it's used to ensure we don't have any syntax issue in the definition.
B is abstract. Abstract classes don’t need to provide implementations. If an abstract class doesn’t implement a required method it doesn’t matter. If a class isn’t abstract, then implementations of all abstract methods need to be there.
D provides an override of the displayNothing method in C. The compiler doesn’t check whether the overridden version is the same as the overriding version, and it doesn't care if the overriding implementation is empty. All the Override annotation does is confirm that there is a method with the same signature above the annotated one in the class hierarchy.
The purpose of the annotation is to confirm that you’re actually overriding an existing method and haven’t introduced a bug by misspelling the method name or otherwise not matching the signature of the method you mean to override. See the Java Language Specification, 9.6.4.4, where it says:
Programmers occasionally overload a method declaration when they mean to override it, leading to subtle problems. The annotation type Override supports early detection of such problems.
The classic example concerns the equals method. Programmers write the following in class Foo:
public boolean equals(Foo that) { ... }
when they mean to write:
public boolean equals(Object that) { ... }
This is perfectly legal, but class Foo inherits the equals implementation from Object, which can cause some very subtle bugs.
(Be aware when I describe what #Override does I'm skipping over override-equivalence because you didn't ask about it and there are already perfectly good answers that cover that.

Naming methods to generic arguments

I am going over some code and I am adding some interfaces so i can make sure all the classes follow the same basic guidelines.
Now I have an interface called Uni < T > which takes exactly one generic argument.
Say I have a class which implements Uni< Foo > then I would like that class to have this method public foo getFoo(){};
Is there any way to add this method to the interface? I would prefer if i could do something like this in my interface public T getT(); and the second T gets replaced by the generic argument.
I can't just call it "get" because I would like some classes to implement multiple versions of Uni. public Example implements Uni<Foo1>,Uni<Foo2>
I know I can give the function 'get' an argument Foo or Class but I'd rather not so I thought I'd ask here.
(I would also mess up the naming convection if i did this)
No, not possible. And as generics in Java are implemented via erasure (i.e. dropped by the compiler), you will also not be able to implement multiple versions in a single class.
its not possible with java but you can do it like this
public interface example<T> {
public void yourmethod(T object);
}
make the interface according to the generic type you want.

#Override annotation in Java

When I implement an Interface in Java, for instance:
public interface IColumnHeader {
public String getHeaderValue();
public String findColumnValueFromHeaderValue(String parseFrom);
}
the following enum implements the above interface:
public enum FileColumnDwellTime implements IColumnHeader {
REPORTER_USER_ID {
#Override
public String getHeaderValue() {
return "reporter_user_id";
}
#Override
public String findColumnValueFromHeaderValue(String parseFrom) {
return parseFrom;
}
};
}
Why does implementing an interface in Java and implementing the methods from the interface introduce the #Override annotation. Isn't that a total misnomer?
Shouldn't that annotation actually be called something like "#Implementation"?
The #Override annotation would be more apt for subclasses that actually override superclass methods that are predefined. In the case of simply implementing a method from an interface, there is no actual overriding being done.
Am I right?
(If I were the JLS writers for Java 9, I would have a new annotation called #Implementation that would "subclass" the #Override annotation, in the case of implementing methods from interfaces, and the like.)
Taking a look at the JLS, it just seems to be how it's defined. I'm looking at JLS 8, not sure if the section I'm going to quote was different in earlier versions (although I highly doubt it will, since interface interactions shouldn't have changed). From section 8.4.8.1:
An instance method mC declared in or inherited by class C, overrides from C another
method mI declared in an interface I, iff all of the following are true:
I is a superinterface of C.
mI is an abstract or default method.
The signature of mC is a subsignature (§8.4.2) of the signature of mI.
So at least based on this, the #Override annotation makes sense, since it denotes an instance method that overrides a method declared in an interface, based on the definitions in the JLS.
Unfortunately, I can't give an authoritative answer as to why this is called overriding, but here's sort of how it works in my head:
If you inherit an abstract method (like one in an interface), your class implicitly contains the signature for that method in its body. When you implement the method corresponding to that signature, you replace (and thus override) the inherited abstract method signature with one corresponding to a concrete implementation. So it makes sense to have #Override, right?
In addition, this way #Override would work for overridden methods regardless of whether they were technically an implementation or "truly" overridden. And why make more work for yourself (and compiler designers) than you have to?
I know that that's a rather bad view of how inheritance works, but I hope it makes sense.
So I guess in the end, I would say you are wrong. There is overriding being done. But I wouldn't say it's immediately obvious why that is the case. Interesting question!

Return error in the implementation of an interface using generics

I have an interface defining a method like this :
public List<IA> myMethod();
with IA another interface.
In my implementation of the method I declare :
public List<A> myMethod() { /* Do something */ }
with A a class implementing IA.
However, Java (or eclipse) doesn't like it and forces me to have List<IA> in my implementation of myMethod. As A implements IA, I don't see why this casts an error.
So here are the questions :
Why do I have this error ?
Which is the best way to avoid it (knowing I do not have much liberty on the code) ?
You have this error because it's unsafe from a type-safety point of view. Consider:
// Interface declaration
List<Fruit> myMethod();
// Implemented by...
public List<Banana> myMethod() {
return new ArrayList<Banana>();
}
// Called as:
List<Fruit> fruit = foo.myMethod();
fruit.add(new Apple());
Do you really want to be able to add an Apple to an ArrayList<Banana>?
You can fix this by changing the declaration to
List<? extends IA> myMethod();
That will prevent calls from adding to the list (or setting values on it).
If you can't change the interface, you will have to return a List<IA> from your method, I'm afraid.
See the Java Generics FAQ for much more information.
Because the contract defined in interface says that myMethod must return a List of type IA.
As a thumb rule: Base class reference can be used anywhere, when derived class object is required. but vice-versa is NOT true. and that's the error.
To avoid these error: always follow the interface (contract) as it is.

Can unchecked warnings be avoided when overriding a method with raw type parameters?

I am extending a class defined in a library which I cannot change:
public class Parent
{
public void init(Map properties) { ... }
}
If I am defining a class 'Child' that extends Parent and I am using Java 6 with generics, what is the best way to override the init method without getting unchecked warnings?
public class Child extends Parent
{
// warning: Map is a raw type. References to generic type Map<K,V> should be parameterized
public void init(Map properties) { }
}
If I add generic parameters, I get:
// error: The method init(Map<Object,Object>) of type Child has the same erasure as init(Map) of type Parent but does not override it
public void init(Map<Object,Object>) { ... }
// same error
public void init(Map<? extends Object,? extends Object>) { ... }
// same error
public void init(Map<?,?>) { ... }
This error occurs regardless of whether I use a specific type, a bounded wildcard, or an unbounded wildcard. Is there a correct or idiomatic way to override a non-generic method without warnings, and without using #SuppressWarnings("unchecked")?
Yes, you have to declare the overriding method with the same signature as in the parent class, without adding any generics info.
I think your best bet is to add the #SuppressWarnings("unchecked") annotation to the raw-type parameter, not the method, so you won't squelch other generics warnings you might have in your own code.
Short answer: no way to do that.
Unsatisfying answer: disable the (specific) warnings in your IDE/build.xml.
If you cannot change the library, alas, you have to stick with non-generic methods.
The problem is that, despite after type erasure both init() have the same signature, they may in fact be different methods -- or the same(*). Compiler cannot tell should it do override or overload, so it's prohibited.
(*)
Suppose the library developer meant init(Map<String,Integer>). Now you are implementing init(Map<String,String>). This is overloading, and two methods should exist in the vtable of Child class.
But what if the library developer meant init(Map<String,String>)? Then it's overriding, and your method should replace original init in Child class, and there would be only one method in the vtable of Child.
P.S. I hate how Generics implemented in Java :-(
I think above answer meant to say #SuppressWarnings("rawtypes") instead.
You have to declare the method with the same signature as the parent, and therefore you will get warnings when you compile. You can suppress them with #SuppressWarnings("unchecked")
The reason why there is no way to get rid of this is that the warnings are there to let you know that it's possible to create Collections with invalid types in them. The warnings should only go away when all code that might allow that has been removed. Since you are inheriting from a non-generic class it will always be possible to create a Collection with invalid contents.

Categories

Resources