Created
January 23, 2020 11:21
-
-
Save bibarsov/031f87df64d9058f2d75207fcb7e152f to your computer and use it in GitHub Desktop.
JTwig support for @path aliases
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.base.Optional; | |
import com.google.common.collect.ImmutableList; | |
import com.google.common.collect.ImmutableMap; | |
import org.apache.commons.logging.Log; | |
import org.apache.commons.logging.LogFactory; | |
import org.jtwig.environment.EnvironmentConfiguration; | |
import org.jtwig.environment.EnvironmentConfigurationBuilder; | |
import org.jtwig.escape.config.DefaultEscapeEngineConfiguration; | |
import org.jtwig.functions.config.DefaultJtwigFunctionList; | |
import org.jtwig.parser.config.DefaultJtwigParserConfiguration; | |
import org.jtwig.property.configuration.DefaultPropertyResolverConfiguration; | |
import org.jtwig.render.config.DefaultRenderConfiguration; | |
import org.jtwig.render.expression.calculator.enumerated.config.DefaultEnumerationListStrategyList; | |
import org.jtwig.resource.config.DefaultResourceConfiguration; | |
import org.jtwig.resource.config.ResourceConfiguration; | |
import org.jtwig.resource.exceptions.ResourceException; | |
import org.jtwig.resource.loader.ClasspathResourceLoader; | |
import org.jtwig.resource.loader.FileResourceLoader; | |
import org.jtwig.resource.loader.StringResourceLoader; | |
import org.jtwig.resource.loader.TypedResourceLoader; | |
import org.jtwig.resource.reference.DefaultResourceReferenceExtractor; | |
import org.jtwig.resource.reference.PosixResourceReferenceExtractor; | |
import org.jtwig.resource.reference.ResourceReference; | |
import org.jtwig.resource.reference.UncResourceReferenceExtractor; | |
import org.jtwig.resource.reference.path.PathTypeSupplier; | |
import org.jtwig.resource.resolver.ReferenceRelativeResourceResolver; | |
import org.jtwig.resource.resolver.RelativeResourceResolver; | |
import org.jtwig.resource.resolver.path.RelativeFilePathResolver; | |
import org.jtwig.resource.resolver.path.RelativePathResolver; | |
import org.jtwig.spring.JtwigViewResolver; | |
import org.jtwig.spring.boot.config.JtwigViewResolverConfigurer; | |
import org.jtwig.value.config.DefaultValueConfiguration; | |
import org.jtwig.web.servlet.JtwigRenderer; | |
import org.springframework.context.annotation.Configuration; | |
//import *****.annotations.NonNull; | |
//import *****.annotations.Nullable; | |
import java.net.URI; | |
import java.net.URISyntaxException; | |
import java.nio.charset.Charset; | |
import java.nio.file.InvalidPathException; | |
import java.util.Collections; | |
import java.util.Map; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
import static com.google.common.base.Preconditions.checkNotNull; | |
import static java.util.Collections.singleton; | |
@Configuration | |
public class CustomJtwigViewResolverConfigurer implements JtwigViewResolverConfigurer { | |
private static final Log LOG = LogFactory.getLog(CustomJtwigViewResolverConfigurer.class); | |
public static class JtwigIncludePaths { | |
@Nullable | |
private Map<String, String> includes; | |
@Nullable | |
public Map<String, String> getIncludes() { | |
return includes; | |
} | |
public void setIncludes(@Nullable Map<String, String> includes) { | |
this.includes = includes; | |
} | |
} | |
private static final String INCLUDE_ALIAS_PREFIX = "@"; | |
private static final Pattern INCLUDE_ALIAS_PATH_PATTERN = Pattern.compile(INCLUDE_ALIAS_PREFIX + "([^/]*)/?(.*)"); | |
private final Map<String, String> jtwigIncludeAliasToPathMap; | |
public CustomJtwigViewResolverConfigurer(JtwigIncludePaths jtwigIncludeAliasToPathMap) { | |
if (jtwigIncludeAliasToPathMap.getIncludes() == null) { | |
LOG.warn("No jtwig include paths mapping provided"); | |
this.jtwigIncludeAliasToPathMap = Collections.emptyMap(); | |
} else { | |
this.jtwigIncludeAliasToPathMap = ImmutableMap.copyOf(jtwigIncludeAliasToPathMap.getIncludes()); | |
} | |
} | |
/** | |
* Overriding relative resolver's behaviour in order to support "@path" like aliases | |
* | |
* @param viewResolver given by jtwig-spring | |
* @see org.jtwig.resource.config.DefaultResourceConfiguration#DefaultResourceConfiguration() original configuration | |
*/ | |
@Override | |
public void configure(JtwigViewResolver viewResolver) { | |
RelativeResourceResolver customRelativeResourceResolver = (parentReference, newPath) -> { | |
if (jtwigIncludeAliasToPathMap.isEmpty()) { | |
return Optional.absent(); | |
} | |
String path = newPath.getPath(); | |
if (path.startsWith(INCLUDE_ALIAS_PREFIX)) { | |
Matcher matcher = INCLUDE_ALIAS_PATH_PATTERN.matcher(path); | |
if (matcher.matches()) { | |
String includeAliasName = checkNotNull( | |
matcher.group(1), | |
"Failed to extract alias name from: " + path | |
); | |
String includePathRest = checkNotNull( | |
matcher.group(2), | |
"Failed to extract alias path from: " + path | |
); | |
String includeAliasReplacement = jtwigIncludeAliasToPathMap.get(includeAliasName); | |
//noinspection Guava | |
return Optional.of(new ResourceReference( | |
parentReference.getType(),//keep the same type, ok | |
resolvePath( | |
includeAliasReplacement, | |
includePathRest | |
) | |
)); | |
} else { | |
throw new IllegalArgumentException("Couldn't resolve jtwig path for: " + path); | |
} | |
} | |
return Optional.absent(); | |
}; | |
//<copypaste> from org.jtwig.resource.config.DefaultResourceConfiguration> | |
EnvironmentConfiguration environmentConfiguration = new EnvironmentConfiguration( | |
new ResourceConfiguration( | |
ImmutableList.<RelativeResourceResolver>builder() | |
.add(customRelativeResourceResolver)//customized behaviour | |
.add(new ReferenceRelativeResourceResolver(singleton(ResourceReference.CLASSPATH), RelativePathResolver.instance())) | |
.add(new ReferenceRelativeResourceResolver(singleton(ResourceReference.FILE), RelativeFilePathResolver.instance())) | |
.build(), | |
ImmutableList.of(ResourceReference.STRING, ResourceReference.MEMORY), | |
ImmutableList.of( | |
new TypedResourceLoader(ResourceReference.FILE, FileResourceLoader.instance()), | |
new TypedResourceLoader(ResourceReference.CLASSPATH, new ClasspathResourceLoader(DefaultResourceConfiguration.class.getClassLoader())), | |
new TypedResourceLoader(ResourceReference.STRING, StringResourceLoader.instance()) | |
), | |
new DefaultResourceReferenceExtractor( | |
PathTypeSupplier.pathTypeSupplier(), | |
new PosixResourceReferenceExtractor(), | |
new UncResourceReferenceExtractor() | |
), | |
Charset.defaultCharset() | |
), | |
new DefaultEnumerationListStrategyList(), | |
new DefaultJtwigParserConfiguration(), | |
new DefaultValueConfiguration(), | |
new DefaultRenderConfiguration(), | |
new DefaultEscapeEngineConfiguration(), | |
new DefaultPropertyResolverConfiguration(), | |
new DefaultJtwigFunctionList(), | |
Collections.emptyMap(), | |
Collections.emptyList(), | |
Collections.emptyList() | |
); | |
//</copypaste> from org.jtwig.resource.config.DefaultResourceConfiguration | |
viewResolver.setRenderer(new JtwigRenderer(new EnvironmentConfigurationBuilder(environmentConfiguration).build())); | |
} | |
@NonNull | |
private static String resolvePath(@NonNull String parent, @NonNull String child) { | |
try { | |
return new URI(String.format("%s/%s", parent, child)).normalize().toString(); | |
} catch (InvalidPathException | URISyntaxException e) { | |
throw new ResourceException("Invalid path", e); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add bean declaration for properties.
Property should look like:
jtwig.includes.content=/templates/subpath/to/content