Patterns for using custom annotations

If you happen to create your own annotations, for instance to use with Java 6 Pluggable Annotation Processors, here are some patterns that I collected over time. Nothing new, nothing fancy, just putting everything into one place, with some proposed names.

annotation

Local-name annotation

Have your tools accept any annotation as long as its single name (without the fully-qualified prefix) is the expected one. For example com.acme.NotNull and net.companyname.NotNull would be considered the same. This enables to use your own annotations rather than the one packaged with the tools, in order not to depend on them.

Example in the Guice documentation:

Guice recognizes any @Nullable annotation, like edu.umd.cs.findbugs.annotations.Nullable or javax.annotation.Nullable.

Composed annotations

Annotations can have annotations as values. This allows for some complex and tree-like configurations, such as mappings from one format to another (from/to XML, JSon, RDBM).

Here is a rather simple example from the Hibernate annotations documentation:

@AssociationOverride( 
   name="propulsion", 
   joinColumns = @JoinColumn(name="fld_propulsion_fk") 
)

Multiplicity Wrapper

Java does not allow to use several times the same annotation on a given target.

To workaround that limitation, you can create a special annotation that expects a collection of values of the desired annotation type. For example, you’d like to apply several times the annotation @Advantage, so you create the Multiplicity Wrapper annotation: @Advantages (advantages = {@Advantage}).

Typically the multiplicity wrapper is named after the plural form of its enclosed elements.

Example in Hibernate annotations documentation:

@AttributeOverrides( {
   @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
   @AttributeOverride(name="name", column = @Column(name="bornCountryName") )
} )

annotationbis

Meta-inheritance

It is not possible in Java for annotations to derive from each other. To workaround that, the idea is simply to annotate your new annotation with the “super” annotation, which becomes a meta annotation.

Whenever you use your own annotation with a meta-annotation, the tools will actually consider it as if it was the meta-annotation.

This kind of meta-inheritance helps centralize the coupling to the external annotation in one place, while making the semantics of your own annotation more precise and meaningful.

Example in Spring annotations, with the annotation @Component, but also works with annotation @Qualifier:

Create your own custom stereotype annotation that is itself annotated with @Component:

@Component
public @interface MyComponent {
String value() default "";
}
@MyComponent
public class MyClass...

Another example in Guice, with the Binding Annotation:

@BindingAnnotation
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface PayPal {}

// Then use it
public class RealBillingService implements BillingService {
  @Inject
  public RealBillingService(@PayPal CreditCardProcessor processor,
      TransactionLog transactionLog) {
    ...
  }

Refactoring-proof values

Prefer values that are robust to refactorings rather than String litterals. MyClass.class is better than “com.acme.MyClass”, and enums are also encouraged.

Example in Hibernate annotations documentation:

@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=CompanyImpl.class )

And another example in the Guice documentation:

@ImplementedBy(PayPalCreditCardProcessor.class)

Configuration Precedence rule

Convention over Configuration and Sensible Defaults are two existing patterns that make a lot of sense with respect to using annotations as part of a configuration strategy. Having no need to annotate is way better than having to annotate for little value.

Annotations are by nature embedded in the code, hence they are not well-suited for every case of configuration, in particular when it comes to deployment-specific configuration. The solution is of course to mix annotations with other mechanisms and use each of them where they are more appropriate.

The following approach, based on precedence rule, and where each mechanism overrides the previous one, appears to work well:

Default value < Annotation < XML < programmatic configuration

For example, the default values could be suited for unit testing, while the annotation define all the stable configuration, leaving the other options to  configure for deployments at the various stages, like production or QA environments.

This principle is common (Spring, Java 6 EE among others), for example in JPA:

The concept of configuration by exception is central to the JPA specification.

Conclusion

This post is mostly a notepad of various patterns on how to use annotations, for instance when creating tools that process annotations, such as the Annotation Processing Tools in Java 5 and the Pluggable Annotations Processors in Java 6.

Don’t hesitate to contribute better patterns names, additional patterns and other examples of use.

EDIT: A related previous post, with a focus on how annotations can lead to coupling hence dependencies.

Pictures Creative Commons from Flicker, by ninaksimon and Iwan Gabovitch.

Read More

Manipulating things collectively

There is great power in being able to manipulate collective things as one single thing. It gives you simplicity, hence control. You can focus your attention on it and reason about it, even though behind the hood it is made of many parts. The composite thing is kept simple, therefore you can also deal with several of them at a time. This would not be possible if you had to deal with every part they are made of, because it would be overwhelming.

There exists many strategies to deal with collective things as if they were one single thing: statistics, multiple selection, groups, classifications and super-signs.

Statistics

Statistics is probably the most obvious way to deal with collective things, when the things can be expressed as numbers. Historically it has been used with great results in physics, thermodynamics in particular.

It is all about extracting a few macro properties that we can reason on instead of the whole set of data:

  • number of elements
  • mean, deviation, moments, percentiles, etc.
  • regression, clusters
  • total property: total weight, total volume, total price

Multiple selection

Many software applications enable you to select multiple elements at a time in order to apply one operation to each element:

Arman accumulation
Arman accumulation
  • When sending an email, you can select multiple addresses to send to
  • In a word processor, you can select several words, several paragraphs, or even all the document to copy, paste or apply formatting to each element
  • In a spreadsheet, you can select multiple rows or columns to apply operations to, and you can also repeat formula for each row or column

The selected elements can be of the same kind or not. However for multiple selection to be useful, they must share at least something in common: the capability of being copied or pasted, or the fact that they are specific for a particular user.

Functional programming and the three higher order functions map, fold and filter address very well how to apply operations collectively to many elements.

Groups

When multiple selections are often needed, you can create groups. We can consider a group to be a multiple selection made explicit. You create a group and you explicitly add elements to it. Common examples of groups:

  • Mailing lists are named groups of email addresses
  • Vectors in maths

As for multiple selection, the elements in a group must share something in common. For example, they must all have a price. Elements of various kinds can be grouped if they relate to something common, for example  the set of various data (name, address, phone number, preferred colour and date of birth) specific for a user is called a user profile.

A group is extensional. The elements in the group may or may not know they belong to a group.

Java packages are groups, and they are declared within the same file as the elements they refer to. Java classes also group fields and methods under one name.

The Composite pattern suggests to group objects that share the same interface into a Composite that also shares the same interface. The intent is to manipulate the collective set of objects as if it was one single object, i.e. without knowing it is collective.

Classification

You get control over multiple things if you just classify them. Given several flowers, if you classify them into categories, then you can talk about several flowers collectively without having to enumerate each of them: the category is a way to refer to several flowers with just one name.

Classifications enable intensional grouping. This means that groups are defined not by the set of their elements, but by a condition (predicate) to be satisfied. The condition can test for the category of something (is this animal a bird?), or test for its attribute (is this car red?).

Of course abstraction is one particular way to classify.

Java modifiers (private, public, abstract, interface etc.) classify Java elements, and can be used to refer collectively to them, as in “let’s generate the Javadoc for every public elements”.

Super signs

Super-sign
Super-sign

There are elements that exhibit a special property when considered together as a whole. For example, the ink dots on the paper can be seen as letters. Letters next to each other can be seen together as words, which again can be seen together as sentences, and then again up to the novel. Collective arrangements of multiple things that together exhibit a property are called super signs.

This phenomenon is related to emergence, and only exists for a given observer if he can recognize the super sign.

In science in general, we use models to account for the collective behavior of several elements, typically objects with measurable properties, and forces in action.

In a Java program, idioms and patterns can be considered super signs for those who know them.

Conclusion

Manipulating multiple things in a simple way really matters, it is a life saver.

In software development it is paramount because it is a lever you use to manage tons of data with no effort. The art is to find the way you think about collective things that reduces the most your effort.

I already mentioned this topic in previous posts: group together things that go together, don’t make things artificially different, and my definition of abstraction, because abstraction is an essential way to refer to different things in what they share in common.

Read More