diff --git a/processor/src/main/java/org/mapstruct/ap/writer/ModelWriter.java b/processor/src/main/java/org/mapstruct/ap/writer/ModelWriter.java index 803182e0c..93c938e5b 100644 --- a/processor/src/main/java/org/mapstruct/ap/writer/ModelWriter.java +++ b/processor/src/main/java/org/mapstruct/ap/writer/ModelWriter.java @@ -19,14 +19,25 @@ package org.mapstruct.ap.writer; import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; + import javax.tools.JavaFileObject; +import org.mapstruct.ap.writer.Writable.Context; + +import freemarker.cache.StrongCacheStorage; +import freemarker.cache.TemplateLoader; import freemarker.log.Logger; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; -import org.mapstruct.ap.writer.Writable.Context; /** * Writes Java source files based on given mapper models, using a FreeMarker @@ -50,13 +61,17 @@ public class ModelWriter { throw new RuntimeException( e ); } - CONFIGURATION = new Configuration(); - CONFIGURATION.setClassForTemplateLoading( ModelWriter.class, "/" ); - CONFIGURATION.setObjectWrapper( new DefaultObjectWrapper() ); + CONFIGURATION = new Configuration( Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS ); + CONFIGURATION.setTemplateLoader( new SimpleClasspathLoader() ); + CONFIGURATION.setObjectWrapper( new DefaultObjectWrapper( Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS ) ); CONFIGURATION.setSharedVariable( "includeModel", new ModelIncludeDirective( CONFIGURATION ) ); + // do not refresh/gc the cached templates, as we never change them at runtime + CONFIGURATION.setCacheStorage( new StrongCacheStorage() ); + CONFIGURATION.setTemplateUpdateDelay( Integer.MAX_VALUE ); + CONFIGURATION.setLocalizedLookup( false ); } public void writeModel(JavaFileObject sourceFile, Writable model) { @@ -65,6 +80,7 @@ public class ModelWriter { Map, Object> values = new HashMap, Object>(); values.put( Configuration.class, CONFIGURATION ); + model.write( new DefaultModelElementWriterContext( values ), writer ); writer.flush(); @@ -79,8 +95,42 @@ public class ModelWriter { } /** - * {@link Context} implementation which provides access to the current - * FreeMarker {@link Configuration}. + * Simplified template loader that avoids reading modification timestamps and disables the jar-file caching. + * + * @author Andreas Gudian + */ + private static final class SimpleClasspathLoader implements TemplateLoader { + @Override + public Reader getReader(Object name, String encoding) throws IOException { + URL url = getClass().getClassLoader().getResource( String.valueOf( name ) ); + + URLConnection connection = url.openConnection(); + + // don't use jar-file caching, as it caused occasionally closed input streams [at least under JDK 1.8.0_25] + connection.setUseCaches( false ); + + InputStream is = connection.getInputStream(); + + return new InputStreamReader( is, Charset.forName( "UTF-8" ) ); + } + + @Override + public long getLastModified(Object templateSource) { + return 0; + } + + @Override + public Object findTemplateSource(String name) throws IOException { + return name; + } + + @Override + public void closeTemplateSource(Object templateSource) throws IOException { + } + } + + /** + * {@link Context} implementation which provides access to the current FreeMarker {@link Configuration}. * * @author Gunnar Morling */