/ TYPESAFE

Type-safe annotations

I don’t like dynamically-typed languages - scripting languages in other terms. Of course, I’ve to live with Javascript because it’s so ubiquitous on the web, but given the chance, I’d switch to TypeScript in an instant. I was amazed by a demo of the Griffon GUI framework, and have read some pretty good stuff about the Spock testing framework, but I barely looked at them because they are based on Groovy, a scripting language (even if it offers optional enforcement of types via annotations). This is not some idiosyncrasy: static typing helps the compiler to find errors. For me, costs of creating and maintaining a safety net just to ensure type correctness instead of letting the compiler handle it overweights most possible benefits.

(I know this is a strong claim, and you’re welcome to challenge it if you’ve valid and factual arguments, but this is not the subject of this post.)

Even within statically-typed languages, not everything is unicorns and rainbows. In Java, one of such gray area is the String class. Before Java 5 and its enum feature, string constants were used as enumeration values. It was a weak design point, as two different constants could hold the same value.

// Pretty unsafe
public static final String CHOICE1 = "choice";
public static final String CHOICE2 = "choice";

String string = ...;
switch (string) {
    case CHOICE1: // do something
        break;
    case CHOICE2: // <- this will never get executed
        break;
}

enum finally set things right.

// Safe
public enum Choice {
    CHOICE1, CHOICE2
}

Choice choice = ...;
switch (choice) {
    case CHOICE1: // do something
        break;
    case CHOICE2: // do something else
        break;
}

Java 5 finally brought safety. Yet, even in Java 8, some design flaw persist. One of them is found in annotations. Nothing world-threatening, but enough to make me curse every time I have to write the following:

@SupressWarnings("deprecation")

That’s the way one has to write it: annotation do not accept enum types! The type-safe way would have been the following:

public enum SupressWarrningsType {
    Deprecation // And others
}

@SupressWarnings(SupressWarrningsType.Deprecation)

The downside of this approach is that only set enumeration values are accepted and they are set in stone. Using string, additional strings can be added at any time.

All is not lost, though. Even with the current state of things, one can benefit from type-safe annotations by just writing the following once per project (or in a company’s shared library):

@SuppressWarnings("deprecation")
public @interface SuppressWarningsDeprecation

And then simply use it like that:

@SuppressWarningsDeprecation

Note that only two element values are mandatory: unchecked and deprecation are required by the Java Language Specification. Additional options are available, depending on the provider. For Oracle, type javac -X and look for the -Xlint: option to list them.

For the laziest among us - including myself, I already created the library. The source code is hosted on Github and the binary on Bintray. It’s available under the friendly Apache License 2.0. Just add the following dependency:

<dependency>
  <groupId>ch.frankel</groupId>
  <artifactId>safe-annotations</artifactId>
  <version>1.0.0</version>
</dependency>

Whether you decide to use it or bake your own, you should strive to use type-safety when possible - that includes annotations.

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
Type-safe annotations
Share this