If you want to use FreeMarker along with jersey, I wrote a Provider
for that and I wanted to share it with you. You just need to annotate
any POJO with @FreeMarkerModel annotation and return an instance of
that class in your resource methods. The returned bean will be used as
the model to the FreeMarker template.
Example usage:
@FreeMarkerModel(template="index.html")
class Index {
public String getMessage() {
return "Hello jersey";
}
}
@Path("/")
public class WebPages {
@GET
@Produces("text/html")
public Index getIndex() {
return new Index();
}
}
index.html:
----------------------------------------------
<html>
<body>${message}</body>
</html>
Here is the code:
FreeMarkerProvider.java
-----------------------------------------------
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Properties;
/**
* Author: Erdinc YILMAZEL
* Date: Mar 9, 2009
* Time: 12:41:20 PM
*/
@Provider
@Produces({"text/plain", "text/html"})
public class FreeMarkerProvider implements MessageBodyWriter<Object> {
String templateBaseDir;
Configuration cfg;
public FreeMarkerProvider() throws IOException {
InputStream in =
this.getClass().getClassLoader().getResourceAsStream("/templates.properties");
if (in != null) {
Properties properties = new Properties();
try {
properties.load(in);
templateBaseDir = (String) properties.get("templateBaseDir");
} catch (IOException e) {
//
}
}
if (templateBaseDir == null) {
templateBaseDir = "/templates";
}
cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(new File(templateBaseDir));
cfg.setObjectWrapper(new DefaultObjectWrapper());
}
@Override
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return type.isAnnotationPresent(FreeMarkerModel.class);
}
@Override
public long getSize(Object o, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return -1;
}
@Override
public void writeTo(Object o,
Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException,
WebApplicationException {
FreeMarkerModel c = type.getAnnotation(FreeMarkerModel.class);
if (c != null) {
httpHeaders.putSingle("Content-Type", mediaType.toString() +
"; charset=" + c.encoding());
Template temp = cfg.getTemplate(c.template(), c.encoding());
OutputStreamWriter outputStreamWriter = new
OutputStreamWriter(entityStream, c.encoding());
try {
temp.process(o, outputStreamWriter);
outputStreamWriter.flush();
} catch (TemplateException e) {
e.printStackTrace();
}
}
}
}
---------------------------------------
FreeMarkerModel.java
----------------------------------------
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Author: Erdinc YILMAZEL
* Date: Mar 9, 2009
* Time: 12:39:25 PM
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FreeMarkerModel {
String template();
String encoding() default "UTF-8";
}