Spring-boot: ThymeleafAutoConfiguration fails if thymeleaf-spring5 is not present

Created on 4 Mar 2019  路  20Comments  路  Source: spring-projects/spring-boot

Hi, this is a first-timers-only issue. This means we've worked to make it more legible to folks who either haven't contributed to our codebase before, or even folks who haven't contributed to open source before.

If that's you, we're interested in helping you take the first step and can answer questions and help you out as you do. Note that we're especially interested in contributions from people from groups underrepresented in free and open source software!

If you have contributed before, consider leaving this one for someone new, and looking through our general ideal-for-contribution issues. Thanks!

Background

Auto-configurations declare conditions to make sure that they back-off when conditions aren't met. For instance, @ConditionalOnClass allows to refer to classes that must be present on the classpath for an auto-configuration to be considered. Spring Boot will parse the bytecode using ASM to identify those classes and skip the auto-configuration altogether if one of them is not present.

Problem

The thymeleaf auto-configuration support relies on the Spring integration module provided by the Thymeleaf project (currently thymeleaf-spring5). Unfortunately, ThymeleafAutoConfiguration only checks for a class in the core thymelaf jar (thymeleaf): if the core jar is present but the integration one isn't, the auto-configuration will be considered and fail:

java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration.templateEngine
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:64) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:181) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:141) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:117) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:327) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:232) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:705) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:531) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at com.example.demo.DemoApplicationKt.main(DemoApplication.kt:13) [classes/:na]
Caused by: java.lang.IllegalStateException: @ConditionalOnMissingBean did not specify a bean using type, name or annotation and the attempt to deduce the bean's type failed
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanSearchSpec.validate(OnBeanCondition.java:451) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanSearchSpec.<init>(OnBeanCondition.java:441) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanSearchSpec.<init>(OnBeanCondition.java:416) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:158) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    ... 16 common frames omitted
Caused by: org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanTypeDeductionException: Failed to deduce bean type for org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration.templateEngine
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanSearchSpec.addDeducedBeanTypeForBeanMethod(OnBeanCondition.java:496) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanSearchSpec.addDeducedBeanType(OnBeanCondition.java:483) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanSearchSpec.<init>(OnBeanCondition.java:435) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    ... 19 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.thymeleaf.spring5.SpringTemplateEngine
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_171]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_171]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[na:1.8.0_171]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_171]
    at java.lang.Class.forName0(Native Method) ~[na:1.8.0_171]
    at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_171]
    at org.springframework.util.ClassUtils.forName(ClassUtils.java:275) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanSearchSpec.getReturnType(OnBeanCondition.java:505) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanSearchSpec.addDeducedBeanTypeForBeanMethod(OnBeanCondition.java:491) ~[spring-boot-autoconfigure-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    ... 21 common frames omitted

Solution

The conditions on ThymeleafAutoConfiguration should be refined so that we don't process it if thymeleaf-spring5 is not on the classpath. A good solution for this is to extend @ConditionalOnClass to also checks for the presence of SpringTemplateEngine.

Steps to Fix

  • [x] Claim this issue with a comment below and ask any clarifying questions you need
  • [x] Set up a repository locally following the Contributing Guidelines
  • [x] Try to fix the issue following the steps above
  • [x] Commit your changes and start a pull request.
first-timers-only superseded bug

Most helpful comment

I will work there

All 20 comments

I will work there

Great! Thank you. Please let us know if you have any questions.

oh i am late again :( i will be here next time! :)

@kandebouya checking in to see if there is anything we can do to help. Please let us know.

@kandebouya we haven't heard back from you and are available if you need help. If we don't hear from you by the end of the week, we'll let someone else have a crack at it. Thanks!

@snicoll I can work on it if @kandebouya is not available

Thanks @koziolk, you're third. @Oguzyildirim is next if we don't hear from @kandebouya

I will be 4th :)

@snicoll If this issue is done (was trying to see if I can really do it or not and well luckily, I did), should we still wait for the turn or can we submit the PR?

@dosdebug as you've indicated yourself, you are 4th so pushing the solution without giving a chance to others to try doesn't seem fair. Once the issue is done you can check if it matches your solution.

@kandebouya we haven't heard from you for two weeks so I suggest that @Oguzyildirim takes over now. @Oguzyildirim, can you please confirm your interest?

I'd love to take it up please let me know if my turn's up.

In the interest of getting this fixed this week as we are releasing 2.1.4 Friday, I'd like to move to the third person on the list (and please answer ASAP if you won't be able to work on it this week). @koziolk are you available to work on it this week? Thanks!

@snicoll Yes, I'm available. Will start working on this Today.

Interested to work here.

@koziolk how is it going? Reminder that we're releasing soon and I'd like to get that change in.

@snicoll Good. I'm going to submit a pull request Today.

@snicoll Just to let you know, if @koziolk could not somehow submit PR, I have my changes ready for this task already.

@snicoll I've implemented a solution based on what @kazuki43zoo suggested in his comment.

Closing in favour of PR #16341

Was this page helpful?
0 / 5 - 0 ratings