0

I've been trying to do some logic upon class loading of an annotation type. Naturally the static block came to my mind.

But unfortunately this isn't allowed, the compile error in Eclipse is:

Syntax error, insert "enum Identifier" to complete EnumHeader

My Annotation declaration is:

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Documented
@Retention(RUNTIME)
@Target(FIELD)
@Validate
public @interface StringSize {

int max();

int min() default 0;

    static {
        Validator.registerCallback(StringSize.class, (Field f, Object parent) -> {
            Object o = f.get(parent);
            if(!(o instanceof CharSequence))
                throw new IllegalAnnotationException("@StringSize allowed on CharSequence fields only.");

            CharSequence str = (CharSequence) o;
            StringSize size = f.getAnnotation(StringSize.class);

            if(str.length() < size.min())
                throw new AssertionError(str + " - length < " + size.min());
            if(str.length() > size.max())
                throw new AssertionError(str + " - length > " + size.max());
        });
    }

} 

What I'm trying to do is build a validator that goes through field after field and check for any illegal value.

Now, this framework is completely unaware of what is considered an 'illegal value' i.e. it is up to any potential user of this framework to create their own rules thus create any number of custom annotations and map it to a callback method that does know how to validate it.

@Validate is a custom meta-annotation used in the validation framework to mark an annotation as a validator (similar to CDI's @Qualifier). All the framework does is, when Validator.validate(obj) is called to scan for all fields if any of its annotations has the meta-annotation @Validate, look up its correspoding callback method and invoke it with that field passed as argument. The callback throws an exception on any illegal value found.

I am trying to find a generic way to do the annotation-callback mapping, so the end user shouldn't have to manually do the mapping, but rather the author of the custom annotation. So this is what I ended up trying.

Any idea how to overcome this constraint?

Mordechai
  • 15,437
  • 2
  • 41
  • 82
  • Write an annotation processor instead, put the semantics in that. – Andy Turner Feb 23 '17 at 21:19
  • You don't put static _initializer_ blocks in an annotation. – Lew Bloch Feb 23 '17 at 23:25
  • @Lew I figured this already. So is there a clean alternative other than let my API users manually do the registration themselves. – Mordechai Feb 24 '17 at 01:18
  • Let the code that processes the annotation have that logic. – Lew Bloch Feb 24 '17 at 03:24
  • @Lew My framework is extensible, the processor isn't aware of any annotation other than `@Validate`. All it does is call a user defined - annotation unique - callback method on all fields annotated with an annotation annotated with the above meta-annotation. (I can also add `@NonNull` and define a callback that checks for that.) – Mordechai Feb 24 '17 at 04:20

1 Answers1

0

This doesn't really solve the problem, but is a nice alternative.

As seen in my post I've defined a meta-annotation @Validate as a marker for my validation framework. I also have an interface (which the lambda expression actually uses) ValidateCallback.

With these in place, I just have to add a value() to @Validate:

public @interface Validate {
    Class<? extends ValidateCallback> value();
}

Now I can drop the "registration" system I've previously used. All I'll have to do i just call the linked functional interface.

Mordechai
  • 15,437
  • 2
  • 41
  • 82