Getting an instance of an annotation with default element values

Discussion in 'Java' started by Tom Anderson, May 10, 2009.

  1. Tom Anderson

    Tom Anderson Guest

    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

    --
    Can we fix it? Yes we can!
     
    Tom Anderson, May 10, 2009
    #1
    1. Advertising

  2. Tom Anderson

    Tom Anderson Guest

    Re: Getting an instance of an annotation with default elementvalues

    On Sun, 10 May 2009, Tom Anderson wrote:

    > 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

    --
    Can we fix it? Yes we can!
     
    Tom Anderson, May 10, 2009
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Raymond McCrae
    Replies:
    2
    Views:
    1,534
    Raymond McCrae
    Mar 3, 2004
  2. Ingo R. Homann
    Replies:
    0
    Views:
    566
    Ingo R. Homann
    Jul 26, 2005
  3. Christopher Benson-Manica

    Cyclic annotation element type

    Christopher Benson-Manica, Mar 15, 2007, in forum: Java
    Replies:
    1
    Views:
    437
    Mark Rafn
    Mar 16, 2007
  4. mani
    Replies:
    2
    Views:
    1,357
  5. mani
    Replies:
    1
    Views:
    297
Loading...

Share This Page