Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Custom annotation with array element

I have a custom annotation as follows.

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnApiVersionConditional.class)
public @interface ConditionalOnApiVersion {

    int[] value() default 5;

    String property();
}

OnApiVersionConditional is,

public class OnApiVersionConditional implements Condition {

  @Override
    public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
        final MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(ConditionalOnApiVersion.class.getName());

       attributes.get("value");


        final String inputVersion = context.getEnvironment().getProperty("userInputVersion");


    }

In my Bean annotation,

  @Bean
  @ConditionalOnApiVersion(value = {6, 7}, property = "userInputVersion")

There are beans with single version matching also, like

@Bean
@ConditionalOnApiVersion(value = 8, property = "userInputVersion")

I would like to validate the userInput version from the property file to the available Beans supported versions. Not sure, how can i get the value, iterate and compare with userInoutVersion. The value could be 8 or {6,7} as an int array. Not sure, how can i iterate the value to check if any of the value is matching with the input version.

final List apiVersions = attributes.get("value").stream().collect(Collectors.toList());

Question:

How to iterate attributes.get("value") and compare with userInputVersion?

attributes.get("value") returns a List of Object.

I tried the below code,

final List<Object> apiVersions = attributes.get("value").stream().collect(Collectors.toList());

boolean result = apiVersions.stream().anyMatch(version -> (int)version == Integer.parseInt(userInputVersion));

But getting the below error int eh 2nd line anyMatch,

java.lang.ClassCastException: [I cannot be cast to java.lang.Integer

Thanks

like image 365
user1578872 Avatar asked Oct 17 '22 23:10

user1578872


1 Answers

You have defined a good custom annotation which uses Spring's @Conditional and this process will only create beans if the property named 'property' is present in the array value.

The annotation defines these two variables as follows:

  1. value: int[] (One or more supported versions)
  2. property: String (The name of the property to compare to)

When you use the metadata to retrieve these values, Spring returns them as Objects. Casting these objects into the types you defined them as is a key step. There is no need for streams as iterating an int[] array is trivial.

I tested various forms of your annotation (value = 5, value = {6,7}, etc) and found the following code to work well (@Conditional beans were only created if the version was correct).

public class OnApiVersionConditional implements Condition {

@Override
public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {

    final MultiValueMap<String, Object> attributes = metadata
            .getAllAnnotationAttributes(ConditionalOnApiVersion.class.getName());

    // 1.  Retrieve the property name from the annotation (i.e. userInputVersion)
    List<Object> propertyObject = attributes.get("property");
    // 2.  Cast it to a String
    String propertyName = (String)propertyObject.get(0);

    // 3.  Retrieve the value 
    List<Object> list = attributes.get("value");
    // 4.  Cast it to int[]
    int[] values = (int[])list.get(0);

    // 5.  Look up the actual version (based on the property name in the annotation)
    final String inputVersion = context.getEnvironment().getProperty(propertyName);
    // Assume it is an integer? 
    int version = Integer.valueOf(inputVersion).intValue();

    // 6.  Scan the supported version; look to match against actual version
    for (int i : values)
        if (i == version)
            return true;

    // The version is not supported
    return false;

}

}

This method could be improved by validating both property and value; returning false if either of these contains bad/empty values, etc.

like image 115
Ian Mc Avatar answered Nov 02 '22 06:11

Ian Mc