Search code examples
javaoval

Access annotation attributes from custom oval annotation


Is it possible, when using custom oval annotation and custom class for check, to access the annotation and retrieve the used annotation attributes ?

Reference for oval: https://sebthom.github.io/oval/USERGUIDE.html#custom-constraint-annotations


Minimal example

Lets assume we have class Foo. It has two annotated fields.
Each time, the annotation has a different myValuea and b.

class Foo {
  @CustomAnnotation(myValue = "a")
  public String first;

  @CustomAnnotation(myValue = "b")
  public String second;
}

This is the annotation.
It is noted that a check should be performed using MyCheck.class, also setting some default value for myValue.

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Constraint(checkWith = MyCheck.class)
public @interface CustomAnnotation {
    String myValue() default "";
}

Now we want to use oval to validate this field.
Most importantly, we want to extract the value a or b from the annotation's myValue and use it inside our validation logic.

public class MyCheck extends AbstractAnnotationCheck<CustomAnnotation> {


    @Override
    public boolean isSatisfied(Object validatedObject, Object valueToValidate, OValContext context,
                               Validator validator) throws OValException {
  // how to get the value of `myValue`, which is `a` or `b` or empty string as default
  }
}

What I have tried and failed:

  1. validatedObject is Foo.class. You can easily get its fields and annotations. However, there is no way to differentiate between the two annotations.
  2. valueToValidate is in this case String value – what first or second holds.
  3. context not useful, you can get compile time type from it, which is String
  4. validator not useful ?

Solution

  • After some digging in the superclass I have found that you can override method

    • configure

    This method gets as the only parameter the annotation that is currently being checked at the field.
    You can then read the myValue.

    public class MyCheck extends AbstractAnnotationCheck<CustomAnnotation> {
    
        private String myValue;
    
        @Override
        public void configure(CustomAnnotation customAnnotation) {
            super.configure(customAnnotation);
            this.myValue = customAnnotation.myValue();
        }
    
        @Override
        public boolean isSatisfied(Object validatedObject, Object valueToValidate, OValContext context,
                                   Validator validator) throws OValException {
            if (myValue.equals("a")) {}
            else if (myValue.equals("b")){}
            else {}
    }