Skip to content

Commit 2729c74

Browse files
committed
Add jmustache support
The package names changed a bit from the prototype project, but wuth vanilla autconfiguration usage that shouldn't matter. Follows closely the Groovy templates support. Templates live in classpath:/templates/*.html by default. Fixes gh-2242
1 parent 9dd4d43 commit 2729c74

File tree

33 files changed

+1365
-2
lines changed

33 files changed

+1365
-2
lines changed

spring-boot-autoconfigure/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@
6060
<artifactId>gson</artifactId>
6161
<optional>true</optional>
6262
</dependency>
63+
<dependency>
64+
<groupId>com.samskivert</groupId>
65+
<artifactId>jmustache</artifactId>
66+
<optional>true</optional>
67+
</dependency>
6368
<dependency>
6469
<groupId>org.flywaydb</groupId>
6570
<artifactId>flyway-core</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2013-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.mustache;
18+
19+
import javax.annotation.PostConstruct;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
25+
import org.springframework.boot.autoconfigure.mustache.web.MustacheViewResolver;
26+
import org.springframework.boot.autoconfigure.template.TemplateLocation;
27+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
28+
import org.springframework.context.ApplicationContext;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.core.Ordered;
32+
import org.springframework.core.env.Environment;
33+
import org.springframework.util.Assert;
34+
35+
import com.samskivert.mustache.Mustache;
36+
import com.samskivert.mustache.Mustache.Collector;
37+
import com.samskivert.mustache.Mustache.Compiler;
38+
import com.samskivert.mustache.Mustache.TemplateLoader;
39+
40+
/**
41+
* @author Dave Syer
42+
* @since 1.2.2
43+
*
44+
*/
45+
@Configuration
46+
@ConditionalOnClass(Mustache.class)
47+
@EnableConfigurationProperties(MustacheProperties.class)
48+
public class MustacheAutoConfiguration {
49+
50+
@Autowired
51+
private MustacheProperties mustache;
52+
53+
@Autowired
54+
private Environment environment;
55+
56+
@Autowired
57+
private ApplicationContext applicationContext;
58+
59+
@PostConstruct
60+
public void checkTemplateLocationExists() {
61+
if (this.mustache.isCheckTemplateLocation()) {
62+
TemplateLocation location = new TemplateLocation(this.mustache.getPrefix());
63+
Assert.state(location.exists(this.applicationContext),
64+
"Cannot find template location: " + location
65+
+ " (please add some templates, check your Mustache "
66+
+ "configuration, or set spring.mustache.template."
67+
+ "check-template-location=false)");
68+
}
69+
}
70+
71+
@Bean
72+
@ConditionalOnMissingBean(Mustache.Compiler.class)
73+
public Mustache.Compiler mustacheCompiler(TemplateLoader mustacheTemplateLoader) {
74+
return Mustache.compiler().withLoader(mustacheTemplateLoader)
75+
.withCollector(collector());
76+
}
77+
78+
private Collector collector() {
79+
MustacheEnvironmentCollector collector = new MustacheEnvironmentCollector();
80+
collector.setEnvironment(this.environment);
81+
return collector;
82+
}
83+
84+
@Bean
85+
@ConditionalOnMissingBean(TemplateLoader.class)
86+
public MustacheResourceTemplateLoader mustacheTemplateLoader() {
87+
MustacheResourceTemplateLoader loader = new MustacheResourceTemplateLoader(
88+
this.mustache.getPrefix(), this.mustache.getSuffix());
89+
loader.setCharset(this.mustache.getCharset());
90+
return loader;
91+
}
92+
93+
@Configuration
94+
@ConditionalOnWebApplication
95+
protected static class MustacheWebConfiguration {
96+
97+
@Autowired
98+
private MustacheProperties mustache;
99+
100+
@Bean
101+
@ConditionalOnMissingBean(MustacheViewResolver.class)
102+
public MustacheViewResolver mustacheViewResolver(Compiler mustacheCompiler) {
103+
MustacheViewResolver resolver = new MustacheViewResolver();
104+
resolver.setPrefix(this.mustache.getPrefix());
105+
resolver.setSuffix(this.mustache.getSuffix());
106+
resolver.setCache(this.mustache.isCache());
107+
resolver.setViewNames(this.mustache.getViewNames());
108+
resolver.setContentType(this.mustache.getContentType());
109+
resolver.setCompiler(mustacheCompiler);
110+
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
111+
return resolver;
112+
}
113+
114+
}
115+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2012-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.mustache;
18+
19+
import org.springframework.beans.factory.FactoryBean;
20+
21+
import com.samskivert.mustache.Mustache;
22+
import com.samskivert.mustache.Mustache.Collector;
23+
import com.samskivert.mustache.Mustache.Compiler;
24+
import com.samskivert.mustache.Mustache.Escaper;
25+
import com.samskivert.mustache.Mustache.Formatter;
26+
import com.samskivert.mustache.Mustache.TemplateLoader;
27+
28+
/**
29+
* Factory for a Mustache compiler with custom strategies. For building a
30+
* <code>@Bean</code> definition in Java it probably doesn't help to use this factory
31+
* since the underlying fluent API is actually richer.
32+
*
33+
* @see MustacheResourceTemplateLoader
34+
*
35+
* @author Dave Syer
36+
* @since 1.2.2
37+
*
38+
*/
39+
public class MustacheCompilerFactoryBean implements FactoryBean<Mustache.Compiler> {
40+
41+
private String delims;
42+
private TemplateLoader templateLoader;
43+
private Formatter formatter;
44+
private Escaper escaper;
45+
private Collector collector;
46+
private Compiler compiler;
47+
48+
public void setDelims(String delims) {
49+
this.delims = delims;
50+
}
51+
52+
public void setTemplateLoader(TemplateLoader templateLoader) {
53+
this.templateLoader = templateLoader;
54+
}
55+
56+
public void setFormatter(Formatter formatter) {
57+
this.formatter = formatter;
58+
}
59+
60+
public void setEscaper(Escaper escaper) {
61+
this.escaper = escaper;
62+
}
63+
64+
public void setCollector(Collector collector) {
65+
this.collector = collector;
66+
}
67+
68+
@Override
69+
public Mustache.Compiler getObject() throws Exception {
70+
this.compiler = Mustache.compiler();
71+
if (this.delims != null) {
72+
this.compiler = this.compiler.withDelims(this.delims);
73+
}
74+
if (this.templateLoader != null) {
75+
this.compiler = this.compiler.withLoader(this.templateLoader);
76+
}
77+
if (this.formatter != null) {
78+
this.compiler = this.compiler.withFormatter(this.formatter);
79+
}
80+
if (this.escaper != null) {
81+
this.compiler = this.compiler.withEscaper(this.escaper);
82+
}
83+
if (this.collector != null) {
84+
this.compiler = this.compiler.withCollector(this.collector);
85+
}
86+
return this.compiler;
87+
}
88+
89+
@Override
90+
public Class<?> getObjectType() {
91+
return Mustache.Compiler.class;
92+
}
93+
94+
@Override
95+
public boolean isSingleton() {
96+
return false;
97+
}
98+
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.springframework.boot.autoconfigure.mustache;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
import org.springframework.boot.bind.PropertySourcesPropertyValues;
7+
import org.springframework.boot.bind.RelaxedDataBinder;
8+
import org.springframework.context.EnvironmentAware;
9+
import org.springframework.core.env.ConfigurableEnvironment;
10+
import org.springframework.core.env.Environment;
11+
12+
import com.samskivert.mustache.DefaultCollector;
13+
import com.samskivert.mustache.Mustache;
14+
import com.samskivert.mustache.Mustache.VariableFetcher;
15+
16+
/**
17+
* @author Dave Syer
18+
* @since 1.2.2
19+
*/
20+
public class MustacheEnvironmentCollector extends DefaultCollector implements
21+
EnvironmentAware {
22+
23+
private ConfigurableEnvironment environment;
24+
private Map<String, Object> target;
25+
26+
@Override
27+
public void setEnvironment(Environment environment) {
28+
this.environment = (ConfigurableEnvironment) environment;
29+
this.target = new HashMap<String, Object>();
30+
new RelaxedDataBinder(this.target).bind(new PropertySourcesPropertyValues(
31+
this.environment.getPropertySources()));
32+
}
33+
34+
@Override
35+
public Mustache.VariableFetcher createFetcher(Object ctx, String name) {
36+
VariableFetcher fetcher = super.createFetcher(ctx, name);
37+
if (fetcher != null) {
38+
return fetcher;
39+
}
40+
if (this.environment.containsProperty(name)) {
41+
return new VariableFetcher() {
42+
43+
@Override
44+
public Object get(Object ctx, String name) throws Exception {
45+
return MustacheEnvironmentCollector.this.environment
46+
.getProperty(name);
47+
}
48+
49+
};
50+
}
51+
if (this.target.containsKey(name)) {
52+
return new VariableFetcher() {
53+
54+
@Override
55+
public Object get(Object ctx, String name) throws Exception {
56+
return MustacheEnvironmentCollector.this.target.get(name);
57+
}
58+
59+
};
60+
}
61+
return null;
62+
}
63+
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2013-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.mustache;
18+
19+
import org.springframework.boot.autoconfigure.template.AbstractViewResolverProperties;
20+
import org.springframework.boot.context.properties.ConfigurationProperties;
21+
22+
/**
23+
* @author Dave Syer
24+
* @since 1.2.2
25+
*
26+
*/
27+
@ConfigurationProperties(prefix = "spring.mustache")
28+
public class MustacheProperties extends AbstractViewResolverProperties {
29+
30+
public static final String DEFAULT_PREFIX = "classpath:/templates/";
31+
32+
public static final String DEFAULT_SUFFIX = ".html";
33+
34+
/**
35+
* Prefix to apply to template names.
36+
*/
37+
private String prefix = DEFAULT_PREFIX;
38+
39+
/**
40+
* Suffix to apply to template names.
41+
*/
42+
private String suffix = DEFAULT_SUFFIX;
43+
44+
public String getPrefix() {
45+
return this.prefix;
46+
}
47+
48+
public void setPrefix(String prefix) {
49+
this.prefix = prefix;
50+
}
51+
52+
public String getSuffix() {
53+
return this.suffix;
54+
}
55+
56+
public void setSuffix(String suffix) {
57+
this.suffix = suffix;
58+
}
59+
60+
}

0 commit comments

Comments
 (0)