Static typing with marker interfaces versus annotations
Java’s static typing means we write more code for the compiler’s benefit, even though in many cases we could do without it. Partly it’s inertia. We use constructs we had to use when annotations were a pipe dream and something we looked for longingly in .NET. One such construct is the marker interface, whose variations I see everywhere. Put simply, a marker interface costs a lot of code for very little in return.
Quite recently, Lukáš Křečan and I were splitting a module into smaller pieces. To cut a long story short, we got stuck on what I’d call a marker interface. Pulling it out meant creating a third module solely to hold it.
public interface Persistable {
void setId(K key);
K getId();
}All this was so I could have the corresponding data access object, following a familiar idiom.
public abstract class AbstractDao<P extends Persistable, K> {
P load(K key);
void save(P persistable);
...
}The marker interface gave us a feeling of compile-time safety. I’m saying “feeling” deliberately, for reasons I’ll explain in a moment. With the Persistable interface and the corresponding AbstractDao definition, the compiler won’t let us use AbstractDao with a class that isn’t Persistable. In other words, the following code won’t compile.
AbstractDao dao = ...
dao.save(new Object());
That about covers the advantages of marker interfaces. Now the disadvantages. I’ve already touched on compile-time safety. If all your code is in one place and you compile it together every time, it’s a guarantee. Things get interesting when the classes implementing the marker interface are in a separate module and you bring it in as a compile-time dependency. I mean binary compatibility at runtime. You might compile against an interface with P load(K key) and run against a newer module with an additional method that AbstractDao uses. Without good integration tests you’re stuck, and the compiler won’t help.
Here’s what the alternative I hinted at earlier might look like. For simplicity I’ll skip the annotation definitions and show an object that uses them in place of the marker interface.
@Persistable
public class Person {
@Id
private Serializable id;
}
The Persistable annotation takes the place of the marker interface, although we could do without it too. The example probably needs little explanation beyond noting that AbstractDao reads the id instance variable through reflection. Annotations have several advantages.
- Less code
- I can apply an annotation to instance variables or to methods. The class can decide whether to expose id as part of its public interface, with a public setter or getter, or keep it private.
- Persistable and Id are needed to compile the class, but aren’t required at runtime. That’s handy if you use the class in another context. We used it on the client as well, where persistent storage made no sense. A marker interface might have dragged in unwanted dependencies that we could avoid only by making a special module for it.
- We don’t have to give up compile-time safety altogether. We can implement a custom annotation processor to check that a class annotated with Persistable has an instance variable or getter or setter annotated with Id. On that subject, here’s Jaroslav Tulach’s talk on API paradoxes.
I wanted to point out a relic that survives unnecessarily in the codebases of many Java projects, and the alternative that annotations give us. Annotations relax strict static typing and save a great deal of code.
Update
I put together an example showing how annotations and interfaces behave differently at runtime. An annotation doesn’t have to be on the classpath if you don’t use it. An interface class always has to be there. This lets us use a class in different contexts without pulling in unwanted dependencies.
Related articles
Related CZ Podcast episodes
- #3 · Java 6 SE, Vývoj webových aplikací
Dagi and Filemon discuss Java 6 and web application frameworks. · Czech audio
- #1 · Vývojová prostředí v Javě
The first CZ Podcast episode looks at Java development environments. · Czech audio