Springboot - Thymeleaf tries to resolve files it should not

Viewed 1223

Hi I am currently working on a web project that uses thymeleaf and also JSF (its a legacy system and we can only slowly migrate to thymeleaf thats why JSF is still there and cannot be removed from one day to another since this is a lot of work). Thymeleaf is configured to resolve the views in the webapp directory that lie under the directory "thymeleaf". This works perfectly if I deploy the application directly on a tomcat server. Also pages from other directories then the "thymeleaf" directory are also resolved by the JSF framework.

I added some integration tests in JUnit that are using SpringBoot. Inside these tests I got the problem that thymeleaf now is trying to resolve any page in any directory. JSF is completely ignored and I got a whole bunch of JUnit tests failing because of that. Is there any point why thymeleaf ignores its configuration and wants to resolve all files? Here is my complete thymeleaf configuration, and as I said this works perfectly if I deploy it on a standalone tomcat.

private ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
  this.applicationContext = applicationContext;
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
  String imagesPattern = "/images/**";
  String imagesLocation = basePath() + "resources/images/";
  registry.addResourceHandler(imagesPattern).addResourceLocations(imagesLocation);
  log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')",
           imagesPattern,
           imagesLocation);

  String cssPattern = "/css/**";
  String cssLocation = basePath() + "resources/css/";
  registry.addResourceHandler(cssPattern).addResourceLocations(cssLocation);
  log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')", cssPattern, cssLocation);
}

@Bean(name = "basepath")
public String basePath()
{
  String basepath = "";

  File file = new File(Optional.ofNullable(System.getenv("THYMELEAF_APP_RESOURCES"))
                               .orElse("thymeleaf-resources/"));
  if (file.exists())
  {
    basepath = "file:" + file.getAbsolutePath();
  }
  if (!basepath.endsWith("/"))
  {
    basepath += "/";
  }
  log.info("basepath: {}", basepath);
  return basepath;
}

@Bean
@Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver(String basePath)
{
  log.info("setting up Thymeleaf view resolver");
  ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
  viewResolver.setTemplateEngine(templateEngine(basePath));
  viewResolver.setCharacterEncoding("UTF-8");
  viewResolver.setCache(true);
  return viewResolver;
}

public SpringTemplateEngine templateEngine(String basePath)
{
  log.info("setting up Thymeleaf template engine.");
  SpringTemplateEngine templateEngine = new SpringTemplateEngine();
  templateEngine.setTemplateResolver(templateResolver(basePath));
  templateEngine.setEnableSpringELCompiler(true);
  return templateEngine;
}

private ITemplateResolver templateResolver(String basePath)
{
  log.info("setting up Thymeleaf template resolver");
  SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
  resolver.setApplicationContext(applicationContext);
  resolver.setPrefix(basePath + "thymeleaf/views/");
  resolver.setSuffix(".html");
  resolver.setTemplateMode(TemplateMode.HTML);
  resolver.setCacheable(false);
  return resolver;
}

@Bean
public IMessageResolver thymeleafMessageSource(MessageSource messageSource)
{
  SpringMessageResolver springMessageResolver = new SpringMessageResolver();
  springMessageResolver.setMessageSource(messageSource);
  return springMessageResolver;
}

EDIT

I just found that the problem seems to lie much deeper. Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context... I just deleted my ThymeleafConfig class for testing purposes and still thymeleaf tries to resolve the JSF pages... (yes I did maven clean before executing the test)

EDIT 2

I read it now and tried to exclude the ThymeleafAutoConfiguration class but it does not help. My configurations are still overridden. Here is my configuration for this so far. (And yes this is the ONLY EnableAutoConfiguration annotation in the whole project)

    @Configuration
    @EnableAutoConfiguration(exclude = {ThymeleafAutoConfiguration.class})
    @Import({WebAppConfig.class, ThymeleafConfig.class})
    public class SpringBootInitializer extends SpringBootServletInitializer

and my ThymeleafConfig class is already added above.

2 Answers

I have been struggling with a similar issue for hours and finally found out the root cause. If you have a dependency to *-data-rest in your pom like this:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>

you will have to add Thymeleaf to your pom as well even if you use a another template engine (Freemarker, JSP, ...) everywhere else. Reason: to expose a JpaRepository as a rest service Spring Boot requires Thymeleaf. I do not understand why this is not defined as a dependency of spring-boot-starter-data-rest so that Maven resolves it automatically. In my opinion it is a Spring Boot configuration bug.

Related