casid / jte

Secure and speedy templates for Java and Kotlin.
https://jte.gg
Apache License 2.0
819 stars 59 forks source link

error template resolution Spring Boot #304

Open maxwellt opened 10 months ago

maxwellt commented 10 months ago

According to the documentation of Spring Boot it is possible to define templates that should be used when a specific HTTP status code occurs.

I have noticed when I place a 404.jte in src/main/resources/templates/error it doesn't work. I have tried the same thing with Thymeleaf and that does work.

Digging through the Spring code I saw that in order to resolve the error view, it goes to the DefaultErrorViewResolver#resolveError, where there is a list of templateAvailabilityProviders. These providers are Thymeleaf, Freemarker, Jsp, ... the supported templating engines of Spring (Boot).

I looked for an easy way to register a custom JteTemplateAvailabilityProvider but found no such luck, the only reference in the Spring Code to for instance ThymeleafTemplateAvailabilityProvider is in the Spring autoconfiguration library, namely in the META-INF/spring.factories file:

# Template Availability Providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

I'm not that experienced with the autoconfiguration bits of Spring Boot, but I tried to add my own META-INF/spring.factories file in my own project:

org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
  care.animax.pms.web.config.WebConfig.JteTemplateAvailabilityProvider

And the JteTemplateAvailabilityProvider class looks like this:

    class JteTemplateAvailabilityProvider implements TemplateAvailabilityProvider {

        @Override
        public boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader, ResourceLoader resourceLoader) {
            return resourceLoader.getResource("classpath:/templates/" + view + ".jte").exists();
        }
    }

This actually worked, when I place a debug point in DefaultErrorViewResolver#resolveError, I now see my own provider listed there as well and the JTE template is resolved properly.

Although this works, I'm not sure it's logical that I add this to my own project, should this not be part of the jte-spring-boot-starter project?

I have tried making it more generic, using the gg.jte.templateLocation and gg.jte.templateSuffix properties, while it works for the suffix, the templateLocation doesn't work.

maxwellt commented 8 months ago

@casid just wondering if you had time to have a look at this to give me feedback?

@tschuehly perhaps you could have a look as well as I know you have a lot of experience using JTE and Spring Boot together and I think Casid doesn't use Spring Boot that much?

tschuehly commented 8 months ago

Hey @maxwellt,

Without looking further into it I would say we need to register a bean of type TemplateAvailabilityProvider in the JteAutoConfiguration of the spring boot starter. The spring.factories is for registering Configuration Classes that are being used when using a library as dependency. This is already done for the JteAutoConfiguration.

casid commented 8 months ago

@maxwellt sorry for the late reply! I don't use Spring Boot, so I'm unfortunately not able to give any meaningful recommendations here.