Navigation

RSS 2.0 New Entries Syndication Feed Atom 0.3 New Entries Syndication Feed

Show blog menu v

 

General

Use it

Documentation

Support

Sibling projects

RIFE powered

Valid XHTML 1.0 Transitional

Valid CSS!

Blogs : Archives

< RIFE 1.4 released   Valid use-cases for stateful web components? >
Are single element annotations a disaster waiting to happen?

I'm looking into making RIFE easier to setup through annotations. The plan is quite logically to mimic what the current builders (XML, Java, Groovy) do, but then with annotations.

I'm a bit stuck though with designing them, and this is mainly due to single element annotations. It feels to me that instead of relying on a fixed "value" element name, Java should automatically detect if there's a single element that hasn't got a default and use that.

Update: this issue is also under discussion at TheServerSide.

The problem

Why? Because "value" gives a conflicting semantic message when your annotation evolves and receives additional elements.

Consider this annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface Param
{
    String value();
}

Initially, it might not seem to be a problem, since everybody uses it like this:

@Param("theName")
public class Element1 extends Element
{}

However, imagine that several months down the road, you decide that this annotation really should allow people to declare an array of default values. So you change its declaration to:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface Param
{
    String value();
    String[] defaultValues() default {};
}

All of a sudden, none of the existing uses of the annotation are valid anymore, since as soon as there's more than one element present, you need to explicitly name them. All your users now have to shift through all their exisiting code to change the annotations and add an explicit "value" name:

@Param(value="theName")
public class Element1 extends Element
{}

Now this is a big problem, since not only does this impose an unnecessary burden on your users, they also didn't actually declare the value of the parameter but its name instead. The meaning of the explicitly named element is completely wrong. This makes code very difficult to read and just asks for hidden bugs and misinterpretations.

The only option that I see at the moment is to never use single element annotations. This sadly makes usability lower when annotations initially only have a single element:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface Param
{
    String name();
}
 
@Param(name="theName")
public class Element1 extends Element
{}

The solution

Java should simply detect when an annotation has a single element that has no default value and allow that one to be used without an explicit name.

For example:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface Param
{
    String name();
    String[] defaultValues() default {};
}

This always people to use them in any of the following fashions:

@Param("theName")
public class Element1 extends Element
{}
 
@Param(name = "theName", defaultValues = {"one", "two"})
public class Element2 extends Element
{}
 
@Param("theName", defaultValues = {"one", "two"})
public class Element3 extends Element
{}

Using this approach, people can easily write semantically correct single element annotations without having to give in on usability and still ensuring that they continue to be semantically correct when their project evolves over time.

posted by Geert Bevin in Java on Mar 4, 2006 11:47 AM : 5 comments [permalink]
 

Comments

Re: Are single element annotations a disaster waiting to happen?
I don't get it.

If the new annotation type member has a default value, everything works fine:

@Param("foo")

will work with both

@interface Param {
String value();
}

and

@interface Param {
String value();
String defaultValue() default "";
}

Now, if you add an annotation type member that doesn't have a default:

@interface Param {
String value();
String defaultValue();
}

then obviously,

@Param("foo")

will no longer work since both value() and defaultValue() need to receive a value.

However, when you do that, you are breaking existing code anyway.

What's the big deal?!?

--
Cedric
Re: Are single element annotations a disaster waiting to happen?
Cedric, instead of being forced to use 'value' as the single element name, you can from the beginning give everything a semantically correct name which continues to be used for the entire life of the annotation. Now, everybody is forced to use 'value' merely for the sake of being able to use annotation declarations without a specific element name.
Re: Are single element annotations a disaster waiting to happen?
I agree that having the element name as value() for single element annotations is confusing when the annotation is extended. But for most use cases, if you add additional elements to a single element annotation, wouldn't it be a natural (limited) extension of the annotation. For example,

say you have something like
public @interface Transactional {
boolean value() default true;
}
you could use @Transactional (or @Transactinal(true)), then you will mostly want to add a timeout, for which you could obviously add a default also

public @interface Transactional {
boolean value() default true;
int timeout() default 30;
}

That should still help.

If the additional elements added are not natural to the original annotation, I think a new annotation should be created.

But in general I agree that having value as a single element name can cause some ugliness in using the annotation should the annotation be extended with non-default elements.
Re: Are single element annotations a disaster waiting to happen?
One can only wonder why the hardcoded name "value" was used, and not an annotation on the annotation field:

@interface something {
@NameCanBeOmitted // TODO: name needs work!
int other();
}

Re: Are single element annotations a disaster waiting to happen?
Yeah, I thought along those lines too, either an annotation or some clear structure guidelines (like the first value without a default) or much better than a fixed name. This really doesn't belong on a language spec.

Add a new comment

Comments on this blog entry have been closed.

< RIFE 1.4 released   Valid use-cases for stateful web components? >
 
 
 
Google
rifers.org web