Skip to content

Commit

Permalink
Mustache support for Spring MVC
Browse files Browse the repository at this point in the history
  • Loading branch information
Bart Tegenbosch committed Aug 26, 2014
1 parent 40854d1 commit 18fb3ef
Show file tree
Hide file tree
Showing 15 changed files with 694 additions and 0 deletions.
55 changes: 55 additions & 0 deletions spring-mvc-extension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#Mustache extension for Spring MVC

To enable mustache views in your Spring MVC application add the `@EnableMustache` annotation to your configuration class.

###Support for messages and themes

This extension provides annotations to let you handle message resolving in your model attributes.

<table>
<thead>
<tr>
<th>Annotation</th>
<th>Description</th>
</thead>
<tbody>
<tr>
<td>@Message</td>
<td>Annotated methods will have their return values resolved to a message.</td>
</tr>
<tr>
<td>@Theme</td>
<td>Annotated methods will have their return values resolved to a theme message.</td>
</tr>
</tbody>
</table>

Both `@Message` and `@Theme` can resolve embedded values.

public class MustacheGreetingContext {

private final String name;

public MustacheGreetingContext() {
this("name");
}

public MustacheGreetingContext(final String name) {
this.name = name;
}

@Message
public String getGreeting() {
return "${my.greeting.property}";
}

@Message
public String getName() {
return name;
}

@Theme
public String getColor() {
return "color";
}
}
113 changes: 113 additions & 0 deletions spring-mvc-extension/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>nl.onedott.mustachejava.extension</groupId>
<artifactId>springmvc</artifactId>
<version>0.9.0.RELEASE</version>
<description>Spring MVC extension for mustache.java</description>
<url>http://github.com/spullara/mustache.java</url>

<developers>
<developer>
<name>Bart Tegenbosch</name>
<email>bart@onedott.nl</email>
<organization>Onedott</organization>
<organizationUrl>http://www.onedott.nl</organizationUrl>
</developer>
</developers>

<properties>
<spring.version>3.2.0.RELEASE</spring.version>
<!--<spring.version>4.0.5.RELEASE</spring.version>-->
</properties>

<dependencies>
<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.8.16</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<argLine>-Xmx128M</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package nl.onedott.mustachejava.extension.springmvc;

import com.github.mustachejava.MustacheException;

/**
* @author Bart Tegenbosch
*/
public class SpringMustacheException extends MustacheException {
public SpringMustacheException(final String message) {
super(message);
}

public SpringMustacheException(final String message, final Throwable cause) {
super(message, cause);
}

public SpringMustacheException(final Throwable cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package nl.onedott.mustachejava.extension.springmvc.annotation;

import nl.onedott.mustachejava.extension.springmvc.config.MustacheConfiguration;
import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

/**
* Enable Mustache views and model processing for Spring MVC.
*
* @author Bart Tegenbosch
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MustacheConfiguration.class)
public @interface EnableMustache {
/*
* The resource location for mustache templates.
* Supports resource prefixes like {@code file:} and {@code classpath:}
*/
String value() default "mustache/";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package nl.onedott.mustachejava.extension.springmvc.annotation;

import java.lang.annotation.*;

/**
* @author Bart Tegenbosch
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Message {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package nl.onedott.mustachejava.extension.springmvc.annotation;

import java.lang.annotation.*;

/**
* @author Bart Tegenbosch
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Theme {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package nl.onedott.mustachejava.extension.springmvc.config;

import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.MustacheFactory;
import nl.onedott.mustachejava.extension.springmvc.annotation.EnableMustache;
import nl.onedott.mustachejava.extension.springmvc.mustache.MessageSupportReflectionObjectHandler;
import nl.onedott.mustachejava.extension.springmvc.view.MustacheView;
import nl.onedott.mustachejava.extension.springmvc.view.MustacheViewResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.web.servlet.ViewResolver;

import java.util.Map;

/**
* Imported by using the {@link nl.onedott.mustachejava.extension.springmvc.annotation.EnableMustache} annotation.
*
* @author Bart Tegenbosch
*/
@Configuration
public class MustacheConfiguration implements ImportAware {

@Autowired
private ApplicationContext context;

private Resource resourceLocation;

@Override
public void setImportMetadata(final AnnotationMetadata importMetadata) {
String className = EnableMustache.class.getName();
setProperties(importMetadata.getAnnotationAttributes(className));
}

@Bean
public MustacheFactory mustacheFactory() throws Exception {
DefaultMustacheFactory factory = new DefaultMustacheFactory(resourceLocation.getFile());
factory.setObjectHandler(new MessageSupportReflectionObjectHandler(context));
return factory;
}

@Bean
public ViewResolver viewResolver() throws Exception {
MustacheViewResolver viewResolver = new MustacheViewResolver(mustacheFactory());

viewResolver.setViewClass(MustacheView.class);
viewResolver.setSuffix(".mustache");
return viewResolver;
}

public void setProperties(final Map<String,Object> attributes) {
String pattern = (String) attributes.get("value");
resourceLocation = context.getResource(pattern);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package nl.onedott.mustachejava.extension.springmvc.mustache;

import com.github.mustachejava.reflect.ReflectionObjectHandler;
import com.github.mustachejava.reflect.ReflectionWrapper;
import com.github.mustachejava.util.Wrapper;
import nl.onedott.mustachejava.extension.springmvc.annotation.Message;
import nl.onedott.mustachejava.extension.springmvc.annotation.Theme;
import org.springframework.context.MessageSource;
import org.springframework.util.Assert;

import java.lang.reflect.Method;

/**
* Enables wrapper with message support.
* @author Bart Tegenbosch
*/
public class MessageSupportReflectionObjectHandler extends ReflectionObjectHandler {

private final MessageSource messageSource;

public MessageSupportReflectionObjectHandler(final MessageSource messageSource) {
Assert.notNull(messageSource);
this.messageSource = messageSource;
}

@Override
public Wrapper find(final String name, final Object[] scopes) {
Wrapper wrapper = super.find(name, scopes);
if (wrapper instanceof ReflectionWrapper) {
ReflectionWrapper w = (ReflectionWrapper) wrapper;
Method method = w.getMethod();

if (method.isAnnotationPresent(Message.class) || method.isAnnotationPresent(Theme.class)) {
wrapper = new MessageSupportReflectionWrapper(w, messageSource);
}
}

return wrapper;
}
}
Loading

0 comments on commit 18fb3ef

Please sign in to comment.