You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/02/01 13:23:54 UTC

[06/10] cayenne git commit: CAY-2215 split cayenne-tools into cayenne-cgen and cayenne-ant

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/datamap-singleclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/datamap-singleclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/datamap-singleclass.vm
new file mode 100644
index 0000000..9ad544c
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/datamap-singleclass.vm
@@ -0,0 +1,96 @@
+##   Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##Terminology:
+##	Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+##  Super class - superclass of entity, ie,  org.apache.cayenne.art.auto._Artist
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+##  Classes available in template
+##    object (duplicated as 'objEntity') - the ObjEntity class: See org.apache.cayenne.map.ObjectEntity
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    dataMapUtils - class for query "helper" functions: See org.apache.cayenne.gen.DataMapUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##    superClassName
+##    superPackageName
+##    subClassName
+##    subPackageName
+##    baseClassName
+##    basePackageName 
+##
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${subPackageName}.${subClassName}")}##
+${importUtils.addType("${basePackageName}.${baseClassName}")}##
+${importUtils.addType('java.util.List')}
+${importUtils.addType('java.util.Map')}
+${importUtils.addType('java.util.HashMap')}
+${importUtils.addType('org.apache.cayenne.ObjectContext')}
+#foreach( $selectQuery in ${object.SelectQueries})
+${importUtils.addType(${selectQuery.Root.ClassName})}
+#foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+${importUtils.addType(${dataMapUtils.getParameterType(${selectQuery}, ${parameter})})}
+#end
+#end
+${importUtils.generate()}
+
+/**
+ * This class was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public class ${subClassName} {
+#if( ${object.hasQueryNames()})
+#foreach( $qname in ${object.QueryNames})
+
+public static final String ${stringUtils.capitalizedAsConstant($qname)}_QUERYNAME = "$qname";
+#end
+#end
+
+    private static ${subClassName} instance;
+
+    private ${subClassName}() {}
+
+    public ${subClassName} getInstance() {
+      if( instance == null) {
+        instance = new ${subClassName}();
+      }
+      return instance;
+    }
+
+#foreach( $selectQuery in ${object.SelectQueries})
+    public List<${stringUtils.stripPackageName($selectQuery.Root.ClassName)}> perform${dataMapUtils.getQueryMethodName(${selectQuery})}(ObjectContext context #foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})}), ${stringUtils.stripPackageName(${dataMapUtils.getParameterType(${selectQuery}, ${parameter})})} ${parameter} #end) {
+    #if(${dataMapUtils.hasParameters($selectQuery)})
+      String[] parameters = new String[] {
+      #foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+      "${parameter}",
+      #end
+      };
+
+      Object[] values = new Object[] {
+      #foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+      ${parameter},
+      #end
+      };
+    #end
+
+      NamedQuery query = new NamedQuery("${selectQuery.Name}"#if(${dataMapUtils.hasParameters($selectQuery)}), parameters, values#end);
+      return context.performQuery(query);
+    }
+#end
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/datamap-subclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/datamap-subclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/datamap-subclass.vm
new file mode 100644
index 0000000..f5e0474
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/datamap-subclass.vm
@@ -0,0 +1,47 @@
+##   Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##Terminology:
+##	Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+##  Super class - superclass of entity, ie,  org.apache.cayenne.art.auto._Artist
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+##  Classes available in template
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    dataMapUtils - class for query "helper" functions: See org.apache.cayenne.gen.dataMapUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${subPackageName}.${subClassName}")}##
+${importUtils.addType("${superPackageName}.${superClassName}")}##
+${importUtils.generate()}
+
+public class ${subClassName} extends ${superClassName} {
+
+    private static ${subClassName} instance;
+
+    private ${subClassName}() {}
+
+    public static ${subClassName} getInstance() {
+        if(instance == null) {
+            instance = new ${subClassName}();
+        }
+
+        return instance;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/datamap-superclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/datamap-superclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/datamap-superclass.vm
new file mode 100644
index 0000000..51c00f3
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/datamap-superclass.vm
@@ -0,0 +1,87 @@
+##   Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##Terminology:
+##	Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+##  Super class - superclass of entity, ie,  org.apache.cayenne.art.auto._Artist
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+##  Classes available in template
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    dataMapUtils - class for query "helper" functions: See org.apache.cayenne.gen.DataMapUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##    superClassName
+##    superPackageName
+##    subClassName
+##    subPackageName
+##    baseClassName
+##    basePackageName
+##
+${importUtils.setPackage($superPackageName)}##
+#if(${superPackageName})${importUtils.addReservedType("${superPackageName}.${superClassName}")}#end##
+#if(${basePackageName})${importUtils.addType("${basePackageName}.${baseClassName}")}#end##
+#if( ${object.hasSelectQueries()} )
+${importUtils.addType('java.util.List')}##
+${importUtils.addType('org.apache.cayenne.ObjectContext')}##
+${importUtils.addType('org.apache.cayenne.query.NamedQuery')}##
+#foreach( $selectQuery in ${object.SelectQueries})
+${importUtils.addType(${selectQuery.Root.ClassName})}##
+#if(${dataMapUtils.isValidParameterNames($selectQuery)})
+#foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+${importUtils.addType(${dataMapUtils.getParameterType(${selectQuery}, ${parameter})})}##
+#end
+#end    
+#end
+#end
+${importUtils.generate()}
+
+/**
+ * This class was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public class ${superClassName} {
+#if( ${object.hasQueryNames()})
+#foreach( $qname in ${object.queryNames})
+
+    public static final String ${stringUtils.capitalizedAsConstant($qname)}_QUERYNAME = "$qname";
+#end
+#end
+#foreach( $selectQuery in ${object.SelectQueries})
+
+#if(${dataMapUtils.isValidParameterNames($selectQuery)})
+    public List<${stringUtils.stripPackageName($selectQuery.Root.ClassName)}> perform${dataMapUtils.getQueryMethodName(${selectQuery})}(ObjectContext context #foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})}), ${stringUtils.stripPackageName(${dataMapUtils.getParameterType(${selectQuery}, ${parameter})})} ${parameter}#end) {
+#if(${dataMapUtils.hasParameters($selectQuery)})
+        String[] parameters = {
+#foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+            "${parameter}",
+#end
+        };
+
+        Object[] values = {
+#foreach( $parameter in ${dataMapUtils.getParameterNames(${selectQuery})})
+            ${parameter},
+#end
+        };
+
+#end
+        return context.performQuery(new NamedQuery("${selectQuery.Name}"#if(${dataMapUtils.hasParameters($selectQuery)}), parameters, values#end));
+    }
+#end
+#end
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-singleclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-singleclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-singleclass.vm
new file mode 100644
index 0000000..a30dcec
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-singleclass.vm
@@ -0,0 +1,106 @@
+##  Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##  Terminology:
+## 
+##	Base class - super superclass of embeddable, usually java.lang.Object
+##  Super class - superclass of embeddable, ie,  org.apache.cayenne.art.auto._Embeddable
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Embeddable
+##
+##  Keys of objects available in template are defined in 'org.apache.cayenne.gen.Artifact', namely:
+## 
+##    object - the Embeddable class: See org.apache.cayenne.map.Embeddable
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##    superClassName
+##    superPackageName
+##    subClassName
+##    subPackageName
+##    baseClassName
+##    basePackageName 
+##
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${subPackageName}.${subClassName}")}##
+${importUtils.addType("${basePackageName}.${baseClassName}")}##
+${importUtils.addType("org.apache.cayenne.Persistent")}##
+#if(${object.Attributes} && !${object.Attributes.isEmpty()})
+${importUtils.addType('org.apache.cayenne.exp.Property')}##
+#end
+#foreach( $attr in ${object.Attributes} )
+$importUtils.addType(${attr.Type})##
+#end
+${importUtils.generate()}
+
+public abstract class ${subClassName} extends ${baseClassName} {
+
+## Create property names
+#if( $createPropertyNames )
+#foreach( $attr in ${object.Attributes} )
+    public static final String ${stringUtils.capitalizedAsConstant($attr.Name)}_PROPERTY = "${attr.Name}";
+#end
+
+#end
+## Create Properties
+#foreach( $attr in ${object.Attributes} )
+    #set ( $type = "$importUtils.formatJavaType(${attr.Type}, false)" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($attr.Name)} = Property.create("${attr.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+
+    // special properties injected by Cayenne
+    private Persistent owner;
+    private String embeddedProperty;
+    
+    // declared properties
+#foreach( $attr in ${object.Attributes} )
+    protected $importUtils.formatJavaType(${attr.Type}) $stringUtils.formatVariableName(${attr.Name});
+#end
+
+    // lifecycle methods
+    protected void propertyWillChange(String property, Object oldValue, Object newValue) {
+        if (owner != null && owner.getObjectContext() != null) {
+            owner.getObjectContext().propertyChanged(
+                    owner,
+                    embeddedProperty + "." + property,
+                    oldValue,
+                    newValue);
+        }
+    }
+
+    // declared getters and setters
+## Create attribute set/get methods
+#foreach( $attr in ${object.Attributes} )
+    public void set${stringUtils.capitalized($attr.Name)}($importUtils.formatJavaType(${attr.Type}) $stringUtils.formatVariableName(${attr.Name})) {
+        propertyWillChange("${attr.Name}", this.$stringUtils.formatVariableName(${attr.Name}), $stringUtils.formatVariableName(${attr.Name}));
+        this.$stringUtils.formatVariableName(${attr.Name}) = $stringUtils.formatVariableName(${attr.Name});
+    }
+#if ( $importUtils.isBoolean(${attr.Type}) )
+	public boolean is${stringUtils.capitalized($attr.Name)}() {
+        return $stringUtils.formatVariableName(${attr.Name});
+    }
+#elseif ( $importUtils.isNonBooleanPrimitive(${attr.Type}) )
+    public $classGen.formatJavaType(${attr.Type}) get${stringUtils.capitalized($attr.Name)}() {
+        return $stringUtils.formatVariableName(${attr.Name});
+    }
+#else
+    public $importUtils.formatJavaType(${attr.Type}) get${stringUtils.capitalized($attr.Name)}() {
+        return $stringUtils.formatVariableName(${attr.Name});
+    }
+#end
+
+#end
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-subclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-subclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-subclass.vm
new file mode 100644
index 0000000..b5b701b
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-subclass.vm
@@ -0,0 +1,45 @@
+##  Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##  Terminology:
+## 
+##	Base class - super superclass of embeddable, usually java.lang.Object
+##  Super class - superclass of embeddable, ie,  org.apache.cayenne.art.auto._Embeddable
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Embeddable
+##
+##  Keys of objects available in template are defined in 'org.apache.cayenne.gen.Artifact', namely:
+## 
+##    object - the Embeddable class: See org.apache.cayenne.map.Embeddable
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##    superClassName
+##    superPackageName
+##    subClassName
+##    subPackageName
+##    baseClassName
+##    basePackageName 
+##
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${subPackageName}.${subClassName}")}##
+${importUtils.addType("${superPackageName}.${superClassName}")}##
+${importUtils.generate()}
+
+
+public#if("true" == "${object.getIsAbstract()}") abstract#end class ${subClassName} extends ${superClassName} {
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-superclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-superclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-superclass.vm
new file mode 100644
index 0000000..95e39dc
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/embeddable-superclass.vm
@@ -0,0 +1,112 @@
+##  Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##  Terminology:
+## 
+##	Base class - super superclass of embeddable, usually java.lang.Object
+##  Super class - superclass of embeddable, ie,  org.apache.cayenne.art.auto._Embeddable
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Embeddable
+##
+##  Keys of objects available in template are defined in 'org.apache.cayenne.gen.Artifact', namely:
+## 
+##    object - the Embeddable class: See org.apache.cayenne.map.Embeddable
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##    superClassName
+##    superPackageName
+##    subClassName
+##    subPackageName
+##    baseClassName
+##    basePackageName 
+##
+##
+${importUtils.setPackage($superPackageName)}##
+${importUtils.addReservedType("${superPackageName}.${superClassName}")}##
+${importUtils.addType("${basePackageName}.${baseClassName}")}##
+${importUtils.addType("org.apache.cayenne.Persistent")}##
+#if(${object.Attributes} && !${object.Attributes.isEmpty()})
+${importUtils.addType('org.apache.cayenne.exp.Property')}##
+#end
+#foreach( $attr in ${object.Attributes} )
+$importUtils.addType(${attr.Type})##
+#end
+${importUtils.generate()}
+
+/** 
+ * Embeddable class ${superClassName} was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually, 
+ * since it may be overwritten next time code is regenerated. 
+ * If you need to make any customizations, please use subclass. 
+ */
+public abstract class ${superClassName} extends ${baseClassName} {
+
+## Create property names
+#if( $createPropertyNames )
+#foreach( $attr in ${object.Attributes} )
+    public static final String ${stringUtils.capitalizedAsConstant($attr.Name)}_PROPERTY = "${attr.Name}";
+#end
+
+#end
+## Create Properties
+#foreach( $attr in ${object.Attributes} )
+    #set ( $type = "$importUtils.formatJavaType(${attr.Type}, false)" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($attr.Name)} = Property.create("${attr.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+
+    // special properties injected by Cayenne
+    private Persistent owner;
+    private String embeddedProperty;
+    
+    // declared properties
+#foreach( $attr in ${object.Attributes} )
+    protected $importUtils.formatJavaType(${attr.Type}) $stringUtils.formatVariableName(${attr.Name});
+#end
+
+    // lifecycle methods
+    protected void propertyWillChange(String property, Object oldValue, Object newValue) {
+        if (owner != null && owner.getObjectContext() != null) {
+            owner.getObjectContext().propertyChanged(
+                    owner,
+                    embeddedProperty + "." + property,
+                    oldValue,
+                    newValue);
+        }
+    }
+
+    // declared getters and setters
+## Create attribute set/get methods
+#foreach( $attr in ${object.Attributes} )
+    public void set${stringUtils.capitalized($attr.Name)}($importUtils.formatJavaType(${attr.Type}) $stringUtils.formatVariableName(${attr.Name})) {
+        propertyWillChange("${attr.Name}", this.$stringUtils.formatVariableName(${attr.Name}), $stringUtils.formatVariableName(${attr.Name}));
+        this.$stringUtils.formatVariableName(${attr.Name}) = $stringUtils.formatVariableName(${attr.Name});
+    }
+#if ( $importUtils.isBoolean(${attr.Type}) )
+	public boolean is${stringUtils.capitalized($attr.Name)}() {
+        return $stringUtils.formatVariableName(${attr.Name});
+    }
+#elseif ( $importUtils.isNonBooleanPrimitive(${attr.Type}) )
+    public $importUtils.formatJavaType(${attr.Type}) get${stringUtils.capitalized($attr.Name)}() {
+        return $stringUtils.formatVariableName(${attr.Name});
+    }
+#else
+    public $importUtils.formatJavaType(${attr.Type}) get${stringUtils.capitalized($attr.Name)}() {
+        return $stringUtils.formatVariableName(${attr.Name});
+    }
+#end
+
+#end
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/singleclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/singleclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/singleclass.vm
new file mode 100644
index 0000000..53c6aa7
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/singleclass.vm
@@ -0,0 +1,147 @@
+##   Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##Terminology:
+##	Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+##  Super class - superclass of entity, ie,  org.apache.cayenne.art.auto._Artist
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+##  Classes available in template
+##    object (duplicated as 'objEntity') - the ObjEntity class: See org.apache.cayenne.map.ObjectEntity
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    entityUtils - class for entity "helper" functions: See org.apache.cayenne.gen.EntityUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##    superClassName
+##    superPackageName
+##    subClassName
+##    subPackageName
+##    baseClassName
+##    basePackageName 
+##
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${subPackageName}.${subClassName}")}##
+${importUtils.addType("${basePackageName}.${baseClassName}")}##
+#if((${object.DeclaredAttributes} && !${object.DeclaredAttributes.isEmpty()}) || (${object.DeclaredRelationships} && !${object.DeclaredRelationships.isEmpty()}))
+${importUtils.addType('org.apache.cayenne.exp.Property')}##
+#end
+#foreach( $attr in ${object.DeclaredAttributes} )
+$importUtils.addType(${attr.Type})##
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+$importUtils.addType(${rel.TargetEntity.ClassName})##
+#if(${rel.CollectionType})
+$importUtils.addType(${rel.CollectionType})##
+#end
+#end
+${importUtils.generate()}
+
+public#if("true" == "${object.isAbstract()}") abstract#end class ${subClassName} extends ${baseClassName} {
+
+    private static final long serialVersionUID = 1L;
+
+## Create property names
+#if( $createPropertyNames )
+#foreach( $attr in ${object.DeclaredAttributes} )
+    public static final String ${stringUtils.capitalizedAsConstant($attr.Name)}_PROPERTY = "${attr.Name}";
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+    public static final String ${stringUtils.capitalizedAsConstant($rel.Name)}_PROPERTY = "${rel.Name}";
+#end
+
+#end
+#if( $object.DbEntity )
+#foreach( $idAttr in ${object.DbEntity.PrimaryKeys} )
+    public static final String ${stringUtils.capitalizedAsConstant($idAttr.Name)}_PK_COLUMN = "${idAttr.Name}";
+#end
+#end
+
+## Create Properties
+#foreach( $attr in ${object.DeclaredAttributes} )
+    #set ( $type = "$importUtils.formatJavaType(${attr.Type}, false)" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($attr.Name)} = Property.create("${attr.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ${rel.CollectionType} == "java.util.Map")
+    #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClassName)>" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#else
+    #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClassName)>" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#else
+    #set( $type = "$importUtils.formatJavaType(${rel.TargetEntity.ClassName})" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#end
+
+## Create attribute set/get methods
+#foreach( $attr in ${object.DeclaredAttributes} )
+#if ("true" != "${object.isReadOnly()}")
+    public void set${stringUtils.capitalized($attr.Name)}($importUtils.formatJavaType(${attr.Type}) $stringUtils.formatVariableName(${attr.Name})) {
+        writeProperty("${attr.Name}", $stringUtils.formatVariableName(${attr.Name}));
+    }
+#end
+#if ( $importUtils.isBoolean(${attr.Type}) )
+	public boolean is${stringUtils.capitalized($attr.Name)}() {
+        Boolean value = (Boolean)readProperty("${attr.Name}");
+        return (value != null) ? value.booleanValue() : false;
+    }
+#elseif ( $importUtils.isNonBooleanPrimitive(${attr.Type}) )
+    public ${importUtils.formatJavaType($attr.Type)} get${stringUtils.capitalized($attr.Name)}() {
+        Object value = readProperty("${attr.Name}");
+        return (value != null) ? ($importUtils.formatJavaTypeAsNonBooleanPrimitive(${attr.Type})) value : 0;
+    }
+#else
+    public $importUtils.formatJavaType(${attr.Type}) get${stringUtils.capitalized($attr.Name)}() {
+        return ($importUtils.formatJavaType(${attr.Type}))readProperty("${attr.Name}");
+    }
+#end
+
+#end
+##
+## Create list add/remove/get methods
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ! $rel.ReadOnly )    public void addTo${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) obj) {
+        addToManyTarget("${rel.name}", obj, true);
+    }
+    public void removeFrom${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) obj) {
+        removeToManyTarget("${rel.name}", obj, true);
+    }
+#end
+    public $importUtils.formatJavaType($rel.CollectionType) get${stringUtils.capitalized($rel.Name)}() {
+        return ($importUtils.formatJavaType($rel.CollectionType))readProperty("${rel.name}");
+    }
+#else
+#if ( ! ${object.isReadOnly()} && ! $rel.ReadOnly )
+    public void set${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) $stringUtils.formatVariableName(${rel.name})) {
+        setToOneTarget("${rel.name}", $stringUtils.formatVariableName(${rel.name}), true);
+    }
+#end
+    public $importUtils.formatJavaType(${rel.TargetEntity.ClassName}) get${stringUtils.capitalized($rel.Name)}() {
+        return ($importUtils.formatJavaType(${rel.TargetEntity.ClassName}))readProperty("${rel.name}");
+    }
+#end
+
+
+#end
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/subclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/subclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/subclass.vm
new file mode 100644
index 0000000..e31e658
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/subclass.vm
@@ -0,0 +1,47 @@
+##   Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##Terminology:
+##	Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+##  Super class - superclass of entity, ie,  org.apache.cayenne.art.auto._Artist
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+##  Classes available in template
+##    objEntity - the ObjEntity class: See org.apache.cayenne.map.ObjectEntity
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    entityUtils - class for entity "helper" functions: See org.apache.cayenne.gen.EntityUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##
+##
+${importUtils.setPackage($subPackageName)}##
+${importUtils.addReservedType("${subPackageName}.${subClassName}")}##
+${importUtils.addType("${superPackageName}.${superClassName}")}##
+${importUtils.generate()}
+
+public#if("true" == "${object.isAbstract()}") abstract#end class ${subClassName} extends ${superClassName} {
+
+    private static final long serialVersionUID = 1L; 
+
+##callbacks
+#foreach($cbname in ${entityUtils.callbackNames})
+    @Override
+    protected void ${cbname}() {
+        //TODO: implement ${cbname}
+    }
+
+#end 
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/resources/templates/v1_2/superclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v1_2/superclass.vm b/cayenne-cgen/src/main/resources/templates/v1_2/superclass.vm
new file mode 100644
index 0000000..7857189
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v1_2/superclass.vm
@@ -0,0 +1,164 @@
+##   Licensed to the Apache Software Foundation (ASF) under one
+##  or more contributor license agreements.  See the NOTICE file
+##  distributed with this work for additional information
+##  regarding copyright ownership.  The ASF licenses this file
+##  to you under the Apache License, Version 2.0 (the
+##  "License"); you may not use this file except in compliance
+##  with the License.  You may obtain a copy of the License at
+##
+##    http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing,
+##  software distributed under the License is distributed on an
+##  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+##  KIND, either express or implied.  See the License for the
+##  specific language governing permissions and limitations
+##  under the License.
+##
+##Terminology:
+##	Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+##  Super class - superclass of entity, ie,  org.apache.cayenne.art.auto._Artist
+##	Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+##  Classes available in template
+##    object (duplicated as 'objEntity') - the ObjEntity class: See org.apache.cayenne.map.ObjectEntity
+##    stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+##    entityUtils - class for entity "helper" functions: See org.apache.cayenne.gen.EntityUtils
+##    importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+##    superClassName
+##    superPackageName
+##    subClassName
+##    subPackageName
+##    baseClassName
+##    basePackageName
+##
+${importUtils.setPackage($superPackageName)}##
+${importUtils.addReservedType("${superPackageName}.${superClassName}")}##
+${importUtils.addType("${basePackageName}.${baseClassName}")}##
+#if((${object.DeclaredAttributes} && !${object.DeclaredAttributes.isEmpty()}) || (${object.DeclaredRelationships} && !${object.DeclaredRelationships.isEmpty()}))
+${importUtils.addType('org.apache.cayenne.exp.Property')}##
+#end
+#foreach( $attr in ${object.DeclaredAttributes} )
+$importUtils.addType(${attr.Type})##
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+$importUtils.addType(${rel.TargetEntity.ClassName})##
+#if(${rel.CollectionType}) 
+$importUtils.addType(${rel.CollectionType})##
+#end
+#end
+${importUtils.generate()}
+
+/**
+ * Class ${superClassName} was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class ${superClassName} extends ${baseClassName} {
+
+    private static final long serialVersionUID = 1L; 
+
+## Create property names
+#if( $createPropertyNames )
+#foreach( $attr in ${object.DeclaredAttributes} )
+    public static final String ${stringUtils.capitalizedAsConstant($attr.Name)}_PROPERTY = "${attr.Name}";
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+    public static final String ${stringUtils.capitalizedAsConstant($rel.Name)}_PROPERTY = "${rel.Name}";
+#end
+
+#end
+#if( $object.DbEntity )
+#foreach( $idAttr in ${object.DbEntity.PrimaryKeys} )
+    public static final String ${stringUtils.capitalizedAsConstant($idAttr.Name)}_PK_COLUMN = "${idAttr.Name}";
+#end
+#end
+
+## Create Properties
+#foreach( $attr in ${object.DeclaredAttributes} )
+    #set ( $type = "$importUtils.formatJavaType(${attr.Type}, false)")
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($attr.Name)} = Property.create("${attr.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ${rel.CollectionType} == "java.util.Map")
+    #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClassName)>" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#else
+    #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClassName)>" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#else
+    #set( $type = "$importUtils.formatJavaType(${rel.TargetEntity.ClassName})" )
+    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#end
+
+## Create attribute set/get methods
+#foreach( $attr in ${object.DeclaredAttributes} )
+#if ("true" != "${object.isReadOnly()}")
+    public void set${stringUtils.capitalized($attr.Name)}($importUtils.formatJavaType(${attr.Type}) $stringUtils.formatVariableName(${attr.Name})) {
+        writeProperty("${attr.Name}", $stringUtils.formatVariableName(${attr.Name}));
+    }
+#end
+#if ( $importUtils.isBoolean(${attr.Type}) )
+	public boolean is${stringUtils.capitalized($attr.Name)}() {
+        Boolean value = (Boolean)readProperty("${attr.Name}");
+        return (value != null) ? value.booleanValue() : false;
+    }
+#elseif ( $importUtils.isNonBooleanPrimitive(${attr.Type}) )
+    public ${importUtils.formatJavaType($attr.Type)} get${stringUtils.capitalized($attr.Name)}() {
+        Object value = readProperty("${attr.Name}");
+        return (value != null) ? ($importUtils.formatJavaTypeAsNonBooleanPrimitive(${attr.Type})) value : 0;
+    }
+#else
+    public $importUtils.formatJavaType(${attr.Type}) get${stringUtils.capitalized($attr.Name)}() {
+        return ($importUtils.formatJavaType(${attr.Type}))readProperty("${attr.Name}");
+    }
+#end
+
+#end
+##
+## Create list add/remove/get methods
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ! $rel.ReadOnly )
+    public void addTo${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) obj) {
+        addToManyTarget("${rel.Name}", obj, true);
+    }
+    public void removeFrom${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) obj) {
+        removeToManyTarget("${rel.Name}", obj, true);
+    }
+#end
+    @SuppressWarnings("unchecked")
+#if ( ${rel.CollectionType} == "java.util.Map")
+    public $importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClassName)> get${stringUtils.capitalized($rel.Name)}() {
+        return ($importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClassName)>)readProperty("${rel.Name}");
+    }
+#else
+    public $importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClassName)> get${stringUtils.capitalized($rel.Name)}() {
+        return ($importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClassName)>)readProperty("${rel.Name}");
+    }
+#end
+#else
+#if ( !${object.isReadOnly()} && !$rel.ReadOnly )
+    public void set${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) $stringUtils.formatVariableName(${rel.name})) {
+        setToOneTarget("${rel.Name}", $stringUtils.formatVariableName(${rel.name}), true);
+    }
+#end
+
+    public $importUtils.formatJavaType(${rel.TargetEntity.ClassName}) get${stringUtils.capitalized($rel.Name)}() {
+        return ($importUtils.formatJavaType(${rel.TargetEntity.ClassName}))readProperty("${rel.Name}");
+    }
+#end
+
+
+#end
+##
+##callback methods
+#foreach($cbname in ${entityUtils.callbackNames})
+    protected abstract void ${cbname}();
+
+#end
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
new file mode 100644
index 0000000..c6e1885
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
@@ -0,0 +1,256 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.apache.cayenne.map.CallbackDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.map.QueryDescriptor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class ClassGenerationActionTest {
+
+	protected ClassGenerationAction action;
+	protected Collection<StringWriter> writers;
+
+	@Before
+	public void setUp() throws Exception {
+		this.writers = new ArrayList<StringWriter>(3);
+		this.action = new ClassGenerationAction() {
+
+			@Override
+			protected Writer openWriter(TemplateType templateType) throws Exception {
+				StringWriter writer = new StringWriter();
+				writers.add(writer);
+				return writer;
+			}
+		};
+	}
+
+	@After
+	public void tearDown() throws Exception {
+		action = null;
+		writers = null;
+	}
+
+	@Test
+	public void testExecuteArtifactPairsImports() throws Exception {
+
+		ObjEntity testEntity1 = new ObjEntity("TE1");
+		testEntity1.setClassName("org.example.TestClass1");
+
+		action.setMakePairs(true);
+		action.setSuperPkg("org.example.auto");
+
+		List<String> generated = execute(new EntityArtifact(testEntity1));
+		assertNotNull(generated);
+		assertEquals(2, generated.size());
+
+		String superclass = generated.get(0);
+		assertTrue(superclass, superclass.contains("package org.example.auto;"));
+		assertTrue(superclass, superclass.contains("import org.apache.cayenne.CayenneDataObject;"));
+
+		String subclass = generated.get(1);
+		assertTrue(subclass, subclass.contains("package org.example;"));
+		assertTrue(subclass, subclass.contains("import org.example.auto._TestClass1;"));
+	}
+
+	@Test
+	public void testExecuteArtifactPairsMapRelationships() throws Exception {
+
+		ObjEntity testEntity1 = new ObjEntity("TE1");
+		testEntity1.setClassName("org.example.TestClass1");
+
+		final ObjEntity testEntity2 = new ObjEntity("TE1");
+		testEntity2.setClassName("org.example.TestClass2");
+
+		ObjRelationship relationship = new ObjRelationship("xMap") {
+
+			private static final long serialVersionUID = 8042147877503405974L;
+
+			@Override
+			public boolean isToMany() {
+				return true;
+			}
+
+			@Override
+			public ObjEntity getTargetEntity() {
+				return testEntity2;
+			}
+		};
+		relationship.setCollectionType("java.util.Map");
+		testEntity1.addRelationship(relationship);
+
+		action.setMakePairs(true);
+
+		List<String> generated = execute(new EntityArtifact(testEntity1));
+		assertNotNull(generated);
+		assertEquals(2, generated.size());
+
+		String superclass = generated.get(0);
+		assertTrue(superclass, superclass.contains("import java.util.Map;"));
+	}
+
+	@Test
+	public void testExecuteArtifactPairsAttribute() throws Exception {
+
+		ObjEntity testEntity1 = new ObjEntity("TE1");
+		testEntity1.setClassName("org.example.TestClass1");
+
+		ObjAttribute attr = new ObjAttribute();
+		attr.setName("ID");
+		attr.setType("int");
+
+		ObjAttribute attr1 = new ObjAttribute();
+		attr1.setName("name");
+		attr1.setType("char");
+
+		testEntity1.addAttribute(attr);
+		testEntity1.addAttribute(attr1);
+
+		action.setMakePairs(true);
+
+		List<String> generated = execute(new EntityArtifact(testEntity1));
+		assertNotNull(generated);
+		assertEquals(2, generated.size());
+		String superclass = generated.get(0);
+
+		assertTrue(superclass, superclass.contains("public void setID(int ID)"));
+		assertTrue(superclass, superclass.contains("writeProperty(\"ID\", ID);"));
+
+		assertTrue(superclass, superclass.contains("public int getID()"));
+		assertTrue(superclass, superclass.contains("Object value = readProperty(\"ID\");"));
+		assertTrue(superclass, superclass.contains("return (value != null) ? (Integer) value : 0;"));
+
+		assertTrue(superclass, superclass.contains("public void setName(char name)"));
+		assertTrue(superclass, superclass.contains("writeProperty(\"name\", name);"));
+
+		assertTrue(superclass, superclass.contains("public char getName()"));
+		assertTrue(superclass, superclass.contains("Object value = readProperty(\"name\");"));
+		assertTrue(superclass, superclass.contains("return (value != null) ? (Character) value : 0;"));
+
+	}
+
+	@Test
+	public void testExecuteDataMapQueryNames() throws Exception {
+		runDataMapTest(false);
+	}
+
+	@Test
+	public void testExecuteClientDataMapQueryNames() throws Exception {
+		runDataMapTest(true);
+	}
+
+	private void runDataMapTest(boolean client) throws Exception {
+		QueryDescriptor descriptor = QueryDescriptor.selectQueryDescriptor();
+        descriptor.setName("TestQuery");
+
+		DataMap map = new DataMap();
+		map.addQueryDescriptor(descriptor);
+		map.setName("testmap");
+		List<String> generated;
+		if (client) {
+			map.setDefaultClientPackage("testpackage");
+			generated = execute(new ClientDataMapArtifact(map, map.getQueryDescriptors()));
+		} else {
+			map.setDefaultPackage("testpackage");
+			generated = execute(new DataMapArtifact(map, map.getQueryDescriptors()));
+		}
+		assertEquals(2, generated.size());
+		assertTrue(generated.get(0).contains("public static final String TEST_QUERY_QUERYNAME = \"TestQuery\""));
+	}
+
+	@Test
+	public void testCallbackMethodGeneration() throws Exception {
+		assertCallbacks(false);
+	}
+
+	@Test
+	public void testClientCallbackMethodGeneration() throws Exception {
+		assertCallbacks(true);
+	}
+
+	private void assertCallbacks(boolean isClient) throws Exception {
+		ObjEntity testEntity1 = new ObjEntity("TE1");
+		testEntity1.setClassName("org.example.TestClass1");
+		int i = 0;
+		for (CallbackDescriptor cb : testEntity1.getCallbackMap().getCallbacks()) {
+			cb.addCallbackMethod("cb" + i++);
+		}
+
+		if (isClient) {
+
+			action = new ClientClassGenerationAction() {
+				@Override
+				protected Writer openWriter(TemplateType templateType) throws Exception {
+					StringWriter writer = new StringWriter();
+					writers.add(writer);
+					return writer;
+				}
+
+			};
+
+		}
+
+		action.setMakePairs(true);
+
+		List<String> generated = execute(new EntityArtifact(testEntity1));
+		assertNotNull(generated);
+		assertEquals(2, generated.size());
+
+		String superclass = generated.get(0);
+
+		assertTrue(superclass, superclass.contains("public abstract class _TestClass1"));
+
+		for (int j = 0; j < i; j++) {
+			assertTrue(superclass, superclass.contains("protected abstract void cb" + j + "();"));
+		}
+
+		String subclass = generated.get(1);
+		for (int j = 0; j < i; j++) {
+			assertTrue(subclass, subclass.contains("protected void cb" + j + "() {"));
+		}
+	}
+
+	protected List<String> execute(Artifact artifact) throws Exception {
+
+		action.execute(artifact);
+
+		List<String> strings = new ArrayList<String>(writers.size());
+		for (StringWriter writer : writers) {
+			strings.add(writer.toString());
+		}
+		return strings;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationCase.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationCase.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationCase.java
new file mode 100644
index 0000000..44b709d
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationCase.java
@@ -0,0 +1,59 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.log.NullLogSystem;
+import org.junit.Before;
+
+import java.io.StringWriter;
+import java.util.Properties;
+
+public class ClassGenerationCase {
+
+    private VelocityEngine velocityEngine;
+
+    @Before
+    public void setUp() throws Exception {
+        Properties props = new Properties();
+
+        // null logger that will prevent velocity.log from being generated
+        props.put(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, NullLogSystem.class.getName());
+        props.put("resource.loader", "cayenne");
+        props.put("cayenne.resource.loader.class", ClassGeneratorResourceLoader.class.getName());
+        props.put("cayenne.resource.loader.cache", "false");
+
+        this.velocityEngine = new VelocityEngine();
+        this.velocityEngine.init(props);
+    }
+
+    protected String renderTemplate(String templateName, Context context) throws Exception {
+        StringWriter writer = new StringWriter();
+
+        Template template = velocityEngine.getTemplate(templateName);
+        template.merge(context, writer);
+
+        return writer.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java
new file mode 100644
index 0000000..b690367
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java
@@ -0,0 +1,86 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.velocity.VelocityContext;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ClientSuperClassGenerationTest extends ClassGenerationCase {
+
+    @Test
+    public void testNotContainsPropertyImport() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClientClassGenerationAction.SUPERCLASS_TEMPLATE, context);
+        assertFalse(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImportForAttributes() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjAttribute attr = new ObjAttribute("attr");
+        objEntity.addAttribute(attr);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClientClassGenerationAction.SUPERCLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImportForRelationships() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjRelationship rel = new ObjRelationship("rel");
+        objEntity.addRelationship(rel);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClientClassGenerationAction.SUPERCLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImport() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjAttribute attr = new ObjAttribute("attr");
+        ObjRelationship rel = new ObjRelationship("rel");
+
+        objEntity.addAttribute(attr);
+        objEntity.addRelationship(rel);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClientClassGenerationAction.SUPERCLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/test/java/org/apache/cayenne/gen/EntityUtilsTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/EntityUtilsTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/EntityUtilsTest.java
new file mode 100644
index 0000000..21d7162
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/EntityUtilsTest.java
@@ -0,0 +1,75 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.apache.cayenne.map.CallbackDescriptor;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.ObjEntity;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertTrue;
+
+
+public class EntityUtilsTest {
+    
+    protected EntityUtils entityUtils = null;
+    protected DataMap dataMap = null;
+    protected ObjEntity objEntity = null;
+    
+    @Before
+    public void setUp() throws Exception {
+        dataMap = new DataMap();
+        objEntity = new ObjEntity();
+    }
+    
+    @After
+    public void tearDown() throws Exception {
+        dataMap = null;
+        objEntity = null;
+        entityUtils = null;
+    }
+
+    @Test
+    public void testAllCallbackNamesUnique() throws Exception {
+        
+        CallbackDescriptor[] callbacks = objEntity.getCallbackMap().getCallbacks();
+        for (int i = 0; i < callbacks.length; i++) {
+            callbacks[i].addCallbackMethod("callback1");
+            callbacks[i].addCallbackMethod("callback2");
+            callbacks[i].addCallbackMethod("callback3");
+        }
+        entityUtils = new EntityUtils(dataMap, objEntity, "TestBaseClass", "TestSuperClass", "TestSubClass");
+        
+        boolean hasNoDuplicates = true;
+        Set<String> callbackNames = new LinkedHashSet<String>();
+        for (String cbName : entityUtils.getCallbackNames()) {
+            if (!callbackNames.add(cbName)) {
+                hasNoDuplicates = false;
+            }
+        }
+        
+        assertTrue("Contains duplicate callback names.", hasNoDuplicates);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ImportUtilsTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ImportUtilsTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ImportUtilsTest.java
new file mode 100644
index 0000000..c6baa31
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ImportUtilsTest.java
@@ -0,0 +1,252 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ImportUtilsTest {
+
+    protected ImportUtils importUtils = null;
+
+    @Before
+    public void setUp() throws Exception {
+        importUtils = new ImportUtils();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        importUtils = null;
+    }
+
+    @Test
+    public void testSetPackageGeneratesPackageStatement() throws Exception {
+        final String packageName = "org.myPackage";
+        final String expectedPackageStatement = "package " + packageName + ";";
+
+        importUtils.setPackage(packageName);
+
+        String generatedStatements = importUtils.generate();
+        assertTrue("<"
+                + generatedStatements
+                + "> does not start with <"
+                + expectedPackageStatement
+                + ">", generatedStatements.startsWith(expectedPackageStatement));
+        assertEquals("package statement appears multiple times.", generatedStatements
+                .lastIndexOf(expectedPackageStatement), generatedStatements
+                .lastIndexOf(expectedPackageStatement));
+    }
+
+    @Test
+    public void testAddTypeGeneratesImportStatement() throws Exception {
+        final String type = "org.myPackage.myType";
+        final String expectedImportStatement = "import " + type + ";";
+
+        importUtils.addType(type);
+
+        String generatedStatements = importUtils.generate();
+        assertFalse("<"
+                + generatedStatements
+                + "> does not contain <"
+                + expectedImportStatement
+                + ">", !generatedStatements.contains(expectedImportStatement));
+        assertEquals("import statement appears multiple times.", generatedStatements
+                .lastIndexOf(expectedImportStatement), generatedStatements
+                .lastIndexOf(expectedImportStatement));
+    }
+
+    @Test
+    public void testAddReservedTypeGeneratesNoImportStatement() throws Exception {
+        final String type = "org.myPackage.myType";
+
+        importUtils.addReservedType(type);
+
+        String generatedStatements = importUtils.generate();
+        assertEquals(
+                "<" + generatedStatements + "> contains <" + type + ">",
+                -1,
+                generatedStatements.indexOf(type));
+    }
+
+    @Test
+    public void testAddTypeAfterReservedTypeGeneratesNoImportStatement() throws Exception {
+        final String baseType = "myType";
+        final String reservedType = "org.myPackage." + baseType;
+        final String nonReservedType = "org.myPackage2." + baseType;
+
+        importUtils.addReservedType(reservedType);
+        importUtils.addType(nonReservedType);
+
+        String generatedStatements = importUtils.generate();
+        assertEquals(
+                "<" + generatedStatements + "> contains <" + reservedType + ">",
+                -1,
+                generatedStatements.indexOf(reservedType));
+        assertEquals(
+                "<" + generatedStatements + "> contains <" + nonReservedType + ">",
+                -1,
+                generatedStatements.indexOf(nonReservedType));
+    }
+
+    @Test
+    public void testAddTypeAfterPackageReservedTypeGeneratesNoImportStatement()
+            throws Exception {
+        final String baseType = "myType";
+        final String packageType = "org.myPackage";
+        final String reservedType = packageType + "." + baseType;
+        final String nonReservedType = "org.myPackage2." + baseType;
+
+        importUtils.setPackage(packageType);
+        importUtils.addReservedType(reservedType);
+        importUtils.addType(nonReservedType);
+
+        String generatedStatements = importUtils.generate();
+
+        assertEquals(
+                "<" + generatedStatements + "> contains <" + reservedType + ">",
+                -1,
+                generatedStatements.indexOf(reservedType));
+        assertEquals(
+                "<" + generatedStatements + "> contains <" + nonReservedType + ">",
+                -1,
+                generatedStatements.indexOf(nonReservedType));
+    }
+
+    @Test
+    public void testAddTypeAfterTypeGeneratesNoImportStatement() throws Exception {
+        final String baseType = "myType";
+        final String firstType = "org.myPackage." + baseType;
+        final String secondType = "org.myPackage2." + baseType;
+
+        final String expectedImportStatement = "import " + firstType + ";";
+
+        importUtils.addType(firstType);
+        importUtils.addType(secondType);
+
+        String generatedStatements = importUtils.generate();
+
+        assertFalse("<"
+                + generatedStatements
+                + "> does not contain <"
+                + expectedImportStatement
+                + ">", !generatedStatements.contains(expectedImportStatement));
+        assertEquals("import statement appears multiple times.", generatedStatements
+                .lastIndexOf(expectedImportStatement), generatedStatements
+                .lastIndexOf(expectedImportStatement));
+
+        assertEquals(
+                "<" + generatedStatements + "> contains <" + secondType + ">",
+                -1,
+                generatedStatements.indexOf(secondType));
+    }
+
+    @Test
+    public void testAddSimilarTypeTwiceBeforeFormatJavaTypeGeneratesCorrectFQNs()
+            throws Exception {
+        final String baseType = "myType";
+        final String firstType = "org.myPackage." + baseType;
+        final String secondType = "org.myPackage2." + baseType;
+
+        importUtils.addType(firstType);
+        importUtils.addType(secondType);
+
+        assertEquals(baseType, importUtils.formatJavaType(firstType));
+        assertEquals(secondType, importUtils.formatJavaType(secondType));
+    }
+
+    @Test
+    public void testAddTypeBeforeFormatJavaTypeGeneratesCorrectFQNs() throws Exception {
+        final String baseType = "myType";
+        final String fullyQualifiedType = "org.myPackage." + baseType;
+
+        importUtils.addType(fullyQualifiedType);
+
+        assertEquals(baseType, importUtils.formatJavaType(fullyQualifiedType));
+    }
+
+    @Test
+    public void testAddReservedTypeBeforeFormatJavaTypeGeneratesCorrectFQNs()
+            throws Exception {
+        final String baseType = "myType";
+        final String fullyQualifiedType = "org.myPackage." + baseType;
+
+        importUtils.addReservedType(fullyQualifiedType);
+
+        assertEquals(fullyQualifiedType, importUtils.formatJavaType(fullyQualifiedType));
+    }
+
+    @Test
+    public void testFormatJavaTypeWithPrimitives() throws Exception {
+        assertEquals("int", importUtils.formatJavaType("int", true));
+        assertEquals("Integer", importUtils.formatJavaType("int", false));
+
+        assertEquals("char", importUtils.formatJavaType("char", true));
+        assertEquals("Character", importUtils
+                .formatJavaType("java.lang.Character", false));
+
+        assertEquals("double", importUtils.formatJavaType("java.lang.Double", true));
+        assertEquals("Double", importUtils.formatJavaType("java.lang.Double", false));
+
+        assertEquals("a.b.C", importUtils.formatJavaType("a.b.C", true));
+        assertEquals("a.b.C", importUtils.formatJavaType("a.b.C", false));
+    }
+
+    @Test
+    public void testFormatJavaTypeWithoutAddTypeGeneratesCorrectFQNs() throws Exception {
+        final String baseType = "myType";
+        final String fullyQualifiedType = "org.myPackage." + baseType;
+
+        assertEquals(fullyQualifiedType, importUtils.formatJavaType(fullyQualifiedType));
+    }
+
+    @Test
+    public void testPackageFormatJavaTypeWithoutAddTypeGeneratesCorrectFQNs()
+            throws Exception {
+        final String baseType = "myType";
+        final String packageType = "org.myPackage";
+        final String fullyQualifiedType = packageType + "." + baseType;
+
+        importUtils.setPackage(packageType);
+
+        assertEquals(baseType, importUtils.formatJavaType(fullyQualifiedType));
+    }
+
+    @Test
+    public void testFormatJavaType() {
+        assertEquals("x.X", importUtils.formatJavaType("x.X"));
+        assertEquals("X", importUtils.formatJavaType("java.lang.X"));
+        assertEquals("java.lang.x.X", importUtils.formatJavaType("java.lang.x.X"));
+    }
+
+    @Test
+    public void testJavaLangTypeFormatJavaTypeWithoutAddTypeGeneratesCorrectFQNs()
+            throws Exception {
+        final String baseType = "myType";
+        final String packageType = "java.lang";
+        final String fullyQualifiedType = packageType + "." + baseType;
+
+        assertEquals(baseType, importUtils.formatJavaType(fullyQualifiedType));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SingleClassGenerationTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SingleClassGenerationTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SingleClassGenerationTest.java
new file mode 100644
index 0000000..0bbe9e9
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SingleClassGenerationTest.java
@@ -0,0 +1,86 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.velocity.VelocityContext;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class SingleClassGenerationTest extends ClassGenerationCase {
+
+    @Test
+    public void testNotContainsPropertyImport() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClassGenerationAction.SINGLE_CLASS_TEMPLATE, context);
+        assertFalse(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImportForAttributes() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjAttribute attr = new ObjAttribute("attr");
+        objEntity.addAttribute(attr);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClassGenerationAction.SINGLE_CLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImportForRelationships() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjRelationship rel = new ObjRelationship("rel");
+        objEntity.addRelationship(rel);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClassGenerationAction.SINGLE_CLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImport() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjAttribute attr = new ObjAttribute("attr");
+        ObjRelationship rel = new ObjRelationship("rel");
+
+        objEntity.addAttribute(attr);
+        objEntity.addRelationship(rel);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClassGenerationAction.SINGLE_CLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/test/java/org/apache/cayenne/gen/StringUtilsTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/StringUtilsTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/StringUtilsTest.java
new file mode 100644
index 0000000..84e7e5e
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/StringUtilsTest.java
@@ -0,0 +1,124 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class StringUtilsTest {
+
+    protected StringUtils stringUtils;
+
+    @Before
+    public void setUp() throws Exception {
+        stringUtils = new StringUtils();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        stringUtils = null;
+    }
+
+    @Test
+    public void testPluralize() throws Exception {
+        assertEquals("Words", stringUtils.pluralize("Word"));
+        assertEquals("Statuses", stringUtils.pluralize("Status"));
+        assertEquals("Indexes", stringUtils.pluralize("Index"));
+        assertEquals("Factories", stringUtils.pluralize("Factory"));
+        assertEquals("", stringUtils.pluralize(""));
+        assertEquals(null, stringUtils.pluralize(null));
+    }
+
+
+    @Test
+    public void testCapitalizedAsConstant1() throws Exception {
+        String expected = "LAST_NAME";
+        assertEquals(expected, stringUtils.capitalizedAsConstant("LastName"));
+    }
+
+    @Test
+    public void testCapitalizedAsConstant2() throws Exception {
+        String expected = "A_CLASS";
+        assertEquals(expected, stringUtils.capitalizedAsConstant("aClass"));
+    }
+
+    @Test
+    public void testCapitalizedAsConstant3() throws Exception {
+        String expected = "VAR_A";
+        assertEquals(expected, stringUtils.capitalizedAsConstant("varA"));
+    }
+
+    @Test
+    public void testCapitalizedAsConstant4() throws Exception {
+        String expected = "LAST_NAME";
+        assertEquals(expected, stringUtils.capitalizedAsConstant("LAST_NAME"));
+    }
+
+    @Test
+    public void testCapitalizedAsConstant5() throws Exception {
+        String expected = "ABC_A";
+        assertEquals(expected, stringUtils.capitalizedAsConstant("abc_A"));
+    }
+
+    @Test
+    public void testCapitalizedAsConstant6() throws Exception {
+        String expected = "A123";
+        assertEquals(expected, stringUtils.capitalizedAsConstant("a123"));
+    }
+
+    @Test
+    public void testCapitalizedAsConstant7() throws Exception {
+        String expected = "AB_CDEF";
+        assertEquals(expected, stringUtils.capitalizedAsConstant("abCDEF"));
+    }
+
+    @Test
+    public void testCapitalizedAsConstant8() throws Exception {
+        String expected = "AB_CE";
+        assertEquals(expected, stringUtils.capitalizedAsConstant("abCe"));
+    }
+
+    @Test
+    public void testStripGeneric() throws Exception {
+        assertEquals("List", stringUtils.stripGeneric("List"));
+        assertEquals("List", stringUtils.stripGeneric("List<Integer>"));
+        assertEquals("List", stringUtils.stripGeneric("List<List<Map<Integer,List<String>>>>"));
+        assertEquals("List123", stringUtils.stripGeneric("List<List<Map<Integer,List<String>>>>123"));
+        assertEquals("List<Integer", stringUtils.stripGeneric("List<Integer"));
+    }
+
+    /**
+     * Test pattern expansion.
+     */
+    @Test
+    public void testReplaceWildcardInStringWithString() throws Exception {
+        assertEquals(null, stringUtils.replaceWildcardInStringWithString("*", null, "Entity"));
+        assertEquals("*.java", stringUtils.replaceWildcardInStringWithString(null, "*.java", "Entity"));
+        assertEquals("Entity.java", stringUtils.replaceWildcardInStringWithString("*", "*.java", "Entity"));
+        assertEquals("java.Entity", stringUtils.replaceWildcardInStringWithString("*", "java.*", "Entity"));
+        assertEquals("Entity.Entity", stringUtils.replaceWildcardInStringWithString("*", "*.*", "Entity"));
+        assertEquals("EntityEntity", stringUtils.replaceWildcardInStringWithString("*", "**", "Entity"));
+        assertEquals("EditEntityReport.vm", stringUtils.replaceWildcardInStringWithString("*", "Edit*Report.vm", "Entity"));
+        assertEquals("Entity", stringUtils.replaceWildcardInStringWithString("*", "*", "Entity"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java
new file mode 100644
index 0000000..0a47d63
--- /dev/null
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java
@@ -0,0 +1,86 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.gen;
+
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.velocity.VelocityContext;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class SuperClassGenerationTest extends ClassGenerationCase {
+
+    @Test
+    public void testNotContainsPropertyImport() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClassGenerationAction.SUPERCLASS_TEMPLATE, context);
+        assertFalse(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImportForAttributes() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjAttribute attr = new ObjAttribute("attr");
+        objEntity.addAttribute(attr);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClassGenerationAction.SUPERCLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImportForRelationships() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjRelationship rel = new ObjRelationship("rel");
+        objEntity.addRelationship(rel);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClassGenerationAction.SUPERCLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+    @Test
+    public void testContainsPropertyImport() throws Exception {
+        ObjEntity objEntity = new ObjEntity("TEST1");
+        ObjAttribute attr = new ObjAttribute("attr");
+        ObjRelationship rel = new ObjRelationship("rel");
+
+        objEntity.addAttribute(attr);
+        objEntity.addRelationship(rel);
+
+        VelocityContext context = new VelocityContext();
+        context.put(Artifact.OBJECT_KEY, objEntity);
+
+        String res = renderTemplate(ClassGenerationAction.SUPERCLASS_TEMPLATE, context);
+        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-client-jetty/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-client-jetty/pom.xml b/cayenne-client-jetty/pom.xml
index 0f1b41c..0fae133 100644
--- a/cayenne-client-jetty/pom.xml
+++ b/cayenne-client-jetty/pom.xml
@@ -121,7 +121,7 @@
                     <target>1.8</target>
                 </configuration>
             </plugin>
-            <!-- This ensures LICESNE and NOTICE inclusion in all jars -->
+            <!-- This ensures LICENSE and NOTICE inclusion in all jars -->
             <plugin>
                 <artifactId>maven-remote-resources-plugin</artifactId>
                 <executions>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-client/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-client/pom.xml b/cayenne-client/pom.xml
index 2d16644..a9112a5 100644
--- a/cayenne-client/pom.xml
+++ b/cayenne-client/pom.xml
@@ -93,7 +93,7 @@
 
 	<build>
 		<plugins>
-			<!-- This ensures LICESNE and NOTICE inclusion in all jars -->
+			<!-- This ensures LICENSE and NOTICE inclusion in all jars -->
             <plugin>
                 <artifactId>maven-remote-resources-plugin</artifactId>
                 <executions>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-dbcp2/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-dbcp2/pom.xml b/cayenne-dbcp2/pom.xml
index b44c5af..35d9771 100644
--- a/cayenne-dbcp2/pom.xml
+++ b/cayenne-dbcp2/pom.xml
@@ -49,7 +49,7 @@
     </dependencies>
     <build>
         <plugins>
-            <!-- This ensures LICESNE and NOTICE inclusion in all jars -->
+            <!-- This ensures LICENSE and NOTICE inclusion in all jars -->
             <plugin>
                 <artifactId>maven-remote-resources-plugin</artifactId>
                 <executions>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-dbsync/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/pom.xml b/cayenne-dbsync/pom.xml
index d94de3f..367c671 100644
--- a/cayenne-dbsync/pom.xml
+++ b/cayenne-dbsync/pom.xml
@@ -96,7 +96,7 @@
 
 	<build>
 		<plugins>
-			<!-- This ensures LICESNE and NOTICE inclusion in all jars -->
+			<!-- This ensures LICENSE and NOTICE inclusion in all jars -->
             <plugin>
                 <artifactId>maven-remote-resources-plugin</artifactId>
                 <executions>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/filter/NamePatternMatcher.java
----------------------------------------------------------------------
diff --git a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/filter/NamePatternMatcher.java b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/filter/NamePatternMatcher.java
index 66d2b96..cb379da 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/filter/NamePatternMatcher.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/filter/NamePatternMatcher.java
@@ -203,31 +203,4 @@ public class NamePatternMatcher implements NameFilter {
         return true;
     }
 
-    public static String replaceWildcardInStringWithString(
-            String wildcard,
-            String pattern,
-            String replacement) {
-
-        if (pattern == null || wildcard == null) {
-            return pattern;
-        }
-
-        StringBuilder buffer = new StringBuilder();
-        int lastPos = 0;
-        int wildCardPos = pattern.indexOf(wildcard);
-        while (wildCardPos != -1) {
-            if (lastPos != wildCardPos) {
-                buffer.append(pattern.substring(lastPos, wildCardPos));
-            }
-            buffer.append(replacement);
-            lastPos += wildCardPos + wildcard.length();
-            wildCardPos = pattern.indexOf(wildcard, lastPos);
-        }
-
-        if (lastPos < pattern.length()) {
-            buffer.append(pattern.substring(lastPos));
-        }
-
-        return buffer.toString();
-    }
 }