views:

98

answers:

3

In my project, I have defined the an annotation similar to the following:
(Omitting @Retention, @Target for brevity)

public @interface DecaysTo {
    String[] value();
}

Since originally writing it, our needs have changed and I have now defined an enum that I want to be able to use in place of the string:

public enum Particle {
    ELECTRON,
    ANTIELECTRON,
    NEUTRINO,
    ANTINEUTRINO,
    ...
}

To avoid updating every instance of this annotation, I would like to be able to construct the annotation with either a String or a member of enum Particle without having update every instance of this annotation to specify the attribute. However, since we define the annotation's attributes, and not constructors, it seems impossible to overload it.

// In a perfect world, either of these would work ...
public @interface DecaysTo {
    String[] value();
    Particle[] value();
}

@DecaysTo({"Electron", ...})
@DecaysTo({Particle.ELECTRON, ...})

// without having to explicitly specify which attribute to set:
public @interface DecaysTo {
    String[] stringVals();
    Particle[] enumVals();
}

@DecaysTo(stringVals = {"Electron", ...})
@DecaysTo(enumVals = {Particle.ELECTRON, ...})

Also attempted:

public @interface DecaysTo {
    Object[] value();
}

Is there any way to do this that doesn't involve going back through and editing an enormous amount of code?

+2  A: 

You could just deprecate this annotation and introduce a new one (say @DecaysToParticle) for new code.

Yishai
+4  A: 

The best way is to find and replace all previous annotations. You don't want old design lingering around. Keep a clean code base throughout refactorings.

Suppose you don't want to do that, or you don't own the code that use the annotation, you should keep two annotation types. in your annotation processing code, you look for both, and if the old one is used, convert it to the new one.

DecaysToV2 anno = getAnnotation( DecaysToV2.class );
if(anno = null)
{
    DecaysTo anno_old = getAnnotation( DecaysTo.class );
    if(anno_old!=null)
       anno = convert (anno_old);
}

DecaysToV2 is just an interface which you can impl:

DecaysToV2 convert( DecaysTo old )
{
    DecaysToV2Impl impl = new DecaysToV2Impl();
    impl.value = ...
    return impl;
}
static class DecaysToV2Impl implements DecaysToV2
{
    Particle[] value;
    public Particle[] value(){ return this.value; }
} 
irreputable
What would that convert method look like? Do you mean making a dynamic proxy yourself, or something else?
Yishai
+1  A: 

Maybe what you really need is

enum Particle {
    ELECTRON("Electron"),
    ...

    private String name;
    private Particle(String name) {
        this.name = name;
    }
    public String getName() {return name;}
}

(You could also generate the name with string functions, but this apporach is more flexible).

Also I dont understand what enormous amount of code have to be changed, since (I guess) your suggestions would not compile, I hope thats not what your code actually looks like.

Arian