PROPOSAL: @OverrideAll annotation

Gabriel Belingueres belingueres at gmail.com
Fri Apr 3 08:23:59 PDT 2009


Hi,

Thanks for taking the time for reading this.

@Derek: My current approach for implementing this feature is to use
the reflection API to get the Methods and generate from there the
source file. (I'm not very experienced with the annotation API so this
may not be the shortest path to do it, but for a first try I think
it's OK.) However my mayor problem here is how to generate the
concrete class, for example let's say we have:

class A {
  public void method1() {};
  public void method2() {};
}
@OverrideAll
class B extends A {
  public void method1() {
    ...
  }
}

the easiest way I'm thinking I can generate the code is to create a
superclass class A_overrideAll which extends A with all methods
overridden, and then make B extends A_overrideAll. However, AFAIK I
can't modify the original source file (where class B is declared) so
how can now make it a subclass of A_overrideAll?

I choose an annotation instead of introducing a new keyword because it
was less intrusive than the other, that is, with a new keyword I would
need to modify the JLS, which is unnecessary because no language rule
changes. If further analysis reveal that a new keyword would be better
than an annotation, then it's fine with me.

@rssh: no compile time error should be thrown, instead, at runtime the
execution of a method should have a default behavior. In terms of the
language, the most basic behavior is do nothing/return default values,
but in general, the idea was to create a Null Object, meaning that the
client code could call methods that do nothing instead of checking for
!= null. (Hopefully you could avoid some NPEs with this idiom.)

Other idiom that apply for @OverrideAll are the AWT/Swing Listeners
and Adapters. There are lots of XXXListener interfaces with an
associated XXXAdapter abstract class that are used with a (sometimes
anonymous) class just to listen to particular events offered in the
listener interface.  With the @OverrideAll annotation, you could avoid
the declaration of the abstract adapter class.

Regards,
Gabriel

2009/4/3 Reinier Zwitserloot <reinier at zwitserloot.com>:
> What Derek said - this is not a good idea.
>
> rssh: The proposal specifically states that each non-overridden method
> is to be generated with an empty body, or if that isn't possible due
> to a return type, the default return for that type (0/false/0.0/'\0'/
> null).
>
>
>
>  --Reinier Zwitserloot
>
>
>
> On Apr 3, 2009, at 10:09, Derek Foster wrote:
>
>> My major problem with this proposal is that it doesn't seem to be
>> straightforward to generate the bodies of methods that have to
>> return something. Particularly for code such as implementations of
>> the Visitor pattern.
>>
>> Having un-overridden methods simply return null or zero is often not
>> the right thing to do.
>>
>> It's OK for generating methods that just take parameters, I suppose.
>>
>> Still, having annotations generate code or otherwise affect the
>> operation of a program is apparently a no-no per Sun's rules. If
>> something like this is going to happen, I think it needs a new
>> keyword or something rather than using an annotation.
>>
>> (Although, personally, I don't think it would be such a bad thing if
>> code generation via annotation existed, but were limited only to
>> certain annotations in a specific package duly designated by the
>> language implementors. Annotations have one nice quality that other
>> ways of extending the language don't: You can create new "keywords"
>> at will with no risk of breaking someone's perfectly-working code.
>> If they don't import the annotation, they won't need to be impacted
>> by it. I sort of wish there was an alternative to annotations (@@Foo
>> instead of @Foo?) which was explicitly for the purpose of telling
>> the compiler to generate boilerplate code of various types.
>> Decorators in Python sort of serve this purpose, for instance.)
>>
>> Derek
>>
>> -----Original Message-----
>>> From: rssh at gradsoft.com.ua
>>> Sent: Mar 31, 2009 10:02 AM
>>> To: Gabriel Belingueres <belingueres at gmail.com>
>>> Cc: coin-dev <coin-dev at openjdk.java.net>
>>> Subject: Re: PROPOSAL: @OverrideAll annotation
>>>
>>>> Hi,
>>>>
>>>> I've written a new feature that might be comfortable to use for
>>>> someone. All input is welcomed.
>>>>
>>>
>>> It-is possible to do near same with annotation API (create a
>>> superclass
>>> which will override all)
>>>
>>> But -- sometime we really need to say, that all methods 'mus be'
>>> overriden.  (For example - when implementing Proxy pattern).
>>> In such case class-level annotation '@OverrideAll'  which tell
>>> compiler
>>> to check, that all methods must be overriden -- brilliant idea.
>>>
>>>
>>>
>>>
>>>
>>>> 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