5

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

3
  • "This is not working if i pass inputversion as 5.0" -- define "not working". "The above results in class cast exception " -- edit your question and include the COMPLETE stack trace (format as code, please, not blockquote) and indicate which line in your source throws the exception. Commented Feb 3, 2018 at 19:35
  • Updated my question Commented Feb 3, 2018 at 19:52
  • The input version can't be a double since it's expecting an int[]. If you want to be flexible you'd want to pass a String[]. You're also not getting a List back, you're getting an array back. Commented Feb 3, 2018 at 19:57

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

6 Comments

This looks great. How can I have a bean to support version greater than 6? Is it possible with conditional?
Are you asking if you can change the annotation to have a 'minSupportedVersion' rather than an int array? And then compare that to the value in the property file? If so, yes.
Yes looking for the minor supported version
1) Instead of define int[] value(), you would define int minValue() default 5. 2) Inside Condition, you would cast to an Integer (not an int[]). 3) Then simply check if (minValue >= version) return true. Do you want edit to post to show?
Thanks. I really liked your approach; very nice use of Spring tools. Well done.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.