2

I try to pass a number value from the Spring properties file to Annotation long properties and I wonder how to set correctly non-string parameter. I try to use the following way, and obviously, we cant define parameters with strings because of Incompatible types. Found: 'java.lang.String', required: 'long'

And my question is "How to pass a number parameter from a properties file to a Spring annotation number parameter"

application.properties

my.parameter=10

MyAnnotation.java

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation {

    long myParameter() default 0;
}

MyClass.java

@Component
@MyAnnotation(myParameter = "${my.parameter}") //incompatible types long and String
public class MyClass {

//some code
}
Oleg Ushakov
  • 1,200
  • 14
  • 27
  • 1
    One way would be to define 2 properties in your annotation - long and String. If String is defined, it overrides long. You need to parse String - as you havent specified how you process your annotation, it is difficult to recommend a class to do it - `ConfigurableBeanFactory` and `ConfigurableEnvironment` come to mind. You can even go full monty and support SpEL in String param. Check `org.springframework.retry.interceptor.Retryable` for similar approach with `maxAttempts` and `maxAttemptsExpression`. – Lesiak May 19 '22 at 19:53
  • @Lesiak thank's a lot for a bunch of ideas. I`ll check it in my code too. Your help is very appreciated and your answer really valuable to me – Oleg Ushakov May 19 '22 at 20:44

2 Answers2

1

Your attempt will fail early at compilation phase (so, not at runtime where Spring resolves application properties), because the template ("${my.parameter}") is a string, not a long (as expected by the definition of the annotation class MyAnnotation).

A solution would be to change the type of myParameter to String, and then resolve it (when needed) using an autowired ConfigurableEnvironment from Spring.

For example:

@Component
@MyAnnotation(myParameter = "${my.parameter}")
public class FooComponent
{
    @Autowired private ConfigurableEnvironment env;

    @PostConstruct
    private void initialize()
    {
        MyAnnotation a = FooComponent.class.getAnnotation(MyAnnotation.class);
        // resolve using our application properties
        String s = env.resolvePlaceholders(a.myParameter()));
        // convert to long
        long n = Long.valueOf(s);
        // use n somehow ...
    }


    // ... more methods ...
} 
Michail Alexakis
  • 1,405
  • 15
  • 14
  • Thank you for the answer I had asked another question, not about the error. I would like to find some way to pass int parameter – Oleg Ushakov May 19 '22 at 19:18
  • @OlegUshakov, i have added an example of resolving a property in a programmatic manner – Michail Alexakis May 19 '22 at 19:27
  • I don't want to change the parameter type. We can use e.g. int in the case when we define it as constant, e.g. @MyAnnotation(myParameter = 10) but what about variables from the property file? Do you know a way to use it for int parameter in the example? – Oleg Ushakov May 19 '22 at 19:30
  • @OlegUshakov, i am not sure i understand the question. If you want to autowire values from application properties you can just use `@Value("${my.parameter}") private int myParameter` as a member of the `@Component` class – Michail Alexakis May 19 '22 at 20:13
0

Here's a couple options that might work:

  1. @MyAnnotation(myParameter = "#{ T(java.lang.Long).parseLong('${email.config.port}')}")
  2. Change the value in application.properties to my.parameter=10L.

If you get the NumberFormatException after this - it means that Spring was not able to find the property.

References & useful sources:

  1. https://stackoverflow.com/a/66084308/9899739
  2. https://stackoverflow.com/a/40894656/9899739
  3. https://stackoverflow.com/a/27341777/9899739
  4. https://stackoverflow.com/a/52064355/9899739
  5. docs.spring.io, Externalized Configuration
RickHeadle
  • 34
  • 6
  • Also I think I should mention that normally Spring is more than capable to convert such values. This options are supposed to be considered only when that's not the case. – RickHeadle May 19 '22 at 20:17
  • Thank you for your answer. The construction looks so bulky but it seems we still don't have any new mechanics for automated type conversion in this case. Anyway I have some idea based on your answer and I wanna check it now – Oleg Ushakov May 19 '22 at 20:38
  • 1
    how your solution (1) will even compile (given that `myParameter` is long)? – Michail Alexakis May 19 '22 at 22:29