Getting an instance of an annotation with default element values

T

Tom Anderson

Right,

I have defined an annotation like so:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ParallelConfiguration {
public int numThreads() default 3;
}

Elsewhere in my code, i do something like this:

Class someClass;
ParallelConfiguration conf = someClass.getAnnotation(ParallelConfiguration.class);
int numThreads = conf.numThreads();

Obviously, if someClass lacks a ParallelConfiguration, this won't work. At
present, my code actually does:

Class someClass;
ParallelConfiguration conf = someClass.getAnnotation(ParallelConfiguration.class);
int numThreads;
if (conf != null) numThreads = conf.numThreads();
else numThreads = DEFAULT_NUMBER_OF_THREADS;

But this is really stupid. I already have a default for numThreads
defined, in the ParallelConfiguration annotation itself; defining another
default elsewhere is dreadful. I could refactor a little bit to make both
bits of code refer to the same constant:

public @interface ParallelConfiguration {
public static final int DEFAULT_NUM_THREADS = 3;

public int numThreads() default DEFAULT_NUM_THREADS;
}

if (conf != null) numThreads = conf.numThreads();
else numThreads = ParallelConfiguration.DEFAULT_NUM_THREADS;

And that's better, but it's still stupid: it's not making use of the fact
that the annotation has a natural way of expressing defaults. This comes
back to haunt me when i start to add more things to the annotation:

public @interface ParallelConfiguration {
public static final int DEFAULT_NUM_THREADS = 3;
public static final String DEFAULT_THREAD_NAME_PREFIX = "worker";

public int numThreads() default DEFAULT_NUM_THREADS;
public String threadNamePrefix() default DEFAULT_THREAD_NAME_PREFIX;
public int threadPriority() default Thread.NORM_PRIORITY;
}

When my client code starts to look really vile:

int numThreads;
String threadNamePrefix;
int threadPriority;
if (conf != null) {
numThreads = conf.numThreads();
threadNamePrefix = conf.threadNamePrefic();
threadPriority = conf.threadPriority();
}
else {
// all this just duplicates the default definitions!
numThreads = ParallelConfiguration.DEFAULT_NUM_THREADS;
threadNamePrefix = ParallelConfiguration.DEFAULT_THREAD_NAME_PREFIX;
threadPriority = Thread.NORM_PRIORITY;
}

What i really want to do is something like this:

if (conf == null) conf = getDefaultInstance(ParallelConfiguration.class);
int numThreads = conf.numThreads();
String threadNamePrefix = conf.threadNamePrefic();
int threadPriority = conf.threadPriority();

The problem is that i have no idea how to do the getDefaultInstance bit.
Is there a standard way to do this?

The best i've come up with is to apply some sort of trickery, like this:

public @interface ParallelConfiguration {

@ParallelConfiguration
public static class DefaultBearer {}

public static final ParallelConfiguration DEFAULT = DefaultBearer.class.getAnnotation(ParallelConfiguration.class);

public int numThreads() default 3;
}

Which works (well, compiles, and looks like it should work), and does what
i want, but is pure evil. I could get rid of the DefaultBearer class by
applying the annotation to itself, but that doesn't exactly reduce the
level of evil!

Any thoughts?

tom
 
T

Tom Anderson

I could get rid of the DefaultBearer class by applying the annotation to
itself, but that doesn't exactly reduce the level of evil!

Or not - that compiles, but dies with a NoClassDefFoundError when the JVM
tries to load the annotation class. Specifically, it seems constructs of
the form:

@Foo
public @interface Foo {
public Foo FOO = Foo.class.getAnnotation(Foo.class);
}

Won't work. Although this:

@Foo
public @interface Foo {
public Foo FOO = FooAccomplice.FOO;
}

class FooAccomplice {
public Foo FOO = Foo.class.getAnnotation(Foo.class);
}

Does. Huh. And you can even make the accomplice an inner class of the
annotation. I suppose that does make sense from a classloading point of
view, but it's still mildly baffling.

tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top