0

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 ?

Vincent F
  • 6,523
  • 7
  • 37
  • 79
  • Is this a duplicate of https://stackoverflow.com/questions/19159472/spring-batch-stepscope-cannot-generate-cglib-subclass ? – Simon Dec 02 '20 at 13:54
  • I don't think it's a duplicate - the link you mention has a fix for XML config. But I am not using XML config, and it says clearly there that another question should be asked in that case. Thanks for poiting it out though - I didn't think it could come from the StepScope annotation, but now I guess it is a good lead – Vincent F Dec 02 '20 at 14:13
  • Is your application just the batch job? If yes, does the date really need to be in stepscope? Maybe just making a simple bean would solve the problem? – Simon Dec 02 '20 at 14:22

1 Answers1

1

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)
Mahmoud Ben Hassine
  • 28,519
  • 3
  • 32
  • 50
  • Thanks - you're right, by refactoring my Spring config, I realized I didn't need it, so I removed it. But for what it's worth, your tip worked ;-) – Vincent F Dec 04 '20 at 17:43