Created Yang to Java Builder pattern class generator 02/702/3
authormsunal <msunal@cisco.com>
Thu, 25 Jul 2013 11:37:39 +0000 (13:37 +0200)
committermsunal <msunal@cisco.com>
Fri, 26 Jul 2013 09:13:24 +0000 (11:13 +0200)
- added Xtend tool to dependencies
- created builder xtend class template
- created BuilderClassDescriptor class which is used as source of information in template
- integrated generating of Builder pattern classes for interfaces
- updated jUnit test

Maven generates .java file as a translation of .xtend template into src/main/xtend-gen. Therefore /binding-java-api-generator/src/main/xtend-gen was added into .gitignore file.
If you use Xtend plugin for Eclipse, you should check a configuration of Xtend compiler in Eclipse, whether there is choosen xtend-gen as an output direcotory.

Change-Id: I72e733c7d8f2587848b0e0d32368f7f1700a44d0
Signed-off-by: Martin Sunal <msunal@cisco.com>
opendaylight/sal/yang-prototype/code-generator/.gitignore
opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/pom.xml
opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderClassDescriptor.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderGenerator.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderTemplate.xtend [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/Constants.java
opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/GeneratorJavaFile.java
opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/controller/sal/java/api/generator/test/GeneratorJavaFileTest.java

index fad725b..86c8a8a 100644 (file)
@@ -7,6 +7,39 @@
         <version>0.5.4-SNAPSHOT</version>\r
     </parent>\r
     <artifactId>binding-java-api-generator</artifactId>\r
+    <build>\r
+        <plugins>\r
+            <plugin>\r
+                <groupId>org.eclipse.xtend</groupId>\r
+                <artifactId>xtend-maven-plugin</artifactId>\r
+                <version>2.4.2</version>\r
+                <executions>\r
+                    <execution>\r
+                        <goals>\r
+                            <goal>compile</goal>\r
+                        </goals>\r
+                        <configuration>\r
+                             <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>\r
+                        </configuration>\r
+                    </execution>\r
+                </executions>\r
+            </plugin>\r
+            <plugin>\r
+               <artifactId>maven-clean-plugin</artifactId>\r
+                           <version>2.4.1</version>\r
+                           <configuration>\r
+                               <filesets>\r
+                                   <fileset>\r
+                                       <directory>${basedir}/src/main/xtend-gen</directory>\r
+                                       <includes>\r
+                                           <include>**</include>\r
+                                       </includes>\r
+                                   </fileset>\r
+                               </filesets>\r
+                           </configuration>\r
+            </plugin>\r
+        </plugins>\r
+    </build>\r
     <dependencies>\r
         <dependency>\r
             <groupId>org.opendaylight.controller</groupId>\r
             <groupId>junit</groupId>\r
             <artifactId>junit</artifactId>\r
         </dependency>\r
+           <dependency>\r
+                   <groupId>org.eclipse.xtend</groupId>\r
+                   <artifactId>org.eclipse.xtend.lib</artifactId>\r
+                   <version>2.4.2</version>\r
+           </dependency>\r
     </dependencies>\r
 </project>\r
diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderClassDescriptor.java b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderClassDescriptor.java
new file mode 100644 (file)
index 0000000..72b4c87
--- /dev/null
@@ -0,0 +1,331 @@
+package org.opendaylight.controller.sal.java.api.generator;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
+import org.opendaylight.controller.sal.binding.model.api.GeneratedType;
+import org.opendaylight.controller.sal.binding.model.api.MethodSignature;
+import org.opendaylight.controller.sal.binding.model.api.ParameterizedType;
+import org.opendaylight.controller.sal.binding.model.api.Type;
+import org.opendaylight.controller.yang.binding.Augmentable;
+
+public class BuilderClassDescriptor {
+
+    private static final String GET_PREFIX = "get";
+    private static final String JAVA_UTIL = "java.util";
+    private static final String HASH_MAP = "HashMap";
+    private static final String MAP = "Map";
+    private static final String GET_AUGMENTATION_METHOD_NAME = "getAugmentation";
+
+    private final GeneratedType genType;
+    private Map<String, String> imports;
+    private final String packageName;
+    private final String className;
+    private final Set<MethodDeclaration> methods;
+    private final Set<FieldDeclaration> fields;
+    private final List<String> importsNames;
+    private FieldDeclaration augmentField;
+
+    class TypeDeclaration {
+
+        private final static String JAVA_LANG_PREFIX = "java.lang";
+        private final String name;
+        private final TypeDeclaration[] generics;
+
+        public TypeDeclaration(String pkg, String name, TypeDeclaration... generics) {
+            this.name = removeJavaLangPkgName(getRightTypeName(pkg, name));
+            if (generics != null && generics.length > 0) {
+                this.generics = generics;
+            } else {
+                this.generics = null;
+            }
+        }
+
+        public TypeDeclaration(final Type type) {
+            if (type == null) {
+                throw new IllegalArgumentException("Type cannot be NULL");
+            }
+
+            this.name = removeJavaLangPkgName(getRightTypeName(type.getPackageName(), type.getName()));
+            TypeDeclaration[] generics = null;
+            if (type instanceof ParameterizedType) {
+                final ParameterizedType pType = (ParameterizedType) type;
+                final Type[] actualTypeArguments = pType.getActualTypeArguments();
+                generics = new TypeDeclaration[actualTypeArguments.length];
+                for (int i = 0; i < actualTypeArguments.length; i++) {
+                    generics[i] = new TypeDeclaration(actualTypeArguments[i].getPackageName(),
+                            actualTypeArguments[i].getName());
+                }
+            }
+            if (generics != null && generics.length > 0) {
+                this.generics = generics;
+            } else {
+                this.generics = null;
+            }
+        }
+
+        private String removeJavaLangPkgName(final String typeName) {
+            if (typeName.startsWith(JAVA_LANG_PREFIX)) {
+                return typeName.substring(typeName.lastIndexOf(Constants.DOT) + 1);
+            }
+            return typeName;
+        }
+
+        private String getRightTypeName(final String pkg, final String name) {
+            if (name == null) {
+                throw new IllegalArgumentException("Name cannot be NULL!");
+            }
+
+            if (imports == null) {
+                return name;
+            }
+            final String pkgFromImports = imports.get(name);
+            if (pkgFromImports == null || pkgFromImports.equals(pkg)) {
+                return name;
+            }
+            return (pkg == null ? "" : pkg) + Constants.DOT + name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public TypeDeclaration[] getGenerics() {
+            return generics;
+        }
+
+    }
+
+    class ParameterDeclaration {
+
+        private final TypeDeclaration type;
+        private final String name;
+
+        public ParameterDeclaration(TypeDeclaration type, String name) {
+            this.type = type;
+            this.name = name;
+        }
+
+        public TypeDeclaration getType() {
+            return type;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+    }
+
+    class MethodDeclaration {
+
+        private final TypeDeclaration returnType;
+        private final String name;
+        private final List<ParameterDeclaration> parameters;
+
+        public MethodDeclaration(final TypeDeclaration returnType, final String name,
+                final List<ParameterDeclaration> parameters) {
+            this.returnType = returnType;
+            this.name = name;
+            if (parameters != null && !parameters.isEmpty()) {
+                this.parameters = parameters;
+            } else {
+                this.parameters = null;
+            }
+        }
+
+        public TypeDeclaration getReturnType() {
+            return returnType;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public List<ParameterDeclaration> getParameters() {
+            return parameters;
+        }
+
+    }
+
+    class FieldDeclaration extends ParameterDeclaration {
+
+        public FieldDeclaration(final TypeDeclaration type, final String name) {
+            super(type, name);
+        }
+
+    }
+
+    public BuilderClassDescriptor(final GeneratedType genType) {
+        if (genType == null) {
+            throw new IllegalArgumentException("Generated type reference cannot be NULL!");
+        }
+        this.genType = genType;
+        this.imports = GeneratorUtil.createImports(genType);
+        addToImports(genType.getPackageName(), genType.getName());
+        packageName = genType.getPackageName();
+        className = genType.getName();
+        methods = createMethods();
+        fields = createFieldsFromMethods();
+        importsNames = createImportsNames();
+    }
+
+    private Set<MethodDeclaration> createMethods() {
+        final Set<MethodDeclaration> methods = new LinkedHashSet<>();
+        storeMethodsOfIfc(methods, genType);
+        storeMethodsOfImplementedIfcs(methods, genType.getImplements());
+        return methods;
+    }
+
+    private void storeMethodsOfIfc(final Set<MethodDeclaration> methodStorage, final GeneratedType ifc) {
+        for (MethodSignature methodSignature : ifc.getMethodDefinitions()) {
+            final List<ParameterDeclaration> parameterDeclarations = getParameterDeclarationsFrom(methodSignature
+                    .getParameters());
+            methodStorage.add(new MethodDeclaration(new TypeDeclaration(methodSignature.getReturnType()),
+                    methodSignature.getName(), parameterDeclarations));
+        }
+        if (ifc.getEnclosedTypes() != null && !ifc.getEnclosedTypes().isEmpty()) {
+            addToImports(ifc.getPackageName(), ifc.getName() + ".*");
+        }
+    }
+
+    private List<ParameterDeclaration> getParameterDeclarationsFrom(final List<MethodSignature.Parameter> parameters) {
+        final List<ParameterDeclaration> parameterDeclarations = new ArrayList<>();
+        for (MethodSignature.Parameter mp : parameters) {
+            parameterDeclarations.add(new ParameterDeclaration(new TypeDeclaration(mp.getType()), mp.getName()));
+        }
+        return parameterDeclarations;
+    }
+
+    private void storeMethodsOfImplementedIfcs(final Set<MethodDeclaration> methodStorage,
+            final List<Type> implementedIfcs) {
+        if (implementedIfcs == null || implementedIfcs.isEmpty()) {
+            return;
+        }
+        for (Type implementedIfc : implementedIfcs) {
+            if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) {
+                final GeneratedType ifc = ((GeneratedType) implementedIfc);
+                storeMethodsOfIfc(methodStorage, ifc);
+                storeMethodsOfImplementedIfcs(methodStorage, ifc.getImplements());
+            } else if (implementedIfc.getFullyQualifiedName().equals(Augmentable.class.getName())) {
+                for (Method m : Augmentable.class.getMethods()) {
+                    if (m.getName().equals(GET_AUGMENTATION_METHOD_NAME)) {
+                        addToImports(JAVA_UTIL, HASH_MAP);
+                        addToImports(JAVA_UTIL, MAP);
+                        java.lang.reflect.Type returnType = m.getReturnType();
+                        final String fullyQualifiedName = ((Class<?>) returnType).getName();
+                        addToImports(getPackageFrom(fullyQualifiedName), getNameFrom(fullyQualifiedName));
+                        TypeDeclaration augmentMethodType = new TypeDeclaration(getPackageFrom(fullyQualifiedName),
+                                getNameFrom(fullyQualifiedName), new TypeDeclaration(genType));
+                        augmentField = createFieldFromGetMethod(new MethodDeclaration(augmentMethodType, m.getName(),
+                                null));
+                    }
+                }
+            }
+        }
+    }
+
+    private void addToImports(final String pkg, final String name) {
+        if (imports == null) {
+            imports = new LinkedHashMap<>();
+        }
+        if (imports.get(name) == null) {
+            imports.put(name, pkg);
+        }
+    }
+
+    private String getPackageFrom(final String fullyQualifiedName) {
+        final int lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT);
+        return lastDotIndex == -1 ? "" : fullyQualifiedName.substring(0, lastDotIndex);
+    }
+
+    private String getNameFrom(final String fullyQualifiedName) {
+        final int lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT);
+        return lastDotIndex == -1 ? fullyQualifiedName : fullyQualifiedName.substring(lastDotIndex + 1);
+    }
+
+    private Set<FieldDeclaration> createFieldsFromMethods() {
+        final Set<FieldDeclaration> result = new LinkedHashSet<>();
+
+        if (methods == null || methods.isEmpty()) {
+            return result;
+        }
+
+        for (MethodDeclaration m : methods) {
+            final FieldDeclaration createdField = createFieldFromGetMethod(m);
+            if (createdField != null) {
+                result.add(createdField);
+            }
+        }
+        return result;
+    }
+
+    private FieldDeclaration createFieldFromGetMethod(final MethodDeclaration method) {
+        if (method == null || method.getName() == null || method.getName().isEmpty()) {
+            return null;
+        } else if (method.getName().startsWith(GET_PREFIX)) {
+            final String fieldNameFromMethod = method.getName().substring(GET_PREFIX.length());
+            final String fieldName = Character.toLowerCase(fieldNameFromMethod.charAt(0))
+                    + fieldNameFromMethod.substring(1);
+            return new FieldDeclaration(method.getReturnType(), fieldName);
+        }
+        return null;
+    }
+
+    private List<String> createImportsNames() {
+        final List<String> result = new ArrayList<>();
+
+        if (imports == null || imports.isEmpty()) {
+            return result;
+        }
+
+        for (Map.Entry<String, String> entry : imports.entrySet()) {
+            final String typeName = entry.getKey();
+            final String packageName = entry.getValue();
+            result.add(packageName + Constants.DOT + typeName);
+        }
+        return result;
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    /**
+     * @return list of imports or empty list
+     */
+    public List<String> getImportsNames() {
+        return importsNames;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    /**
+     * @return set of methods or empty set
+     */
+    public Set<FieldDeclaration> getFields() {
+        return fields;
+    }
+
+    /**
+     * @return set of methods or empty set
+     */
+    public Set<MethodDeclaration> getMethods() {
+        return methods;
+    }
+
+    /**
+     * @return declaration of augment field or NULL
+     */
+    public FieldDeclaration getAugmentField() {
+        return augmentField;
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderGenerator.java b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderGenerator.java
new file mode 100644 (file)
index 0000000..07ee733
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.controller.sal.java.api.generator;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import org.opendaylight.controller.sal.binding.model.api.CodeGenerator;
+import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
+import org.opendaylight.controller.sal.binding.model.api.GeneratedType;
+import org.opendaylight.controller.sal.binding.model.api.Type;
+
+public final class BuilderGenerator implements CodeGenerator {
+
+    public static final String FILE_NAME_SUFFIX = "Builder";
+
+    @Override
+    public Writer generate(Type type) throws IOException {
+        Writer writer = new StringWriter();
+        if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {
+            BuilderTemplate builerGeneratorXtend = new BuilderTemplate();
+            writer.write(builerGeneratorXtend.generate(new BuilderClassDescriptor((GeneratedType) type)).toString());
+        }
+        return writer;
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderTemplate.xtend b/opendaylight/sal/yang-prototype/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/controller/sal/java/api/generator/BuilderTemplate.xtend
new file mode 100644 (file)
index 0000000..484fbfb
--- /dev/null
@@ -0,0 +1,96 @@
+package org.opendaylight.controller.sal.java.api.generator
+
+import java.util.List
+import java.util.Set
+
+class BuilderTemplate {
+
+    val static BUILDER = 'Builder'
+    val static IMPL = 'Impl'
+
+    def generate(BuilderClassDescriptor cd) '''
+        package «cd.packageName»;
+        «IF !cd.importsNames.empty»
+            
+            «FOR in : cd.importsNames»
+                import «in»;
+            «ENDFOR»
+        «ENDIF»
+        
+        public class «cd.className»«BUILDER» {
+        
+            «fields(cd.fields, cd.augmentField)»
+
+            «IF !cd.fields.empty»
+                «FOR field : cd.fields SEPARATOR '\n'»
+                    public «cd.className»«BUILDER» set«field.name.toFirstUpper»(«field.type.name»«field.type.generics.print» «field.name») {
+                        this.«field.name» = «field.name»;
+                        return this;
+                    }
+                «ENDFOR»
+            «ENDIF»
+            «IF cd.augmentField != null»
+                
+                public «cd.className»«BUILDER» add«cd.augmentField.name.toFirstUpper»(Class<? extends «cd.augmentField.type.name»«cd.augmentField.type.generics.print»> augmentationType, «cd.augmentField.type.name»«cd.augmentField.type.generics.print» augmentation) {
+                    this.«cd.augmentField.name».put(augmentationType, augmentation);
+                    return this;
+                }
+            «ENDIF»
+
+            public «cd.className» build() {
+                return new «cd.className»«IMPL»();
+            }
+
+            private class «cd.className»«IMPL» implements «cd.className» {
+
+                «fields(cd.fields, cd.augmentField)»
+
+                private «cd.className»«IMPL»() {
+                    «IF !cd.fields.empty»
+                        «FOR field : cd.fields»
+                            this.«field.name» = «cd.className»«BUILDER».this.«field.name»;
+                        «ENDFOR»
+                    «ENDIF»
+                    «IF cd.augmentField != null»
+                        this.«cd.augmentField.name».putAll(«cd.className»«BUILDER».this.«cd.augmentField.name»);
+                    «ENDIF»
+                }
+
+                «IF !cd.fields.empty»
+                    «FOR field : cd.fields SEPARATOR '\n'»
+                        @Override
+                        public «field.type.name»«field.type.generics.print» get«field.name.toFirstUpper»() {
+                            return «field.name»;
+                        }
+                    «ENDFOR»
+                «ENDIF»
+                «IF cd.augmentField != null»
+
+                    @Override
+                    public <E extends «cd.augmentField.type.name»«cd.augmentField.type.generics.print»> E get«cd.augmentField.name.toFirstUpper»(Class<E> augmentationType) {
+                        if (augmentationType == null) {
+                            throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
+                        }
+                        return (E) «cd.augmentField.name».get(augmentationType);
+                    }
+                «ENDIF»
+
+            }
+
+        }
+    '''
+
+    def private fields(Set<BuilderClassDescriptor.FieldDeclaration> fields, BuilderClassDescriptor.FieldDeclaration augmentField) '''
+        «IF !fields.empty»
+            «FOR field : fields»
+                private «field.type.name»«field.type.generics.print» «field.name»;
+            «ENDFOR»
+        «ENDIF»
+        «IF augmentField != null»
+            private Map<Class<? extends «augmentField.type.name»«augmentField.type.generics.print»>, «augmentField.type.name»«augmentField.type.generics.print»> «augmentField.name» = new HashMap<>();
+        «ENDIF»
+    '''
+
+    def private print(List<BuilderClassDescriptor.TypeDeclaration> generics) '''«IF generics != null && !generics.empty»<«FOR generic : generics SEPARATOR ', '»«generic.name»«ENDFOR»>«ENDIF»'''
+
+}
index bcc1790..8f5c456 100644 (file)
@@ -24,6 +24,8 @@ final class Constants {
 
     public static final String GAP = " ";
     public static final String COMMA = ",";
+    public static final String DOT = ".";
+    public static final String ASTERISK = "*";
     public static final String NL = "\n";
     public static final String SC = ";";
     public static final String TAB = "    ";
index 55b8d77..1d2e60f 100644 (file)
@@ -23,6 +23,7 @@ public final class GeneratorJavaFile {
     private final CodeGenerator interfaceGenerator;
     private final ClassCodeGenerator classGenerator;
     private final EnumGenerator enumGenerator;
+    private final BuilderGenerator builderGenerator;
 
     private final Set<GeneratedType> genTypes;
     private final Set<GeneratedTransferObject> genTransferObjects;
@@ -35,6 +36,7 @@ public final class GeneratorJavaFile {
         this.enumerations = new HashSet<>();
         this.classGenerator = new ClassCodeGenerator();
         this.enumGenerator = new EnumGenerator();
+        this.builderGenerator = new BuilderGenerator();
     }
 
     public GeneratorJavaFile(final Set<GeneratedType> types, final Set<GeneratedTransferObject> genTransferObjects,
@@ -42,6 +44,7 @@ public final class GeneratorJavaFile {
         this.interfaceGenerator = new InterfaceGenerator();
         this.classGenerator = new ClassCodeGenerator();
         this.enumGenerator = new EnumGenerator();
+        this.builderGenerator = new BuilderGenerator();
 
         this.genTypes = types;
         this.genTransferObjects = genTransferObjects;
@@ -51,14 +54,19 @@ public final class GeneratorJavaFile {
     public List<File> generateToFile(final File parentDirectory) throws IOException {
         final List<File> result = new ArrayList<>();
         for (GeneratedType type : genTypes) {
-            final File genFile = generateTypeToJavaFile(parentDirectory, type, interfaceGenerator);
+            final File genFile = generateTypeToJavaFile(parentDirectory, type, interfaceGenerator, "");
+            final File genBuilderFile = generateTypeToJavaFile(parentDirectory, type, builderGenerator,
+                    BuilderGenerator.FILE_NAME_SUFFIX);
 
             if (genFile != null) {
                 result.add(genFile);
             }
+            if (genBuilderFile != null) {
+                result.add(genBuilderFile);
+            }
         }
         for (GeneratedTransferObject transferObject : genTransferObjects) {
-            final File genFile = generateTypeToJavaFile(parentDirectory, transferObject, classGenerator);
+            final File genFile = generateTypeToJavaFile(parentDirectory, transferObject, classGenerator, "");
 
             if (genFile != null) {
                 result.add(genFile);
@@ -66,7 +74,7 @@ public final class GeneratorJavaFile {
         }
 
         for (Enumeration enumeration : enumerations) {
-            final File genFile = generateTypeToJavaFile(parentDirectory, enumeration, enumGenerator);
+            final File genFile = generateTypeToJavaFile(parentDirectory, enumeration, enumGenerator, "");
 
             if (genFile != null) {
                 result.add(genFile);
@@ -76,7 +84,7 @@ public final class GeneratorJavaFile {
         return result;
     }
 
-    private File generateTypeToJavaFile(final File parentDir, final Type type, final CodeGenerator generator)
+    private File generateTypeToJavaFile(final File parentDir, final Type type, final CodeGenerator generator, String fileNameSuffix)
             throws IOException {
         if (parentDir == null) {
             log.warn("Parent Directory not specified, files will be generated "
@@ -95,7 +103,7 @@ public final class GeneratorJavaFile {
         if (!packageDir.exists()) {
             packageDir.mkdirs();
         }
-        final File file = new File(packageDir, type.getName() + ".java");
+        final File file = new File(packageDir, type.getName() + fileNameSuffix + ".java");
         try (final FileWriter fw = new FileWriter(file)) {
             file.createNewFile();
 
index db42d32..6a38050 100644 (file)
@@ -90,10 +90,13 @@ public class GeneratorJavaFileTest {
                 + "controller" + FS + "gen").list();
         List<String> filesList = Arrays.asList(files);
 
-        assertEquals(3, files.length);
+        assertEquals(6, files.length);
         assertTrue(filesList.contains("Type1.java"));
         assertTrue(filesList.contains("Type2.java"));
         assertTrue(filesList.contains("Type3.java"));
+        assertTrue(filesList.contains("Type1Builder.java"));
+        assertTrue(filesList.contains("Type2Builder.java"));
+        assertTrue(filesList.contains("Type3Builder.java"));
     }
 
     @Ignore