Using LocalDate in Spring context and avoid CGLib issue

Tags: , ,



I have a small job written with Spring Boot Batch 2.2.2. It takes a date as a parameter, and since several components need that date, I place it as a bean in the Spring context :

@Bean
@StepScope
public Date processingDate(){
if(isEmpty(applicationArguments.getSourceArgs())){
  throw new IllegalArgumentException("No parameter received - expecting a date to be passed as a command line parameter.");
}

SimpleDateFormat sdf = new SimpleDateFormat(EXPECTED_DATE_FORMAT);
String expectedDateFromCommandLine=applicationArguments.getSourceArgs()[0];

try {

  return sdf.parse(expectedDateFromCommandLine);

} catch (ParseException e) {
  throw new IllegalArgumentException("Expecting the parameter date to have this format : "+ EXPECTED_DATE_FORMAT,e);
}
}

It works well, no issue.

Now I am doing some refactoring, and thought I should use LocalDate instead of Date, as it is now recommended since Java 8.

@Bean
@StepScope
public LocalDate processingDate(){

    if(isEmpty(applicationArguments.getSourceArgs())){
        throw new IllegalArgumentException("No parameter received - expecting a date to be passed as a command line parameter.");
    }

    String expectedDateFromCommandLine=applicationArguments.getSourceArgs()[0];

    return LocalDate.parse(expectedDateFromCommandLine, DateTimeFormatter.ofPattern(EXPECTED_DATE_FORMAT));

}

However, Spring doesn’t like it :

Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class java.time.LocalDate: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class java.time.LocalDate
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:208)

I understand that behind the scene, Spring does some magic with some proxy-ing and all.. But there must be an easy way to make this possible, right ?

Answer

From the Javadoc of StepScope:

Marking a @Bean as @StepScope is equivalent to marking it as @Scope(value="step", proxyMode=TARGET_CLASS)

Now the proxy mode TARGET_CLASS means the proxy will be a CGLIB proxy (See ScopedProxyMode#TARGET_CLASS) which mean a sub-class of the bean type will be created for the proxy. Since you are declaring a step scoped bean of type LocalDate which is a final class, Spring (Batch) is unable to create the proxy, hence the error.

I don’t see the added value of having a step scoped LocalDate bean. A step scoped bean is useful for late binding of job parameters or attributes from the step/job execution context. But if you really want that bean to be step scoped, you can try another proxy mode like:

@Scope(value = "step", proxyMode = ScopedProxyMode.DEFAULT)


Source: stackoverflow