Parse LocalTime string inside the #Value attribute - spring

My environment variable is a string with time 23:30 In my String Boot application I'd like to parse it automatically and set it the result to variable.
I tried like this
#Value("#{ java.time.LocalTime.parse('${NIGHT_START_TIME}')}")
private LocalTime NIGHT_START_TIME;
IntelliJ shows the error
Cannot resolve variable 'java'
Here is log
Unsatisfied dependency expressed through field 'NIGHT_START_TIME';
nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'LocalTime' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
If I read variable like this I see that value is correct
#Value("${NIGHT_START_TIME}")
private String NIGHT_START_TIME;
Any ideas how to make it work?

Try this
#Value("#{ T(java.time.LocalTime).parse('${NIGHT_START_TIME}')}")
private LocalTime NIGHT_START_TIME;
The way you reference a class is using T.
Check the documentation.

Have checked at Spring Boot 2.2.6.RELEASE:
application.yml
NIGHT_START_TIME: '23:30'
Service
#Value("${NIGHT_START_TIME}")
private LocalTime NIGHT_START_TIME;
Work perfect without any "knee bends":)

Related

Kotlin application.yml data class looking for beans

I have a Kotlin data class that I want to read properties from application.yml file. Here is my data class:
#ConstructorBinding
#ConfigurationProperties("meanwhile.in.hell.myapp")
data class MyAppProperties(val serverId: String, val locationId: String)
I then added it to my configuration class:
#Configuration
#EnableConfigurationProperties(MyAppProperties::class)
open class MyAppConfiguration(private val properties: MyAppProperties) {
where I access the values using just properties.serverId and pass the object into the constructor of other beans being created, such as this one:
open class MyAppClient(
private val webClient: WebClient,
private val properties: MyAppProperties
) : IMyAppClient {
However, when I start up my application I get an error that instead of trying to load the properties from application.yml, it is trying to find beans for the constructor params:
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'meanwhile.in.hell.myapp-meanwhile.in.hell.myapp.MyAppProperties': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Parameter 0 of constructor in meanwhile.in.hell.myapp.MyAppProperties required a bean of type 'java.lang.String' that could not be found.
How do I stop my app thinking that these params are Autowired? I know that in Kotlin, this is how a constructor Autowired bean looks like (ie, not requiring the annotation), but all example I have seen online on how to read application.yml properties looks the same as my data class.
Spring-Boot v2.3.0.RELEASE
Kotlin v1.3.72
Turns out I was missing the dependency
org.jetbrains.kotlin:kotlin-reflect
Docs:
https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/htmlsingle/#boot-features-kotlin-requirements
Issue:
https://github.com/spring-projects/spring-boot/issues/19582

#Value annotation for reading Map from property file

My Java has this
#Value("#{${validators}}")
private Map<String,String> validators;
property file has this
validators={AlphabetValidator:'AlphabetValidator',NumberValidator:'NumberValidator'AlphaNumericValidator:'AlphaNumericValidator',DateValidator:'DateValidator', FixedLengthValidator:'FixedLengthValidator',MinimumLengthValidator:'MinimumLengthValidator',MaximumLengthValidator:'MaximumLengthValidator',CustomValidator:'CustomValidator' MandatoryFieldValidator: 'MandatoryFieldValidator',TimeValidator:'TimeValidator'}
when I run the app.. I am getting this error
Exception in thread "main"
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'validatorProperties': Unsatisfied
dependency expressed through field 'validators'; nested exception is
org.springframework.beans.factory.BeanExpressionException: Expression
parsing failed; nested exception is
org.springframework.expression.spel.SpelParseException: EL1041E:(pos
1): After parsing a valid expression, there is still more data in the
expression: 'lcurly({)'
Check out for comma ',' in property file.
Properties file:
validators={AlphabetValidator:'AlphabetValidator',NumberValidator:'NumberValidator',AlphaNumericValidator:'AlphaNumericValidator',DateValidator:'DateValidator',FixedLengthValidator:'FixedLengthValidator',MinimumLengthValidator:'MinimumLengthValidator',MaximumLengthValidator:'MaximumLengthValidator',CustomValidator:'CustomValidator',MandatoryFieldValidator:'MandatoryFieldValidator',TimeValidator:'TimeValidator'}
Java code:
#Value("#{${validators}}")
private Map<String,String> validators;
You have missed to specify some commas inside your properties. Try with following:
validators={AlphabetValidator:'AlphabetValidator',NumberValidator:'NumberValidator',AlphaNumericValidator:'AlphaNumericValidator',DateValidator:'DateValidator',FixedLengthValidator:'FixedLengthValidator',MinimumLengthValidator:'MinimumLengthValidator',MaximumLengthValidator:'MaximumLengthValidator',CustomValidator:'CustomValidator',MandatoryFieldValidator:'MandatoryFieldValidator',TimeValidator:'TimeValidator'}

Spring | SPEL multiple property accessors

I'm trying to use SPeL with multiple property accessors.
StandardEvaluationContext simpleContext = new StandardEvaluationContext(myPojo);
simpleContext.setVariable("ctx", ruleExecutionContext);
simpleContext.setPropertyAccessors(Arrays.asList(new MapAccessor(), new ReflectivePropertyAccessor()));
ExpressionParser parser = new SpelExpressionParser();
return (Boolean) parser.parseExpression(spelExpression).getValue(simpleContext, RulebaseConfiguration.LIB_MAP);
RulebaseConfiguration.LIB_MAP contains {"instanceName": instance}
I want to pass expressions that could operate on a POJO as well as call methods on the instance. But it only takes map into the effect.
I get this error:
SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'payload' cannot be found on object of type 'java.util.HashMap' - maybe not public?] with root cause
org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'payload' cannot be found on object of type 'java.util.HashMap' - maybe not public?
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:226)
Creating a context and parsing the expression for each request is wasteful, unless it's different for each request; in which case, consider caching expressions/contexts.
As I said, since you are passing a rootObject to getValue(), your myPojo is "hidden" - the evaluation is always performed on LIB_MAP.
You need to call getValue() without a root object to use the context's root object. You can add LIB_MAP as a variable (e.g. with name nationalityLookup) and use
payload['channel'] == #nationalityLookup.resolveChannel('CBR1000')

Inject date using #Value annotation

This is how I am trying to inject a date into a #Component class.
#Value("${new java.text.SimpleDateFormat(\"yyyyMMdd\").parse(\"${PROP_DATE}\")}")
Date myDate;
The date is specified as a String in properties file :
PROP_DATE=20110421
I get this error. What am I doing wrong? Is there any other way to inject Date property? Thanks.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ccc': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: java.util.Date aaa.bbb.ccc.myDate; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'new java.text.SimpleDateFormat("yyyyMMdd").parse("20110421")'
Use #{new java.text.SimpleDateFormat(\"yyyyMMdd\").parse(\"${PROP_DATE}\")} for process value with spEL

spring aop - exception while creating advice around JdbcTemplate methods

I've a web application that uses apache dbcp and spring jdbc to perform database operations on an oracle database. I need to write a performance logger that logs the individual times of each database operation. I tried writing an around advice on all 'execute' methods of org.springframework.jdbc.core.JdbcTemplate but it results in an error when spring gets initialized. The logger class and the exception stacktrace is as follows:-
I also tried to use CGLIB proxies by enabling but it errors out on dao classes that extends from spring's StoredProcedure class and use constructor injection.
#Aspect
public class Logger {
#Around("this(org.springframework.jdbc.core.JdbcTemplate) && execution(* execute(*))")
public Object invoke(ProceedingJoinPoint pjp) throws Throwable {
long time = System.currentTimeMillis();
Object result = pjp.proceed();
LOGGER.debug("time consumed = " + (System.currentTimeMillis() - time));
return result;
}
Exception stacktrace:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'myDao' defined in class path resource [spring/my-dao.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.jdbc.core.JdbcTemplate]:
Could not convert constructor argument value of type [$Proxy7] to required type [org.springframework.jdbc.core.JdbcTemplate]:
Failed to convert value of type '$Proxy7 implementing org.springframework.jdbc.core.JdbcOperations,org.springframework.beans.factory.InitializingBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised'
to required type 'org.springframework.jdbc.core.JdbcTemplate';
nested exception is
java.lang.IllegalStateException: Cannot convert value of type [$Proxy7 implementing org.springframework.jdbc.core.JdbcOperations,org.springframework.beans.factory.InitializingBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised]
to required type [org.springframework.jdbc.core.JdbcTemplate]:
no matching editors or conversion strategy found
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:702)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)

Resources