PROPOSAL: @OverrideAll annotation

Gabriel Belingueres belingueres at gmail.com
Tue Mar 31 06:49:20 PDT 2009


Hi,

I've written a new feature that might be comfortable to use for
someone. All input is welcomed.

Regards,
Gabriel

PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0

AUTHOR(S): Gabriel Belingueres

OVERVIEW

Add an @OverrideAll annotation to allow a class to override all
inherited methods with a trivial implementation. The resulting class
then could be used as the basis for a Null Object pattern (or even a
basic Mock object.)


FEATURE SUMMARY:

The proposed @OverrideAll annotation will allow the class to override
all methods (from its superclasses and implemented interfaces) with a
trivial body, but the defined class can choose to implement specific
methods, replacing those that would be produced automatically by the
annotation.


MAJOR ADVANTAGE:

Less coding for implementing Null Objects, or simple tests.


MAJOR BENEFIT:

Let the compiler implement all uninteresting, non relevant behavior by
automatically providing with a trivial implementation of the inherited
methods.


MAJOR DISADVANTAGE:

Might be a cause of NullPointerException if not used judiciously.


ALTERNATIVES:

Implement all uninteresting methods by yourself by providing yourself
a trivial implementation (though actually popular IDEs can do this
automatically for you already.)

EXAMPLES

Given:

class B {}

public class A implements I1, I2 {

  public static final int VAR = 1;

  private B b;

  public static Integer getSome() {
    return VAR;
  }

  public A() {
  }

  public A(B b) {
    this.b=b;
  }

  public B getB() {
    return b;
  }

  public void setB(B b) {
    this.b=b;
  }

  protected void doProtected() { ... }

  private void doPrivate() { ... }

  A someNewA() { ... }

  public synchronized void someSynchronized() {
  }

}

then:

@OverrideAll
public class NullA extends A {
}

is equivalent to declare:

public class NullA extends A {

  public NullA() {}

  public NullA(B b) {
    super(b);
  }

  public B getB() {
    return null;
  }

  public void setB(B b) {
  }

  protected void doProtected() {
   // empty
  }

  A someNewA() {
   return null;
  }

  public synchronized void someSynchronized() {
    // empty
  }

}

You may not want the default trivial implementation in some methods,
then you override them as usual:

@OverrideAll
public class NullA extends A {

  @Override
  public B getB() {
    return new B();
  }

  @Override
  public synchronized void someSynchronized() {
    System.out.println("overridden");
  }

}

EXAMPLE 2

Implement a trivial Collection interface just to test that adding
elements will increase the collection size:

Currently:

public class SomeCollection<E> implements Collection<E> {

  private int counter;

  @Override
  public boolean add(E arg0) {
    counter++;
    return true;
  }

  @Override
  public boolean addAll(Collection<? extends E> c) {
    counter += c.size();
    return true;
  }

  @Override
  public void clear() {
  }

  @Override
  public boolean contains(Object arg0) {
    return false;
  }

  @Override
  public boolean containsAll(Collection<?> arg0) {
    return false;
  }

  @Override
  public boolean isEmpty() {
    return false;
  }

  @Override
  public Iterator<E> iterator() {
    return null;
  }

  @Override
  public boolean remove(Object arg0) {
    return false;
  }

  @Override
  public boolean removeAll(Collection<?> arg0) {
    return false;
  }

  @Override
  public boolean retainAll(Collection<?> arg0) {
    return false;
  }

  @Override
  public int size() {
    return counter;
  }

  @Override
  public Object[] toArray() {
    return null;
  }

  @Override
  public <T> T[] toArray(T[] arg0) {
    return null;
  }

}

With the annotation:

@OverrideAll
public class SomeCollection<E> implements Collection<E> {

  private int counter;

  @Override
  public boolean add(E arg0) {
    counter++;
    return true;
  }

  @Override
  public boolean addAll(Collection<? extends E> c) {
    counter += c.size();
    return true;
  }


  @Override
  public int size() {
    return counter;
  }

}


DETAILS


SPECIFICATION:

A preliminary specification follows:

As this feature is proposed as an annotation for code generation, no
changes to the current JLSv3 are needed.

The annotation will generate "trivial" overridden implementations for
all methods not specified in the class, for each superclass in the
hierarchy (except Object) and implemented interface.

- Static methods, private methods, final methods, constructors and
methods from class Object should never be generated.
- If some superclass (except Object) has already overridden some
Object class methods, then do NOT generate an empty overridden method
(to reuse current behavior.) (for example, if some superclass already
override toString(), equals() or hashCode().)

- OPTIONAL: add a parameter to the @OverrideAll annotation to indicate
if @Deprecated methods should not be implemented.

Trivial implementation for generated methods:

- Methods returning void will have an empty body. (OPTIONAL: add a
parameter to the @OverrideAll annotation to indicate that it should
throw UnsupportedOperationException instead)
- Methods returning a primitive type will have a body returning the
same default value that would have for uninitialized instance
variables. (JLS section 4.12.5.)
- Methods returning a reference type will "return null;". (JLS section 4.12.5.)
- The method will never return a covariant return type (because in
case of implementing a Null object, it should be undistinguished from
the common case)
- Methods that throws checked exceptions can be modified to delete the
throws clause. (ie. the trivial implementation should not throw
checked exceptions)
- Synchronized methods should retain that attribute.


COMPILATION:

Compilation should proceed as usual, except that the annotation
processor would generate the code when it encounters an annotated
class.

No changes to the class file format are needed.


TESTING

Test cases should be done, including testing with classes implementing
several interfaces, classes with generics, inner classes, etc.


LIBRARY SUPPORT:

No, except creating the new annotation.


REFLECTIVE APIS:

No changes foreseen.


OTHER CHANGES:

Output of javadoc tool.


MIGRATION:

Just add the annotation to class level, and erase your trivially
implemented overridden methods.


COMPATIBILITY

BREAKING CHANGES:
All existing programs remain valid.

EXISTING PROGRAMS:
The semantics of existing class files and legal source files are
unchanged by this feature.


REFERENCES

EXISTING BUGS:

None that I know about.

URL FOR PROTOTYPE:

None at this time.



More information about the coin-dev mailing list