Closed phasebash closed 3 years ago
The idea being to support both developer mode and production mode via this CompositeTemplateFilesResolver?
The root problem is that PathMatchingResourcePatternResolver is limited heavily by the underlying classloader, so it's very difficult to make patterns which will match across classpath roots. We've got templates in two modules: 1 module that is a published Jar other projects use, and 1 module which is a webapp with it's own app-specific Soys. Using a single ClasspathTemplateFilesResolver, I cannot scan both reliably.
Otherwise, PathMatchingResourcePatternResolver is great, and works very well on one root.
Here is what we're using now (mind the Groovy):
class CompositeTemplateFilesResolver implements TemplateFilesResolver {
/**
* The collection of TemplateFilesResolvers to use.
*/
private Collection<TemplateFilesResolver> templateFilesResolvers
@Required
void setTemplateFilesResolvers(Collection<TemplateFilesResolver> templateFilesResolvers) {
this.templateFilesResolvers = templateFilesResolvers
}
@Override
Collection<URL> resolve() throws IOException {
templateFilesResolvers.collectMany {
it.resolve().findAll { it }
}
}
@Override
Optional<URL> resolve(String templateName) throws IOException {
templateFilesResolvers.findResult Optional.absent(), {
Optional<URL> o = it.resolve(templateName)
// findResult requires null value to flag 'false'
o.present ? o : null
}
}
}
I am fine with this contribution if you wish to convert this to Java. I think the real trick will be for people to get their head around in terms how to use all these classes and the right patterns of integrating the library in the project.
People might hate it like they do java.io and all those decorators. Most Spring classes seem to offer Lists of strings for similar kinds of use cases. I'll look at working that into the ClasspathTFR, if you agree.
You mean to write a CompositeTemplateFilesResolver or something else? I am lost a bit. Is this referring to this issue or something new?
Can you contribute some class for this? Actually one could think there are lots of possibilities for this, should this project support this composite?
I've come about an interesting limitation (feature?) of the PathMatchingResourcePatternResolver used by the ClasspathTemplateFilesResolver. First, some background information...
In our applications, we've started to stray from the War packaging for both services and frontend webapps, instead packaging executable Jars with embedded Jetty servers. When run from Gradle using the application plugin "run" task, the ClasspathTemplateFilesResolver will only find templates on the first classpath root found if a pattern can span multiple classpath roots.
For example: assume two modules
With one ClasspathTemplateFilesResolver we could make a pattern like so:
This works, but not all the time.
Note, we cannot use /foo-bar/application and /foo-bar/components due to a limitation in the Java classloader which leaks through the PathMatchingResourcePatternResolver.
Anyway, when running ./gradlew run from foo-bar-application, Soy templates in the application will be of type FileSystemResource, and those from the components Jar should be of type ClassPathResource. The problem is, they will not be found in this particular configuration. Within an IDE, the resources will all be of type FileSystemResource, and templates from both modules are found. If the pattern above is adjusted with less wildcards, it can find templates on either root, just not both at the same time.
Anyway. What do you think about a CompositeTemplateFilesResolver? It would take an Iterable of TemplateFilesResolvers, and allow the client to specify as many simple TemplateFilesResolvers as they want. Or, should ClasspathTemplateFilesResolver take a List of paths (like ApplicationContext does for contextLocations)?