You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by sg...@apache.org on 2021/01/05 21:24:59 UTC

[freemarker-generator] branch FREEMARKER-161 updated: FREEMARKER-161 [freemarker-generator] Allow multiple transformations on the CLI

This is an automated email from the ASF dual-hosted git repository.

sgoeschl pushed a commit to branch FREEMARKER-161
in repository https://gitbox.apache.org/repos/asf/freemarker-generator.git


The following commit(s) were added to refs/heads/FREEMARKER-161 by this push:
     new bdd9487  FREEMARKER-161 [freemarker-generator] Allow multiple transformations on the CLI
bdd9487 is described below

commit bdd94872e6c5882620bc2b21d07dede89a8d1232
Author: Siegfried Goeschl <si...@gmail.com>
AuthorDate: Tue Jan 5 22:24:33 2021 +0100

    FREEMARKER-161 [freemarker-generator] Allow multiple transformations on the CLI
---
 .../generator/base/output/OutputGenerator.java     |  4 +-
 .../generator/base/template/TemplateOutput.java    | 28 ++-----------
 .../template/TemplateTransformationsBuilder.java   | 30 +++++++++-----
 .../TemplateTransformationsBuilderTest.java        | 18 ++++-----
 .../org/apache/freemarker/generator/cli/Main.java  |  9 +----
 .../cli/config/ConfigurationSupplier.java          |  7 +++-
 .../cli/config/OutputGeneratorsSupplier.java       |  5 ++-
 .../freemarker/generator/cli/config/Suppliers.java |  6 +--
 .../generator/cli/task/FreeMarkerTask.java         | 46 +++++++++++++++-------
 .../site/markdown/cli/concepts/transformation.md   | 12 ++++++
 .../freemarker/generator/cli/ExamplesTest.java     | 11 ++++++
 .../cli/config/ConfigurationSupplierTest.java      |  2 +-
 12 files changed, 105 insertions(+), 73 deletions(-)

diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/output/OutputGenerator.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/output/OutputGenerator.java
index a9cfc37..5ce4cf4 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/output/OutputGenerator.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/output/OutputGenerator.java
@@ -39,7 +39,7 @@ public class OutputGenerator {
     /** Data sources used for the transformation */
     private final List<DataSource> dataSources;
 
-    /** Data sources used for the transformation */
+    /** Variables (as a map) used for the transformation */
     private final Map<String, Object> variables;
 
     public OutputGenerator(
@@ -74,6 +74,8 @@ public class OutputGenerator {
         return "OutputGenerator{" +
                 "templateSource=" + templateSource +
                 ", templateOutput=" + templateOutput +
+                ", dataSources=" + dataSources +
+                ", variables=" + variables +
                 '}';
     }
 }
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java
index 818d66d..a73a849 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java
@@ -16,11 +16,7 @@
  */
 package org.apache.freemarker.generator.base.template;
 
-import org.apache.freemarker.generator.base.util.Validate;
-
 import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
 import java.io.Writer;
 
 import static java.util.Objects.requireNonNull;
@@ -59,20 +55,12 @@ public class TemplateOutput {
         return writer;
     }
 
-    public File getFile() {
-        return file;
-    }
-
-    public boolean isWrittenToFile() {
-        return file != null;
-    }
-
-    public boolean isWrittenToSuppliedWriter() {
+    public boolean hasWriter() {
         return writer != null;
     }
 
-    public Writer writer() {
-        return writer != null ? writer : fileWriter();
+    public File getFile() {
+        return file;
     }
 
     @Override
@@ -82,14 +70,4 @@ public class TemplateOutput {
                 ", file=" + file +
                 '}';
     }
-
-    private FileWriter fileWriter() {
-        Validate.notNull(file, "Output file is null");
-
-        try {
-            return new FileWriter(file);
-        } catch (IOException e) {
-            throw new RuntimeException("Failed to create FileWriter: " + file.getAbsolutePath(), e);
-        }
-    }
 }
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java
index 5561cb7..aee4438 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java
@@ -27,6 +27,7 @@ import java.io.BufferedWriter;
 import java.io.File;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -56,15 +57,19 @@ public class TemplateTransformationsBuilder {
     /** Optional output file(s) or directory - if none is defined everything is written to a user-supplied writer */
     private final List<String> outputs;
 
-    /** Optional user-supplied writer */
-    private Writer userSuppliedWriter;
+    /** Optional output encoding */
+    private Charset outputEncoding;
+
+    /** Optional caller-supplied writer used for testing */
+    private Writer callerSuppliedWriter;
 
     private TemplateTransformationsBuilder() {
         this.templateSources = new ArrayList<>();
         this.includes = new ArrayList<>();
         this.excludes = new ArrayList<>();
         this.outputs = new ArrayList<>();
-        this.userSuppliedWriter = null;
+        this.callerSuppliedWriter = null;
+        this.outputEncoding = UTF_8;
     }
 
     public static TemplateTransformationsBuilder builder() {
@@ -137,8 +142,16 @@ public class TemplateTransformationsBuilder {
         return this;
     }
 
-    public TemplateTransformationsBuilder setUserSuppliedWriter(Writer userSuppliedWriter) {
-        this.userSuppliedWriter = userSuppliedWriter;
+    public TemplateTransformationsBuilder setOutputEncoding(Charset outputEncoding) {
+        if (outputEncoding != null) {
+            this.outputEncoding = outputEncoding;
+        }
+
+        return this;
+    }
+
+    public TemplateTransformationsBuilder setCallerSuppliedWriter(Writer callerSuppliedWriter) {
+        this.callerSuppliedWriter = callerSuppliedWriter;
         return this;
     }
 
@@ -215,13 +228,12 @@ public class TemplateTransformationsBuilder {
     }
 
     private TemplateOutput templateOutput(File templateOutputFile) {
-        if (userSuppliedWriter != null) {
-            return TemplateOutput.fromWriter(userSuppliedWriter);
+        if (callerSuppliedWriter != null) {
+            return TemplateOutput.fromWriter(callerSuppliedWriter);
         } else if (templateOutputFile != null) {
             return TemplateOutput.fromFile(templateOutputFile);
         } else {
-            // @TODO FREEMARKER-161 sgoeschl Shall we close the writer or use "userSuppliedWriter"?
-            return TemplateOutput.fromWriter(new BufferedWriter(new OutputStreamWriter(System.out, UTF_8)));
+            return TemplateOutput.fromWriter(new BufferedWriter(new OutputStreamWriter(System.out, outputEncoding)));
         }
     }
 
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java
index 42e933e..c560ae7 100644
--- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java
@@ -54,7 +54,7 @@ public class TemplateTransformationsBuilderTest {
     public void shouldCreateFromInteractiveTemplate() {
         final List<TemplateTransformation> transformations = builder()
                 .setInteractiveTemplate("Hello World")
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
 
         assertEquals(1, transformations.size());
@@ -77,7 +77,7 @@ public class TemplateTransformationsBuilderTest {
         builder()
                 .setInteractiveTemplate("Hello World")
                 .addTemplateSource(ANY_TEMPLATE_FILE_NAME)
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
     }
 
@@ -87,7 +87,7 @@ public class TemplateTransformationsBuilderTest {
     public void shouldCreateFromTemplateFile() {
         final List<TemplateTransformation> transformations = builder()
                 .addTemplateSource(ANY_TEMPLATE_FILE_NAME)
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
 
         assertEquals(1, transformations.size());
@@ -125,7 +125,7 @@ public class TemplateTransformationsBuilderTest {
     public void shouldCreateFromTemplatePath() {
         final List<TemplateTransformation> transformations = builder()
                 .addTemplateSource(ANY_TEMPLATE_PATH)
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
 
         assertEquals(1, transformations.size());
@@ -149,7 +149,7 @@ public class TemplateTransformationsBuilderTest {
     public void shouldCreateFromTemplateDirectory() {
         final List<TemplateTransformation> transformations = builder()
                 .addTemplateSource(ANY_TEMPLATE_DIRECTORY_NAME)
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
 
         assertEquals(2, transformations.size());
@@ -174,7 +174,7 @@ public class TemplateTransformationsBuilderTest {
         final List<TemplateTransformation> transformations = builder()
                 .addTemplateSource(ANY_TEMPLATE_DIRECTORY_NAME)
                 .addInclude("*.properties")
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
 
         assertEquals(1, transformations.size());
@@ -186,7 +186,7 @@ public class TemplateTransformationsBuilderTest {
         final List<TemplateTransformation> transformations = builder()
                 .addTemplateSource(ANY_TEMPLATE_DIRECTORY_NAME)
                 .addExclude("*.ftl")
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
 
         assertEquals(1, transformations.size());
@@ -199,7 +199,7 @@ public class TemplateTransformationsBuilderTest {
     public void shouldCreateFromTemplateUrl() {
         final List<TemplateTransformation> transformations = builder()
                 .addTemplateSource(ANY_TEMPLATE_URL)
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
 
         final TemplateSource templateSource = transformations.get(0).getTemplateSource();
@@ -218,7 +218,7 @@ public class TemplateTransformationsBuilderTest {
     public void shouldCreateFromTemplateEnvironmentVariable() {
         final List<TemplateTransformation> transformations = builder()
                 .addTemplateSource(ANY_ENV_URI)
-                .setUserSuppliedWriter(stdoutWriter())
+                .setCallerSuppliedWriter(stdoutWriter())
                 .build();
 
         final TemplateSource templateSource = transformations.get(0).getTemplateSource();
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
index b737357..2f34edb 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
@@ -20,7 +20,6 @@ import org.apache.freemarker.generator.base.FreeMarkerConstants.Configuration;
 import org.apache.freemarker.generator.base.FreeMarkerConstants.SystemProperties;
 import org.apache.freemarker.generator.base.parameter.ParameterModelSupplier;
 import org.apache.freemarker.generator.base.util.ClosableUtils;
-import org.apache.freemarker.generator.base.util.MapBuilder;
 import org.apache.freemarker.generator.cli.config.Settings;
 import org.apache.freemarker.generator.cli.picocli.GitVersionProvider;
 import org.apache.freemarker.generator.cli.picocli.OutputGeneratorDefinition;
@@ -33,10 +32,7 @@ import picocli.CommandLine.Option;
 import picocli.CommandLine.Parameters;
 import picocli.CommandLine.Spec;
 
-import java.io.BufferedWriter;
 import java.io.File;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -46,7 +42,6 @@ import java.util.Properties;
 import java.util.concurrent.Callable;
 import java.util.stream.IntStream;
 
-import static java.util.Arrays.asList;
 import static java.util.Objects.requireNonNull;
 import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty;
 import static org.apache.freemarker.generator.base.util.StringUtils.isNotEmpty;
@@ -54,7 +49,6 @@ import static org.apache.freemarker.generator.cli.config.Suppliers.configuration
 import static org.apache.freemarker.generator.cli.config.Suppliers.outputGeneratorsSupplier;
 import static org.apache.freemarker.generator.cli.config.Suppliers.propertiesSupplier;
 import static org.apache.freemarker.generator.cli.config.Suppliers.templateDirectorySupplier;
-import static org.apache.freemarker.generator.cli.config.Suppliers.toolsSupplier;
 
 @Command(description = "Apache FreeMarker Generator", name = "freemarker-generator", mixinStandardHelpOptions = true, versionProvider = GitVersionProvider.class)
 public class Main implements Callable<Integer> {
@@ -162,7 +156,8 @@ public class Main implements Callable<Integer> {
             final FreeMarkerTask freeMarkerTask = new FreeMarkerTask(
                     configurationSupplier(settings),
                     outputGeneratorsSupplier(settings),
-                    () -> MapBuilder.merge(asList(toolsSupplier(settings).get(), settings.getUserParameters()))
+                    settings::getUserParameters,
+                    Collections::emptyList
             );
             return freeMarkerTask.call();
         } finally {
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplier.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplier.java
index 8f45e90..3bce48d 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplier.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplier.java
@@ -40,10 +40,12 @@ public class ConfigurationSupplier implements Supplier<Configuration> {
 
     private final Settings settings;
     private final Supplier<TemplateLoader> templateLoader;
+    private final ToolsSupplier toolsSupplier;
 
-    public ConfigurationSupplier(Settings settings, Supplier<TemplateLoader> templateLoader) {
+    public ConfigurationSupplier(Settings settings, Supplier<TemplateLoader> templateLoader, ToolsSupplier toolsSupplier) {
         this.settings = requireNonNull(settings);
         this.templateLoader = requireNonNull(templateLoader);
+        this.toolsSupplier = requireNonNull(toolsSupplier);
     }
 
     @Override
@@ -63,6 +65,9 @@ public class ConfigurationSupplier implements Supplier<Configuration> {
             configuration.setOutputEncoding(settings.getOutputEncoding().name());
             configuration.setTemplateLoader(templateLoader.get());
 
+            // instantiate the tools as shared FreeMarker variables
+            configuration.setSharedVariables(toolsSupplier.get());
+
             return configuration;
         } catch (Exception e) {
             throw new RuntimeException("Failed to create FreeMarker configuration", e);
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/OutputGeneratorsSupplier.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/OutputGeneratorsSupplier.java
index b49dce0..e7fad76 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/OutputGeneratorsSupplier.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/OutputGeneratorsSupplier.java
@@ -46,13 +46,16 @@ public class OutputGeneratorsSupplier implements Supplier<List<OutputGenerator>>
         }
 
         // set the writer
-        builder.setUserSuppliedWriter(settings.getCallerSuppliedWriter());
+        builder.setCallerSuppliedWriter(settings.getCallerSuppliedWriter());
 
         // set template output
         if (templateOutputDefinition != null) {
             builder.addOutputs(templateOutputDefinition.outputs);
         }
 
+        // set the output encoding
+        builder.setOutputEncoding(settings.getOutputEncoding());
+
         // set template filter
         if (definition.hasTemplateSourceIncludes()) {
             builder.addInclude(definition.getTemplateSourceFilterDefinition().templateIncludePatterns.get(0));
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java
index 793318e..c38e980 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java
@@ -29,11 +29,7 @@ import java.util.function.Supplier;
 public class Suppliers {
 
     public static ConfigurationSupplier configurationSupplier(Settings settings) {
-        return new ConfigurationSupplier(settings, templateLoaderSupplier(settings));
-    }
-
-    public static ConfigurationSupplier configurationSupplier(Settings settings, Supplier<TemplateLoader> templateLoader) {
-        return new ConfigurationSupplier(settings, templateLoader);
+        return new ConfigurationSupplier(settings, templateLoaderSupplier(settings), toolsSupplier(settings));
     }
 
     public static TemplateDirectorySupplier templateDirectorySupplier(String additionalTemplateDirName) {
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java
index 19a4634..6858f55 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java
@@ -20,6 +20,7 @@ import freemarker.template.Configuration;
 import freemarker.template.Template;
 import freemarker.template.TemplateException;
 import org.apache.commons.io.FileUtils;
+import org.apache.freemarker.generator.base.datasource.DataSource;
 import org.apache.freemarker.generator.base.datasource.DataSources;
 import org.apache.freemarker.generator.base.output.OutputGenerator;
 import org.apache.freemarker.generator.base.template.TemplateOutput;
@@ -31,11 +32,14 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.Writer;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static java.util.Objects.requireNonNull;
 import static org.apache.freemarker.generator.base.FreeMarkerConstants.Model.DATASOURCES;
@@ -56,13 +60,16 @@ public class FreeMarkerTask implements Callable<Integer> {
     private final Supplier<Configuration> configurationSupplier;
     private final Supplier<List<OutputGenerator>> outputGeneratorsSupplier;
     private final Supplier<Map<String, Object>> sharedDataModelSupplier;
+    private final Supplier<List<DataSource>> sharedDataSourcesSupplier;
 
     public FreeMarkerTask(Supplier<Configuration> configurationSupplier,
                           Supplier<List<OutputGenerator>> outputGeneratorsSupplier,
-                          Supplier<Map<String, Object>> sharedDataModelSupplier) {
+                          Supplier<Map<String, Object>> sharedDataModelSupplier,
+                          Supplier<List<DataSource>> sharedDataSourcesSupplier) {
         this.configurationSupplier = requireNonNull(configurationSupplier, "configurationSupplier");
         this.outputGeneratorsSupplier = requireNonNull(outputGeneratorsSupplier, "outputGeneratorsSupplier");
         this.sharedDataModelSupplier = requireNonNull(sharedDataModelSupplier, "sharedDataModelSupplier");
+        this.sharedDataSourcesSupplier = requireNonNull(sharedDataSourcesSupplier, "sharedDataSourcesSupplier");
     }
 
     @Override
@@ -70,19 +77,26 @@ public class FreeMarkerTask implements Callable<Integer> {
         final Configuration configuration = configurationSupplier.get();
         final List<OutputGenerator> outputGenerators = outputGeneratorsSupplier.get();
         final Map<String, Object> sharedDataModel = sharedDataModelSupplier.get();
-        outputGenerators.forEach(outputGenerator -> process(configuration, outputGenerator, sharedDataModel));
+        final List<DataSource> sharedDataSources = sharedDataSourcesSupplier.get();
+
+        outputGenerators.forEach(outputGenerator -> process(
+                configuration,
+                outputGenerator,
+                sharedDataModel,
+                sharedDataSources));
+
         return SUCCESS;
     }
 
     private void process(Configuration configuration,
                          OutputGenerator outputGenerator,
-                         Map<String, Object> sharedDataModelMap) {
-
+                         Map<String, Object> sharedDataModelMap,
+                         List<DataSource> sharedDataSources) {
         final TemplateSource templateSource = outputGenerator.getTemplateSource();
         final TemplateOutput templateOutput = outputGenerator.getTemplateOutput();
-        final DataSources dataSources = new DataSources(outputGenerator.getDataSources());
-        final Map<String, Object> dataModelMap = outputGenerator.getVariables();
-        final Map<String, Object> dataModel = toDataModel(dataSources, dataModelMap, sharedDataModelMap);
+        final DataSources dataSources = toDataSources(outputGenerator, sharedDataSources);
+        final Map<String, Object> variables = outputGenerator.getVariables();
+        final Map<String, Object> dataModel = toDataModel(dataSources, variables, sharedDataModelMap);
 
         try (Writer writer = writer(templateOutput)) {
             final Template template = template(configuration, templateSource);
@@ -92,6 +106,11 @@ public class FreeMarkerTask implements Callable<Integer> {
         }
     }
 
+    private static DataSources toDataSources(OutputGenerator outputGenerator, List<DataSource> sharedDataSources) {
+        return new DataSources(Stream.of(outputGenerator.getDataSources(), sharedDataSources)
+                .flatMap(Collection::stream).collect(Collectors.toList()));
+    }
+
     @SafeVarargs
     private static Map<String, Object> toDataModel(DataSources dataSources, Map<String, Object>... maps) {
         final Map<String, Object> result = new HashMap<>();
@@ -101,13 +120,13 @@ public class FreeMarkerTask implements Callable<Integer> {
     }
 
     private static Writer writer(TemplateOutput templateOutput) throws IOException {
-        if (templateOutput.getWriter() != null) {
+        if (templateOutput.hasWriter()) {
             return templateOutput.getWriter();
+        } else {
+            final File file = templateOutput.getFile();
+            FileUtils.forceMkdirParent(file);
+            return new BufferedWriter(new FileWriter(file));
         }
-
-        final File file = templateOutput.getFile();
-        FileUtils.forceMkdirParent(file);
-        return new BufferedWriter(new FileWriter(file));
     }
 
     /**
@@ -127,7 +146,7 @@ public class FreeMarkerTask implements Callable<Integer> {
             case TEMPLATE_CODE:
                 return fromTemplateCode(configuration, templateSource);
             default:
-                throw new IllegalArgumentException("Don't know how to handle: " + templateSource.getOrigin());
+                throw new IllegalArgumentException("Don't know how to create a template: " + templateSource.getOrigin());
         }
     }
 
@@ -142,7 +161,6 @@ public class FreeMarkerTask implements Callable<Integer> {
 
     private static Template fromTemplateCode(Configuration configuration, TemplateSource templateSource) {
         final String name = templateSource.getName();
-
         try {
             return new Template(name, templateSource.getCode(), configuration);
         } catch (IOException e) {
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
index 03a9b3a..306d66e 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
@@ -72,3 +72,15 @@ target
         `-- nginx.conf
 
 ```
+
+Transforming multiple templates and data sources to multiple output files
+
+```
+freemarker-generator \
+-t freemarker-generator/yaml/json/transform.ftl -s examples/data/yaml/customer.yaml -o customer.json \
+-t freemarker-generator/yaml/json/transform.ftl -s examples/data/yaml/swagger-spec.yaml -o swagger-spec.json
+
+> ls -l *.json
+-rw-r--r--  1 sgoeschl  staff   332B Jan  5 21:30 customer.json
+-rw-r--r--  1 sgoeschl  staff    25K Jan  5 21:30 swagger-spec.json
+```  
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java
index 045bb42..736be95 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java
@@ -147,6 +147,17 @@ public class ExamplesTest extends AbstractMainTest {
         assertValid(execute("-t freemarker-generator/csv/md/transform.ftl -o target/contract.md -t freemarker-generator/csv/html/transform.ftl -o target/contract.html src/app/examples/data/csv/contract.csv"));
     }
 
+
+    @Test
+    public void shouldTransformMultipleTemplatesAndDataSources() throws IOException {
+        final String output = execute(
+                "-t freemarker-generator/yaml/json/transform.ftl -s src/app/examples/data/yaml/swagger-spec.yaml -o swagger-spec.json " +
+                        "-t freemarker-generator/yaml/json/transform.ftl -s src/app/examples/data/yaml/customer.yaml -o customer.json");
+
+        assertTrue("Swagger file content is missing", output.contains("This is a sample server Petstore server"));
+        assertTrue("Customer data is missing", output.contains("Xyz, DEF Street"));
+    }
+
     @Test
     public void shouldSupportDataSourcesAccessInFTL() throws IOException {
         final String args = "users=src/app/examples/data/json/github-users.json contract=src/app/examples/data/csv/contract.csv";
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
index ac817f6..67721b9 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
@@ -51,7 +51,7 @@ public class ConfigurationSupplierTest {
     }
 
     private ConfigurationSupplier configurationSupplier(Settings settings) {
-        return new ConfigurationSupplier(settings, templateLoaderSupplier());
+        return new ConfigurationSupplier(settings, templateLoaderSupplier(), Suppliers.toolsSupplier(settings));
     }
 
     private TemplateLoaderSupplier templateLoaderSupplier() {