JDO-709: Add more TCK converter test cases (#24)

Added converter test cases IntAttributeConverterTest
- PCPoint fields of a basic type and a wrapper class type
- PCPointAnnotated uses annotations for JDO metadata
- PCPointProps defines the JDO metadata for properties instead of fields
- PCPointPropAnnotated uses annotations for JDO metadata for properties
- Refactored the converter test cases in its own package
- XML class metadata an annotated class use the same datastore table
diff --git a/tck/src/main/java/org/apache/jdo/tck/api/converter/IntAttributeConverterTest.java b/tck/src/main/java/org/apache/jdo/tck/api/converter/IntAttributeConverterTest.java
new file mode 100644
index 0000000..d14a23e
--- /dev/null
+++ b/tck/src/main/java/org/apache/jdo/tck/api/converter/IntAttributeConverterTest.java
@@ -0,0 +1,442 @@
+/*
+ * 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.jdo.tck.api.converter;
+
+import org.apache.jdo.tck.JDO_Test;
+import org.apache.jdo.tck.pc.converter.IPCPoint;
+import org.apache.jdo.tck.pc.converter.PCPoint;
+import org.apache.jdo.tck.pc.converter.PCPointAnnotated;
+import org.apache.jdo.tck.pc.converter.PCPointProp;
+import org.apache.jdo.tck.pc.converter.PCPointPropAnnotated;
+import org.apache.jdo.tck.util.BatchTestRunner;
+import org.apache.jdo.tck.util.IntegerToStringConverter;
+
+import javax.jdo.JDOHelper;
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+/**
+ *<B>Title:</B>IntAttributeConverterTest
+ *<BR>
+ *<B>Keywords:</B> mapping
+ *<BR>
+ *<B>Assertion ID:</B> [not identified]
+ *<BR>
+ *<B>Assertion Description: </B>
+ * A IPCPoint instance has an int and an Integer field, that are stored as strings in the datastore.
+ * The int / Integer fields are converted using an AttributeConverter.
+ */
+public class IntAttributeConverterTest extends JDO_Test {
+
+    private static final int MIN_X = 1;
+    private static final int MIN_Y = 5;
+
+    /**
+     * The <code>main</code> is called when the class
+     * is directly executed from the command line.
+     * @param args The arguments passed to the program.
+     */
+    public static void main(String[] args) {
+        BatchTestRunner.run(IntAttributeConverterTest.class);
+    }
+
+    /**
+     * @see JDO_Test#localSetUp()
+     */
+    @Override
+    protected void localSetUp() {
+        addTearDownClass(PCPoint.class);
+        addTearDownClass(PCPointAnnotated.class);
+        addTearDownClass(PCPointProp.class);
+        addTearDownClass(PCPointPropAnnotated.class);
+    }
+
+    /**
+     * Test method creating and storing a PCPoint instance.
+     */
+    public void testStorePCPointInstance() {
+        runStoreIPCPointInstance(PCPoint.class);
+    }
+
+    /**
+     * Test method reading a PCPoint instance from the datastore.
+     */
+    public void testReadPCPointInstance() {
+        runReadIPCPointInstance(PCPoint.class);
+    }
+
+    /**
+     * Test method modifying a PCPoint instance and storing in the datastore.
+     */
+    public void testModifyPCPointInstance() {
+        runModifyIPCPointInstance(PCPoint.class);
+    }
+
+    /**
+     * Test method running a PCPoint query with a query parameter of type Point.
+     */
+    public void testPCPointQueryWithPointParam() throws Exception {
+        runQueryWithIntParameter(PCPoint.class);
+    }
+
+    /**
+     * Test method running a PCPoint query with a query parameter of type String.
+     */
+    public void testPCPointQueryWithStringParam() throws Exception {
+        runQueryWithStringParameter(PCPoint.class);
+    }
+
+    /**
+     * Test method creating and storing a PCPointAnnotated instance.
+     */
+    public void testStorePCPointAnnotatedInstance() {
+        runStoreIPCPointInstance(PCPointAnnotated.class);
+    }
+
+    /**
+     * Test method reading a PCPointAnnotated instance from the datastore.
+     */
+    public void testReadPCPointAnnotatedInstance() {
+        runReadIPCPointInstance(PCPointAnnotated.class);
+    }
+
+    /**
+     * Test method modifying a PCPointAnnotated instance and storing in the datastore.
+     */
+    public void testModifyPCPointAnnotatedInstance() {
+        runModifyIPCPointInstance(PCPointAnnotated.class);
+    }
+
+    /**
+     * Test method running a PCPointAnnotated query with a query parameter of type String.
+     */
+    public void testPCPointAnnotatedQueryWithPointParam() throws Exception {
+        runQueryWithIntParameter(PCPointAnnotated.class);
+    }
+
+    /**
+     * Test method running a PCPointAnnotated query with a query parameter of type Point.
+     */
+    public void testPCPointAnnotatedQueryWithStringParam() throws Exception {
+        runQueryWithStringParameter(PCPointAnnotated.class);
+    }
+
+    /**
+     * Test method creating and storing a PCPoint instance.
+     */
+    public void testStorePCPointPropInstance() {
+        runStoreIPCPointInstance(PCPointProp.class);
+    }
+
+    /**
+     * Test method reading a PCPoint instance from the datastore.
+     */
+    public void testReadPCPointPropInstance() {
+        runReadIPCPointInstance(PCPointProp.class);
+    }
+
+    /**
+     * Test method modifying a PCPoint instance and storing in the datastore.
+     */
+    public void testModifyPCPointPropInstance() {
+        runModifyIPCPointInstance(PCPointProp.class);
+    }
+
+    /**
+     * Test method running a PCPoint query with a query parameter of type Point.
+     */
+    public void testPCPointPropQueryWithPointParam() throws Exception {
+        runQueryWithIntParameter(PCPointProp.class);
+    }
+
+    /**
+     * Test method running a PCPoint query with a query parameter of type String.
+     */
+    public void testPCPointPropQueryWithStringParam() throws Exception {
+        runQueryWithStringParameter(PCPointProp.class);
+    }
+
+    /**
+     * Test method creating and storing a PCPointAnnotated instance.
+     */
+    public void testStorePCPointPropAnnotatedInstance() {
+        runStoreIPCPointInstance(PCPointPropAnnotated.class);
+    }
+
+    /**
+     * Test method reading a PCPointAnnotated instance from the datastore.
+     */
+    public void testReadPCPointPropAnnotatedInstance() {
+        runReadIPCPointInstance(PCPointPropAnnotated.class);
+    }
+
+    /**
+     * Test method modifying a PCPointAnnotated instance and storing in the datastore.
+     */
+    public void testModifyPCPointPropAnnotatedInstance() {
+        runModifyIPCPointInstance(PCPointPropAnnotated.class);
+    }
+
+    /**
+     * Test method running a PCPointAnnotated query with a query parameter of type String.
+     */
+    public void testPCPointPropAnnotatedQueryWithPointParam() throws Exception {
+        runQueryWithIntParameter(PCPointPropAnnotated.class);
+    }
+
+    /**
+     * Test method running a PCPointAnnotated query with a query parameter of type Point.
+     */
+    public void testPCPointPropAnnotatedQueryWithStringParam() throws Exception {
+        runQueryWithStringParameter(PCPointPropAnnotated.class);
+    }
+
+
+    // Helper methods
+
+    /**
+     * Helper method creating a IPCPoint instance.
+     * It should call AttributeConverter method convertToDatastore.
+     */
+    private <T extends IPCPoint> void runStoreIPCPointInstance(Class<T> pcPointClass) {
+        int nrOfDbCalls = IntegerToStringConverter.getNrOfConvertToDatastoreCalls();
+        int nrOfAttrCalls = IntegerToStringConverter.getNrOfConvertToAttributeCalls();
+
+        // Create a persistent IPCPoint instance and store its oid
+        // AttributeConverter method convertToDatastore is called when persisting instance
+        createIPCPointInstances(pcPointClass, 1);
+
+        // convertToDatastore should be called twice
+        assertEquals(2, IntegerToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
+        // convertToAttribute should not be called
+        assertEquals(0, IntegerToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
+    }
+
+    /**
+     * Helper method reading a IPCPoint instance from the datastore.
+     * It should call AttributeConverter method convertToAttribute.
+     */
+    private <T extends IPCPoint> void runReadIPCPointInstance(Class<T> pcPointClass) {
+        IPCPoint point;
+        Object oid;
+        int nrOfDbCalls;
+        int nrOfAttrCalls;
+
+        // Create a persistent IPCPoint instance and store its oid
+        oid = createIPCPointInstances(pcPointClass, 1);
+
+        // Cleanup the 2nd-level cache and close the pm to make sure PCPoint instances are not cached
+        pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcPointClass);
+        pm.close();
+        pm = null;
+
+        nrOfDbCalls = IntegerToStringConverter.getNrOfConvertToDatastoreCalls();
+        nrOfAttrCalls = IntegerToStringConverter.getNrOfConvertToAttributeCalls();
+        pm = getPM();
+        pm.currentTransaction().begin();
+        // Read the IPCPoint instance from the datastore, this should call convertToAttribute
+        point = (IPCPoint)pm.getObjectById(oid);
+        int x = point.getX();
+        Integer y = point.getY();
+        pm.currentTransaction().commit();
+
+        // convertToDatastore should not be called
+        assertEquals(0, IntegerToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
+        // convertToAttribute should be called twice
+        assertEquals(2, IntegerToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
+        // Check the values of the associated Point instances
+        assertEquals(MIN_X, x);
+        assertEquals(MIN_Y, y == null ? 0 : y.intValue());
+    }
+
+    /**
+     * Helper method modifying a IPCPoint instance.
+     * It should call AttributeConverter method convertToDatastore.
+     */
+    private <T extends IPCPoint> void runModifyIPCPointInstance(Class<T> pcPointClass) {
+        Transaction tx;
+        IPCPoint point;
+        Object oid;
+        int nrOfDbCalls;
+        int nrOfAttrCalls;
+
+        // Create a persistent IPCPoint instance and store its oid
+        oid = createIPCPointInstances(pcPointClass, 1);
+
+        // Cleanup the 2nd-level cache and close the pm to make sure PCPoint instances are not cached
+        pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcPointClass);
+        pm.close();
+        pm = null;
+
+        nrOfDbCalls = IntegerToStringConverter.getNrOfConvertToDatastoreCalls();
+        nrOfAttrCalls = IntegerToStringConverter.getNrOfConvertToAttributeCalls();
+        pm = getPM();
+        tx = pm.currentTransaction();
+        tx.begin();
+        // Load the PCPoint instance, this should call convertToAttribute
+        point = (IPCPoint)pm.getObjectById(oid);
+        // Update IPCPoint instance, this should call convertToDatastore
+        point.setX(MIN_X + 1);
+        point.setY(Integer.valueOf(MIN_Y + 1));
+        // IPCPoint instance should be dirty
+        assertTrue(JDOHelper.isDirty(point));
+        tx.commit();
+
+        // convertToDatastore should be called twice
+        assertEquals(2, IntegerToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
+        // convertToAttribute should be called twice
+        assertEquals(2, IntegerToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
+    }
+
+    /**
+     * Helper method running a query with an int parameter.
+     * The parameter value is converted using the AttributeConverter.
+     * @throws Exception
+     */
+    private <T extends IPCPoint> void runQueryWithIntParameter(Class<T> pcPointClass) throws Exception {
+        int nrOfDbCalls;
+        int nrOfAttrCalls;
+
+        nrOfDbCalls = IntegerToStringConverter.getNrOfConvertToDatastoreCalls();
+        nrOfAttrCalls = IntegerToStringConverter.getNrOfConvertToAttributeCalls();
+        createIPCPointInstances(pcPointClass, 5);
+        // convertToDatastore should be called twice per instance = 10 times
+        assertEquals(10, IntegerToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
+        // convertToAttribute should not be called
+        assertEquals(0, IntegerToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
+
+        // Cleanup the 2nd-level cache and close the pm to make sure PCPoint instances are not cached
+        pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcPointClass);
+        pm.close();
+        pm = null;
+
+        nrOfDbCalls = IntegerToStringConverter.getNrOfConvertToDatastoreCalls();
+        nrOfAttrCalls = IntegerToStringConverter.getNrOfConvertToAttributeCalls();
+        pm = getPM();
+        pm.currentTransaction().begin();
+        try (Query<T> q = pm.newQuery(pcPointClass, "this.x == :param")) {
+            q.setParameters(MIN_X + 1);
+            // AttributeConverter method convertToAttribute is called when loading instance from the datastore
+            List<T> res = q.executeList();
+            assertEquals(1, res.size());
+            IPCPoint point = res.get(0);
+
+            // Check the coordinates of the associated Point instances
+            assertEquals(MIN_X + 1, point.getX());
+            assertEquals(MIN_Y + 1, point.getY() == null ? 0 : point.getY().intValue());
+        } catch (Exception e) {
+            fail(e.getMessage());
+        } finally {
+            pm.currentTransaction().commit();
+        }
+
+        // convertToDatastore should be called to handle the query parameter
+        assertTrue(IntegerToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls >= 1);
+        // convertToAttribute should be called at least twice
+        assertTrue(IntegerToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls >= 2);
+    }
+
+    /**
+     * Helper method running a query with a Point parameter.
+     * The string parameter is compared to the converted int field.
+     * @throws Exception
+     */
+    private <T extends IPCPoint> void runQueryWithStringParameter(Class<T> pcPointClass) throws Exception {
+        int nrOfDbCalls;
+        int nrOfAttrCalls;
+
+        nrOfDbCalls = IntegerToStringConverter.getNrOfConvertToDatastoreCalls();
+        nrOfAttrCalls = IntegerToStringConverter.getNrOfConvertToAttributeCalls();
+        createIPCPointInstances(pcPointClass,5);
+        // convertToDatastore should be called twice per instance = 10 times
+        assertEquals(10, IntegerToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
+        // convertToAttribute should not be called
+        assertEquals(0, IntegerToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
+
+        // Cleanup the 2nd-level cache and close the pm to make sure PCPoint instances are not cached
+        pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcPointClass);
+        pm.close();
+        pm = null;
+
+        nrOfDbCalls = IntegerToStringConverter.getNrOfConvertToDatastoreCalls();
+        nrOfAttrCalls = IntegerToStringConverter.getNrOfConvertToAttributeCalls();
+        pm = getPM();
+        pm.currentTransaction().begin();
+        try (Query<T> q = pm.newQuery(pcPointClass, "this.x == param")) {
+            q.declareParameters("String param");
+            q.setParameters("3");
+            // AttributeConverter method convertToAttribute is called when loading instance from the datastore
+            List<T> res = q.executeList();
+            assertEquals(1, res.size());
+            IPCPoint point = res.get(0);
+
+            assertEquals(MIN_X+2, point.getX());
+            assertEquals(MIN_Y+2, point.getY() == null ? 0 : point.getY().intValue());
+        } finally {
+            pm.currentTransaction().commit();
+        }
+
+        // convertToDatastore should not be called
+        assertTrue(IntegerToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls == 0);
+        // convertToAttribute should be called at least twice
+        assertTrue(IntegerToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls >= 2);
+
+    }
+
+    /**
+     * Helper method to create IPCPoint instances.
+     * @param pcPointClass class instance of the IPCPoint implementation class to be created
+     * @param nrOfObjects number of IPCPoint instances to be created
+     * @return ObjectId of the first IPCPoint instance
+     */
+    private <T extends IPCPoint> Object createIPCPointInstances(Class<T> pcPointClass, int nrOfObjects) {
+        IPCPoint point;
+        Object oid = null;
+
+        if (nrOfObjects < 1) {
+            return null;
+        }
+
+        pm = getPM();
+        try {
+            pm.currentTransaction().begin();
+            point = pcPointClass.getConstructor().newInstance();
+            point.setX(MIN_X);
+            point.setY(Integer.valueOf(MIN_Y));
+            pm.makePersistent(point);
+            oid = pm.getObjectId(point);
+            for (int i = 1; i < nrOfObjects; i++) {
+                point = pcPointClass.getConstructor().newInstance();
+                point.setX(MIN_X + i);
+                point.setY(Integer.valueOf(MIN_Y + i));
+                pm.makePersistent(point);
+            }
+            pm.currentTransaction().commit();
+        } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException |
+                IllegalArgumentException | InvocationTargetException ex) {
+            fail("Error creating IPCPoint instance: " + ex.getMessage());
+        } finally {
+            if (pm.currentTransaction().isActive()) {
+                pm.currentTransaction().rollback();
+            }
+        }
+        return oid;
+    }
+
+}
diff --git a/tck/src/main/java/org/apache/jdo/tck/api/converter/AttributeConverterTest.java b/tck/src/main/java/org/apache/jdo/tck/api/converter/PointAttributeConverterTest.java
similarity index 91%
rename from tck/src/main/java/org/apache/jdo/tck/api/converter/AttributeConverterTest.java
rename to tck/src/main/java/org/apache/jdo/tck/api/converter/PointAttributeConverterTest.java
index 36f1b7b..019ebf3 100644
--- a/tck/src/main/java/org/apache/jdo/tck/api/converter/AttributeConverterTest.java
+++ b/tck/src/main/java/org/apache/jdo/tck/api/converter/PointAttributeConverterTest.java
@@ -17,9 +17,9 @@
 package org.apache.jdo.tck.api.converter;
 
 import org.apache.jdo.tck.JDO_Test;
-import org.apache.jdo.tck.pc.mylib.IPCRect;
-import org.apache.jdo.tck.pc.mylib.PCRectString;
-import org.apache.jdo.tck.pc.mylib.PCRectStringAnnotated;
+import org.apache.jdo.tck.pc.converter.IPCRect;
+import org.apache.jdo.tck.pc.converter.PCRect;
+import org.apache.jdo.tck.pc.converter.PCRectAnnotated;
 import org.apache.jdo.tck.pc.mylib.Point;
 import org.apache.jdo.tck.util.BatchTestRunner;
 import org.apache.jdo.tck.util.PointToStringConverter;
@@ -31,7 +31,7 @@
 import java.util.List;
 
 /**
- *<B>Title:</B>AttributeConverterTest
+ *<B>Title:</B>PointAttributeConverterTest
  *<BR>
  *<B>Keywords:</B> mapping
  *<BR>
@@ -41,7 +41,7 @@
  * A IPCRect instance refers two Point instances, that are stored as strings in the datastore.
  * A Point instance is converted using an AttributeConverter.
  */
-public class AttributeConverterTest extends JDO_Test {
+public class PointAttributeConverterTest extends JDO_Test {
 
     private static final int UL_X = 1;
     private static final int UL_Y = 10;
@@ -54,7 +54,7 @@
      * @param args The arguments passed to the program.
      */
     public static void main(String[] args) {
-        BatchTestRunner.run(AttributeConverterTest.class);
+        BatchTestRunner.run(PointAttributeConverterTest.class);
     }
 
     /**
@@ -62,78 +62,78 @@
      */
     @Override
     protected void localSetUp() {
-        addTearDownClass(PCRectString.class);
-        addTearDownClass(PCRectStringAnnotated.class);
+        addTearDownClass(PCRect.class);
+        addTearDownClass(PCRectAnnotated.class);
     }
 
     /**
      * Test method creating and storing a PCRectString instance.
      */
     public void testStorePCRectStringInstance() {
-        runStoreIPCRectInstance(PCRectString.class);
+        runStoreIPCRectInstance(PCRect.class);
     }
 
     /**
      * Test method reading a PCRectString instance from the datastore.
      */
     public void testReadPCRectStringInstance() {
-        runReadIPCRectInstance(PCRectString.class);
+        runReadIPCRectInstance(PCRect.class);
     }
 
     /**
      * Test method modifying a PCRectString instance and storing in the datastore.
      */
     public void testModifyPCRectStringInstance() {
-        runModifyIPCRectInstance(PCRectString.class);
+        runModifyIPCRectInstance(PCRect.class);
     }
 
     /**
      * Test method running a PCRectString query with a query parameter of type Point.
      */
     public void testPCRectStringQueryWithPointParam() throws Exception {
-        runQueryWithPointParameter(PCRectString.class);
+        runQueryWithPointParameter(PCRect.class);
     }
 
     /**
      * Test method running a PCRectString query with a query parameter of type String.
      */
     public void testPCRectStringQueryWithStringParam() throws Exception {
-        runQueryWithStringParameter(PCRectString.class);
+        runQueryWithStringParameter(PCRect.class);
     }
 
     /**
      * Test method creating and storing a PCRectStringAnnotated instance.
      */
     public void testStorePCRectStringAnnotatedInstance() {
-        runStoreIPCRectInstance(PCRectStringAnnotated.class);
+        runStoreIPCRectInstance(PCRectAnnotated.class);
     }
 
     /**
      * Test method reading a PCRectStringAnnotated instance from the datastore.
      */
     public void testReadPCRectStringAnnotatedInstance() {
-        runReadIPCRectInstance(PCRectStringAnnotated.class);
+        runReadIPCRectInstance(PCRectAnnotated.class);
     }
 
     /**
      * Test method modifying a PCRectStringAnnotated instance and storing in the datastore.
      */
     public void testModifyPCRectStringAnnotatedInstance() {
-        runModifyIPCRectInstance(PCRectStringAnnotated.class);
+        runModifyIPCRectInstance(PCRectAnnotated.class);
     }
 
     /**
      * Test method running a PCRectStringAnnotated query with a query parameter of type String.
      */
     public void testPCRectStringAnnotatedQueryWithPointParam() throws Exception {
-        runQueryWithPointParameter(PCRectStringAnnotated.class);
+        runQueryWithPointParameter(PCRectAnnotated.class);
     }
 
     /**
      * Test method running a PCRectStringAnnotated query with a query parameter of type Point.
      */
     public void testPCRectStringAnnotatedQueryWithStringParam() throws Exception {
-        runQueryWithStringParameter(PCRectStringAnnotated.class);
+        runQueryWithStringParameter(PCRectAnnotated.class);
     }
 
     // Helper methods
@@ -209,12 +209,20 @@
         // Create a persistent IPCRect instance and store its oid
         oid = createIPCRectInstances(pcrectClass, 1);
 
+        // Cleanup the 2nd-level cache and close the pm to make sure PCRect instances are not cached
+        pm.getPersistenceManagerFactory().getDataStoreCache().evictAll(false, pcrectClass);
+        pm.close();
+        pm = null;
+
         nrOfDbCalls = PointToStringConverter.getNrOfConvertToDatastoreCalls();
         nrOfAttrCalls = PointToStringConverter.getNrOfConvertToAttributeCalls();
         pm = getPM();
         tx = pm.currentTransaction();
         tx.begin();
         rect = (IPCRect)pm.getObjectById(oid);
+        // should trigger convertToAttribute
+        rect.getLowerRight();
+        rect.getUpperLeft();
         // Update IPCRect instance, this should call convertToDatastore
         rect.setUpperLeft(new Point(UL_X + 1, UL_Y + 1));
         rect.setLowerRight(new Point(LR_X + 1, LR_Y + 1));
@@ -224,8 +232,8 @@
 
         // convertToDatastore should be called twice
         assertEquals(2, PointToStringConverter.getNrOfConvertToDatastoreCalls() - nrOfDbCalls);
-        // convertToAttribute should not be called
-        assertEquals(0, PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
+        // convertToAttribute should be called twice
+        assertEquals(2, PointToStringConverter.getNrOfConvertToAttributeCalls() - nrOfAttrCalls);
     }
 
     /**
@@ -334,7 +342,7 @@
 
     /**
      * Helper method to create IPCRect instances.
-     * @param pcrectClass class instance of the IPCRect implementation class to be craeted
+     * @param pcrectClass class instance of the IPCRect implementation class to be created
      * @param nrOfObjects number of IPCRect instances to be created
      * @return ObjectId of the first IPCRect instance
      */
diff --git a/tck/src/main/java/org/apache/jdo/tck/pc/mylib/IPCRect.java b/tck/src/main/java/org/apache/jdo/tck/pc/converter/IPCPoint.java
similarity index 72%
copy from tck/src/main/java/org/apache/jdo/tck/pc/mylib/IPCRect.java
copy to tck/src/main/java/org/apache/jdo/tck/pc/converter/IPCPoint.java
index a328200..357b4b0 100644
--- a/tck/src/main/java/org/apache/jdo/tck/pc/mylib/IPCRect.java
+++ b/tck/src/main/java/org/apache/jdo/tck/pc/converter/IPCPoint.java
@@ -14,15 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jdo.tck.pc.mylib;
+package org.apache.jdo.tck.pc.converter;
 
 /**
- * Interface for common methods of implementation classes PCRectString and PCRectStringAnnotated.
+ * Interface for common methods of implementation classes PCPoint, PCPointAnnotated,
+ * PCPointProp and PCPointPropAnnotated.
  */
-public interface IPCRect {
-    Point getUpperLeft();
-    void setUpperLeft(Point upperLeft);
+public interface IPCPoint {
+    int getX();
+    void setX(int x);
 
-    Point getLowerRight();
-    void setLowerRight(Point lowerRight);
+    Integer getY();
+    void setY(Integer y);
 }
diff --git a/tck/src/main/java/org/apache/jdo/tck/pc/mylib/IPCRect.java b/tck/src/main/java/org/apache/jdo/tck/pc/converter/IPCRect.java
similarity index 90%
rename from tck/src/main/java/org/apache/jdo/tck/pc/mylib/IPCRect.java
rename to tck/src/main/java/org/apache/jdo/tck/pc/converter/IPCRect.java
index a328200..4a543db 100644
--- a/tck/src/main/java/org/apache/jdo/tck/pc/mylib/IPCRect.java
+++ b/tck/src/main/java/org/apache/jdo/tck/pc/converter/IPCRect.java
@@ -14,10 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jdo.tck.pc.mylib;
+package org.apache.jdo.tck.pc.converter;
+
+import org.apache.jdo.tck.pc.mylib.Point;
 
 /**
- * Interface for common methods of implementation classes PCRectString and PCRectStringAnnotated.
+ * Interface for common methods of implementation classes PCRect and PCRectAnnotated.
  */
 public interface IPCRect {
     Point getUpperLeft();
diff --git a/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPoint.java b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPoint.java
new file mode 100644
index 0000000..f9beca3
--- /dev/null
+++ b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPoint.java
@@ -0,0 +1,61 @@
+/*
+ * 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.jdo.tck.pc.converter;
+import java.util.Date;
+
+/**
+ * PersistenceCapable class to test JDO AttributeConverter interface.
+ * Its fields of type int and Integer are converted to strings in the datastore.
+ */
+public class PCPoint implements IPCPoint {
+    private static long counter = new Date().getTime();
+
+    private static synchronized long newId() {
+        return counter++;
+    }
+
+    private long id = newId();
+    private int x;
+    private Integer y;
+
+    public PCPoint() {}
+
+    public long getId() {
+        return id;
+    }
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public int getX() {
+        return x;
+    }
+    public void setX(int x) {
+        this.x = x;
+    }
+
+    public Integer getY() {
+        return y;
+    }
+    public void setY(Integer y) {
+        this.y = y;
+    }
+
+    public String toString() {
+        return this.getClass().getName() + "(x: " + x + " / y: " + y + ")";
+    }
+}
diff --git a/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointAnnotated.java b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointAnnotated.java
new file mode 100644
index 0000000..3f379cc
--- /dev/null
+++ b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointAnnotated.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.jdo.tck.pc.converter;
+
+import org.apache.jdo.tck.util.IntegerToStringConverter;
+
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.Convert;
+import javax.jdo.annotations.PersistenceCapable;
+import java.util.Date;
+
+/**
+ * PersistenceCapable class to test JDO AttributeConverter interface.
+ * Its fields of type int and Integer are converted to strings in the datastore.
+ */
+@PersistenceCapable(table="PCPointConv")
+public class PCPointAnnotated implements IPCPoint {
+    private static long counter = new Date().getTime();
+
+    private static synchronized long newId() {
+        return counter++;
+    }
+
+    @Column(name="ID")
+    private long id = newId();
+
+    @Column(name="X")
+    @Convert(value = IntegerToStringConverter.class)
+    private int x;
+
+    @Column(name="Y")
+    @Convert(value = IntegerToStringConverter.class)
+    private Integer y;
+
+    public PCPointAnnotated() {}
+
+    public long getId() {
+        return id;
+    }
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public int getX() {
+        return x;
+    }
+    public void setX(int x ) {
+        this.x = x;
+    }
+
+    public Integer getY() {
+        return y;
+    }
+    public void setY(Integer y) {
+        this.y = y;
+    }
+
+    public String toString() {
+        return this.getClass().getName() + "(x: " + x + " / y: " + y + ")";
+    }
+}
diff --git a/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointProp.java b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointProp.java
new file mode 100644
index 0000000..10d88a7
--- /dev/null
+++ b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointProp.java
@@ -0,0 +1,61 @@
+/*
+ * 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.jdo.tck.pc.converter;
+import java.util.Date;
+
+/**
+ * PersistenceCapable class to test JDO AttributeConverter interface.
+ * Its fields of type int and Integer are converted to strings in the datastore.
+ */
+public class PCPointProp implements IPCPoint {
+    private static long counter = new Date().getTime();
+
+    private static synchronized long newId() {
+        return counter++;
+    }
+
+    private long id = newId();
+    private int x;
+    private Integer y;
+
+    public PCPointProp() {}
+
+    public long getId() {
+        return id;
+    }
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public int getX() {
+        return x;
+    }
+    public void setX(int x) {
+        this.x = x;
+    }
+
+    public Integer getY() {
+        return y;
+    }
+    public void setY(Integer y) {
+        this.y = y;
+    }
+
+    public String toString() {
+        return this.getClass().getName() + "(x: " + x + " / y: " + y + ")";
+    }
+}
diff --git a/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointPropAnnotated.java b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointPropAnnotated.java
new file mode 100644
index 0000000..40d3d8a
--- /dev/null
+++ b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCPointPropAnnotated.java
@@ -0,0 +1,73 @@
+/*
+ * 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.jdo.tck.pc.converter;
+
+import org.apache.jdo.tck.util.IntegerToStringConverter;
+
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.Convert;
+import javax.jdo.annotations.PersistenceCapable;
+import java.util.Date;
+
+/**
+ * PersistenceCapable class to test JDO AttributeConverter interface.
+ * Its fields of type int and Integer are converted to strings in the datastore.
+ */
+@PersistenceCapable(table="PCPointConv")
+public class PCPointPropAnnotated implements IPCPoint {
+    private static long counter = new Date().getTime();
+
+    private static synchronized long newId() {
+        return counter++;
+    }
+
+    private long id = newId();
+    private int x;
+    private Integer y;
+
+    public PCPointPropAnnotated() {}
+
+    @Column(name="ID")
+    public long getId() {
+        return id;
+    }
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    @Column(name="X")
+    @Convert(value = IntegerToStringConverter.class)
+    public int getX() {
+        return x;
+    }
+    public void setX(int x ) {
+        this.x = x;
+    }
+
+    @Column(name="Y")
+    @Convert(value = IntegerToStringConverter.class)
+    public Integer getY() {
+        return y;
+    }
+    public void setY(Integer y) {
+        this.y = y;
+    }
+
+    public String toString() {
+        return this.getClass().getName() + "(x: " + x + " / y: " + y + ")";
+    }
+}
diff --git a/tck/src/main/java/org/apache/jdo/tck/pc/mylib/PCRectString.java b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCRect.java
similarity index 90%
rename from tck/src/main/java/org/apache/jdo/tck/pc/mylib/PCRectString.java
rename to tck/src/main/java/org/apache/jdo/tck/pc/converter/PCRect.java
index 958a9e6..9b39823 100644
--- a/tck/src/main/java/org/apache/jdo/tck/pc/mylib/PCRectString.java
+++ b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCRect.java
@@ -14,7 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jdo.tck.pc.mylib;
+package org.apache.jdo.tck.pc.converter;
+
+import org.apache.jdo.tck.pc.mylib.Point;
 
 import java.util.Date;
 
@@ -22,7 +24,7 @@
  * PersistenceCapable class to test JDO AttributeConverter interface.
  * Its fields of type Point are converted to strings in the datastore.
  */
-public class PCRectString implements IPCRect {
+public class PCRect implements IPCRect {
     private static long counter = new Date().getTime();
 
     private static synchronized long newId() {
@@ -33,7 +35,14 @@
     private Point upperLeft;
     private Point lowerRight;
 
-    public PCRectString() {}
+    public PCRect() {}
+
+    public long getId() {
+        return id;
+    }
+    public void setId(long id) {
+        this.id = id;
+    }
 
     public Point getUpperLeft() {
         return upperLeft;
@@ -48,12 +57,6 @@
     public void setLowerRight(Point lowerRight) {
         this.lowerRight = lowerRight;
     }
-    public long getId() {
-        return id;
-    }
-    public void setId(long id) {
-        this.id = id;
-    }
 
     public String toString() {
         String rc = null;
@@ -63,7 +66,7 @@
                     + " ul: " + getUpperLeft().name()
                     + " lr: " + getLowerRight().name();
         } catch (NullPointerException ex) {
-            rc = "NPE getting PCRectString's values";
+            rc = "NPE getting PCRect's values";
         }
         return rc;
     }
diff --git a/tck/src/main/java/org/apache/jdo/tck/pc/mylib/PCRectStringAnnotated.java b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCRectAnnotated.java
similarity index 88%
rename from tck/src/main/java/org/apache/jdo/tck/pc/mylib/PCRectStringAnnotated.java
rename to tck/src/main/java/org/apache/jdo/tck/pc/converter/PCRectAnnotated.java
index ec627b0..f62f174 100644
--- a/tck/src/main/java/org/apache/jdo/tck/pc/mylib/PCRectStringAnnotated.java
+++ b/tck/src/main/java/org/apache/jdo/tck/pc/converter/PCRectAnnotated.java
@@ -14,22 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jdo.tck.pc.mylib;
+package org.apache.jdo.tck.pc.converter;
 
+import org.apache.jdo.tck.pc.mylib.Point;
 import org.apache.jdo.tck.util.PointToStringConverter;
 
 import javax.jdo.annotations.Column;
 import javax.jdo.annotations.Convert;
 import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
 import java.util.Date;
 
 /**
  * PersistenceCapable class to test JDO AttributeConverter interface.
  * Its fields of type Point are converted to strings in the datastore.
  */
-@PersistenceCapable(table="PCRectStringAnnotated")
-public class PCRectStringAnnotated implements IPCRect {
+@PersistenceCapable(table="PCRectConv")
+public class PCRectAnnotated implements IPCRect {
     private static long counter = new Date().getTime();
 
     private static synchronized long newId() {
@@ -47,7 +47,14 @@
     @Convert(value = PointToStringConverter.class)
     private Point lowerRight;
 
-    public PCRectStringAnnotated() {}
+    public PCRectAnnotated() {}
+
+    public long getId() {
+        return id;
+    }
+    public void setId(long id) {
+        this.id = id;
+    }
 
     public Point getUpperLeft() {
         return upperLeft;
@@ -62,12 +69,6 @@
     public void setLowerRight(Point lowerRight) {
         this.lowerRight = lowerRight;
     }
-    public long getId() {
-        return id;
-    }
-    public void setId(long id) {
-        this.id = id;
-    }
 
     public String toString() {
         String rc = null;
@@ -77,7 +78,7 @@
                     + " ul: " + getUpperLeft().name()
                     + " lr: " + getLowerRight().name();
         } catch (NullPointerException ex) {
-            rc = "NPE getting PCRectString's values";
+            rc = "NPE getting PCRectAnnotated's values";
         }
         return rc;
     }
diff --git a/tck/src/main/java/org/apache/jdo/tck/util/IntegerToStringConverter.java b/tck/src/main/java/org/apache/jdo/tck/util/IntegerToStringConverter.java
new file mode 100644
index 0000000..2e769fa
--- /dev/null
+++ b/tck/src/main/java/org/apache/jdo/tck/util/IntegerToStringConverter.java
@@ -0,0 +1,81 @@
+/*
+ * 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.jdo.tck.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.jdo.AttributeConverter;
+
+/**
+ * AttributeConverter implementation mapping a Integer instance to a string.
+ */
+public class IntegerToStringConverter implements AttributeConverter<Integer, String> {
+
+    private static int nrOfConvertToDatastoreCalls = 0;
+    private static int nrOfConvertToAttributeCalls = 0;
+
+    private final Log logger = LogFactory.getFactory().getInstance("org.apache.jdo.tck");
+
+    /**
+     * Converts the given Integer attribute value to its string representation in the datastore.
+     * @param attributeValue the attribute value of type Integer to be converted
+     * @return the string representation of the Integer instance
+     */
+    @Override
+    public String convertToDatastore(Integer attributeValue) {
+        nrOfConvertToDatastoreCalls++;
+        String datastoreValue = attributeValue != null ? attributeValue.toString() : null;
+        if (logger.isDebugEnabled()) {
+            logger.debug("IntegerToStringConverter.convertToDatastore " +
+                    "attributeValue=" + attributeValue + " datastoreValue=" + datastoreValue);
+        }
+        return datastoreValue;
+    }
+
+    /**
+     * Converts the given string datastore value to its representation as a persistent attribute of type Integer.
+     * @param datastoreValue the string value in the datastore
+     * @return the attribute value as Integer instance
+     */
+    @Override
+    public Integer convertToAttribute(String datastoreValue) {
+        nrOfConvertToAttributeCalls++;
+        Integer attributeValue = datastoreValue != null ? Integer.valueOf(datastoreValue): null;
+        if (logger.isDebugEnabled()) {
+            logger.debug("IntegerToStringConverter.convertToAttribute " +
+                    "datastoreValue=" + datastoreValue + " attributeValue=" + attributeValue);
+        }
+        return attributeValue;
+    }
+
+    /**
+     * Method returning the current number of convertToDatastore method calls.
+     * @return number of convertToDatastore method calls
+     */
+    public static int getNrOfConvertToDatastoreCalls() {
+        return nrOfConvertToDatastoreCalls;
+    }
+
+    /**
+     * Method returning the current number of convertToAttribute method calls.
+     * @return number of convertToAttribute method calls
+     */
+    public static int getNrOfConvertToAttributeCalls() {
+        return nrOfConvertToAttributeCalls;
+    }
+}
diff --git a/tck/src/main/java/org/apache/jdo/tck/util/PointToStringConverter.java b/tck/src/main/java/org/apache/jdo/tck/util/PointToStringConverter.java
index eeda26f..300b937 100644
--- a/tck/src/main/java/org/apache/jdo/tck/util/PointToStringConverter.java
+++ b/tck/src/main/java/org/apache/jdo/tck/util/PointToStringConverter.java
@@ -33,7 +33,7 @@
     // Character to separate x and y value of the Point instance.
     private static final String SEPARATOR = ":";
 
-    private Log logger = LogFactory.getFactory().getInstance("org.apache.jdo.tck");
+    private final Log logger = LogFactory.getFactory().getInstance("org.apache.jdo.tck");
 
     /**
      * Converts the given Point attribute value to its string representation in the datastore.
@@ -45,11 +45,9 @@
         nrOfConvertToDatastoreCalls++;
         String datastoreValue = null;
         if (attributeValue != null) {
-            StringBuilder builder = new StringBuilder();
-            builder.append(attributeValue.getX());
-            builder.append(SEPARATOR);
-            builder.append(attributeValue.getY() == null ? Integer.valueOf(0) : attributeValue.getY());
-            datastoreValue = builder.toString();
+            datastoreValue = attributeValue.getX() +
+                    SEPARATOR +
+                    (attributeValue.getY() == null ? Integer.valueOf(0) : attributeValue.getY());
         }
         if (logger.isDebugEnabled()) {
             logger.debug("PointToStringConverter.convertToDatastore " +
diff --git a/tck/src/main/resources/conf/converter.conf b/tck/src/main/resources/conf/converter.conf
index 921a371..a9901ce 100644
--- a/tck/src/main/resources/conf/converter.conf
+++ b/tck/src/main/resources/conf/converter.conf
@@ -20,4 +20,6 @@
 jdo.tck.mapping = 0
 jdo.tck.requiredOptions =
 jdo.tck.classes = \
-org.apache.jdo.tck.api.converter.AttributeConverterTest
+org.apache.jdo.tck.api.converter.PointAttributeConverterTest \
+org.apache.jdo.tck.api.converter.IntAttributeConverterTest
+
diff --git a/tck/src/main/resources/jdo/applicationidentity/org/apache/jdo/tck/pc/converter/package.jdo b/tck/src/main/resources/jdo/applicationidentity/org/apache/jdo/tck/pc/converter/package.jdo
new file mode 100644
index 0000000..304a5f4
--- /dev/null
+++ b/tck/src/main/resources/jdo/applicationidentity/org/apache/jdo/tck/pc/converter/package.jdo
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<jdo xmlns="http://java.sun.com/xml/ns/jdo/jdo"
+     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/jdo 
+	http://java.sun.com/xml/ns/jdo/jdo_3_0.xsd">
+  <package name="org.apache.jdo.tck.pc.converter">
+
+    <class name="PCRect"
+           identity-type="application" objectid-class="javax.jdo.identity.LongIdentity">
+      <field name="id" primary-key="true"/>
+      <field name="upperLeft" converter="org.apache.jdo.tck.util.PointToStringConverter"/>
+      <field name="lowerRight" converter="org.apache.jdo.tck.util.PointToStringConverter"/>
+    </class>
+
+    <class name="PCRectAnnotated"
+           identity-type="application" objectid-class="javax.jdo.identity.LongIdentity">
+      <field name="id" primary-key="true"/>
+    </class>
+
+    <class name="PCPoint"
+           identity-type="application" objectid-class="javax.jdo.identity.LongIdentity">
+      <field name="id" primary-key="true"/>
+      <field name="x" converter="org.apache.jdo.tck.util.IntegerToStringConverter"/>
+      <field name="y" converter="org.apache.jdo.tck.util.IntegerToStringConverter"/>
+    </class>
+
+    <class name="PCPointAnnotated"
+           identity-type="application" objectid-class="javax.jdo.identity.LongIdentity">
+      <field name="id" primary-key="true"/>
+    </class>
+
+    <class name="PCPointProp"
+           identity-type="application" objectid-class="javax.jdo.identity.LongIdentity">
+      <property name="id" primary-key="true"/>
+      <property name="x" converter="org.apache.jdo.tck.util.IntegerToStringConverter"/>
+      <property name="y" converter="org.apache.jdo.tck.util.IntegerToStringConverter"/>
+    </class>
+
+    <class name="PCPointPropAnnotated"
+           identity-type="application" objectid-class="javax.jdo.identity.LongIdentity">
+      <property name="id" primary-key="true"/>
+    </class>
+
+  </package>
+</jdo>
+
diff --git a/tck/src/main/resources/jdo/applicationidentity/org/apache/jdo/tck/pc/mylib/package.jdo b/tck/src/main/resources/jdo/applicationidentity/org/apache/jdo/tck/pc/mylib/package.jdo
index 2330581..0a4e695 100644
--- a/tck/src/main/resources/jdo/applicationidentity/org/apache/jdo/tck/pc/mylib/package.jdo
+++ b/tck/src/main/resources/jdo/applicationidentity/org/apache/jdo/tck/pc/mylib/package.jdo
@@ -52,18 +52,6 @@
       </fetch-group>
     </class>
 
-    <class name="PCRectString"
-           identity-type="application" objectid-class="javax.jdo.identity.LongIdentity">
-      <field name="id" primary-key="true"/>
-      <field name="upperLeft" converter="org.apache.jdo.tck.util.PointToStringConverter"/>
-      <field name="lowerRight" converter="org.apache.jdo.tck.util.PointToStringConverter"/>
-    </class>
-
-    <class name="PCRectStringAnnotated"
-           identity-type="application" objectid-class="javax.jdo.identity.LongIdentity">
-      <field name="id" primary-key="true"/>
-    </class>
-
     <class name="PrimitiveTypes" 
            identity-type="application" objectid-class="org.apache.jdo.tck.pc.mylib.PrimitiveTypes$Oid">
       <field name="id" primary-key="true"/>
diff --git a/tck/src/main/resources/jdo/datastoreidentity/org/apache/jdo/tck/pc/converter/package.jdo b/tck/src/main/resources/jdo/datastoreidentity/org/apache/jdo/tck/pc/converter/package.jdo
new file mode 100644
index 0000000..05a173c
--- /dev/null
+++ b/tck/src/main/resources/jdo/datastoreidentity/org/apache/jdo/tck/pc/converter/package.jdo
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<jdo xmlns="http://java.sun.com/xml/ns/jdo/jdo"
+     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/jdo 
+	http://java.sun.com/xml/ns/jdo/jdo_3_0.xsd">
+  <package name="org.apache.jdo.tck.pc.converter">
+
+    <class name="PCRect" identity-type="datastore">
+      <field name="upperLeft" converter="org.apache.jdo.tck.util.PointToStringConverter"/>
+      <field name="lowerRight" converter="org.apache.jdo.tck.util.PointToStringConverter"/>
+    </class>
+
+    <class name="PCRectAnnotated" identity-type="datastore"/>
+
+    <class name="PCPoint" identity-type="datastore">
+      <field name="x" converter="org.apache.jdo.tck.util.IntegerToStringConverter"/>
+      <field name="y" converter="org.apache.jdo.tck.util.IntegerToStringConverter"/>
+    </class>
+
+    <class name="PCPointAnnotated" identity-type="datastore"/>
+
+    <class name="PCPointProp" identity-type="datastore">
+      <property name="x" converter="org.apache.jdo.tck.util.IntegerToStringConverter"/>
+      <property name="y" converter="org.apache.jdo.tck.util.IntegerToStringConverter"/>
+    </class>
+
+    <class name="PCPointPropAnnotated" identity-type="datastore"/>
+
+  </package>
+</jdo>
+
diff --git a/tck/src/main/resources/jdo/datastoreidentity/org/apache/jdo/tck/pc/mylib/package.jdo b/tck/src/main/resources/jdo/datastoreidentity/org/apache/jdo/tck/pc/mylib/package.jdo
index f5da7db..99e376f 100644
--- a/tck/src/main/resources/jdo/datastoreidentity/org/apache/jdo/tck/pc/mylib/package.jdo
+++ b/tck/src/main/resources/jdo/datastoreidentity/org/apache/jdo/tck/pc/mylib/package.jdo
@@ -43,13 +43,6 @@
       </fetch-group>
     </class>
 
-    <class name="PCRectStringAnnotated" identity-type="datastore"/>
-
-    <class name="PCRectString" identity-type="datastore">
-      <field name="upperLeft" converter="org.apache.jdo.tck.util.PointToStringConverter"/>
-      <field name="lowerRight" converter="org.apache.jdo.tck.util.PointToStringConverter"/>
-    </class>
-
     <class name="PrimitiveTypes" identity-type="datastore"/>
 
   </package>
diff --git a/tck/src/main/resources/orm/applicationidentity/org/apache/jdo/tck/pc/converter/package-standard.orm b/tck/src/main/resources/orm/applicationidentity/org/apache/jdo/tck/pc/converter/package-standard.orm
new file mode 100644
index 0000000..b134ba0
--- /dev/null
+++ b/tck/src/main/resources/orm/applicationidentity/org/apache/jdo/tck/pc/converter/package-standard.orm
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<orm xmlns="http://java.sun.com/xml/ns/jdo/orm"
+     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/orm 
+	http://java.sun.com/xml/ns/jdo/orm_2_1.xsd">
+  <package name="org.apache.jdo.tck.pc.converter">
+
+    <class name="PCRect" table="PCRectConv">
+      <field name="id" column="ID"/>
+      <field name="lowerRight" column="LOWER_RIGHT"/>
+      <field name="upperLeft" column="UPPER_LEFT"/>
+    </class>
+
+    <class name="PCPoint" table="PCPointConv">
+      <field name="id" column="ID"/>
+      <field name="x" column="X"/>
+      <field name="y" column="Y"/>
+    </class>
+
+    <class name="PCPointProp" table="PCPointConv">
+      <property name="id" column="ID"/>
+      <property name="x" column="X"/>
+      <property name="y" column="Y"/>
+    </class>
+
+  </package>
+</orm>
+
diff --git a/tck/src/main/resources/orm/applicationidentity/org/apache/jdo/tck/pc/mylib/package-standard.orm b/tck/src/main/resources/orm/applicationidentity/org/apache/jdo/tck/pc/mylib/package-standard.orm
index 0a7b45c..053bbc7 100644
--- a/tck/src/main/resources/orm/applicationidentity/org/apache/jdo/tck/pc/mylib/package-standard.orm
+++ b/tck/src/main/resources/orm/applicationidentity/org/apache/jdo/tck/pc/mylib/package-standard.orm
@@ -49,12 +49,6 @@
       </field>
     </class>
 
-    <class name="PCRectString" table="PCRectString">
-      <field name="id" column="ID"/>
-      <field name="lowerRight" column="LOWER_RIGHT"/>
-      <field name="upperLeft" column="UPPER_LEFT"/>
-    </class>
-
     <class name="PrimitiveTypes" table="PrimitiveTypes">
       <field name="id" column="ID"/>
       <field name="booleanNotNull" column="booleanNotNull"/>
diff --git a/tck/src/main/resources/orm/datastoreidentity/org/apache/jdo/tck/pc/converter/package-standard.orm b/tck/src/main/resources/orm/datastoreidentity/org/apache/jdo/tck/pc/converter/package-standard.orm
new file mode 100644
index 0000000..18b43f6
--- /dev/null
+++ b/tck/src/main/resources/orm/datastoreidentity/org/apache/jdo/tck/pc/converter/package-standard.orm
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<orm xmlns="http://java.sun.com/xml/ns/jdo/orm"
+     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/orm 
+	http://java.sun.com/xml/ns/jdo/orm_2_1.xsd">
+  <package name="org.apache.jdo.tck.pc.converter">
+
+    <class name="PCRect" table="PCRectConv">
+      <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
+      <field name="id" column="ID"/>
+      <field name="lowerRight" column="LOWER_RIGHT"/>
+      <field name="upperLeft" column="UPPER_LEFT"/>
+    </class>
+
+    <class name="PCRectAnnotated">
+      <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
+    </class>
+
+    <class name="PCPoint" table="PCPointConv">
+      <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
+      <field name="id" column="ID"/>
+      <field name="x" column="X"/>
+      <field name="y" column="Y"/>
+    </class>
+
+    <class name="PCPointAnnotated">
+      <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
+    </class>
+
+    <class name="PCPointProp" table="PCPointConv">
+      <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
+      <property name="id" column="ID"/>
+      <property name="x" column="X"/>
+      <property name="y" column="Y"/>
+    </class>
+
+    <class name="PCPointPropAnnotated">
+      <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
+    </class>
+
+  </package>
+</orm>
+
diff --git a/tck/src/main/resources/orm/datastoreidentity/org/apache/jdo/tck/pc/mylib/package-standard.orm b/tck/src/main/resources/orm/datastoreidentity/org/apache/jdo/tck/pc/mylib/package-standard.orm
index e7f1ac9..3ca561e 100644
--- a/tck/src/main/resources/orm/datastoreidentity/org/apache/jdo/tck/pc/mylib/package-standard.orm
+++ b/tck/src/main/resources/orm/datastoreidentity/org/apache/jdo/tck/pc/mylib/package-standard.orm
@@ -53,17 +53,6 @@
       </field>
     </class>
 
-    <class name="PCRectString" table="PCRectString">
-      <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
-      <field name="id" column="ID"/>
-      <field name="lowerRight" column="LOWER_RIGHT"/>
-      <field name="upperLeft" column="UPPER_LEFT"/>
-    </class>
-
-    <class name="PCRectStringAnnotated">
-      <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
-    </class>
-
     <class name="PrimitiveTypes" table="PrimitiveTypes">
       <datastore-identity strategy="identity" column="DATASTORE_IDENTITY"/>
       <field name="id" column="ID"/>
diff --git a/tck/src/main/resources/sql/derby/applicationidentity/schema.sql b/tck/src/main/resources/sql/derby/applicationidentity/schema.sql
index 4596103..52b08fc 100644
--- a/tck/src/main/resources/sql/derby/applicationidentity/schema.sql
+++ b/tck/src/main/resources/sql/derby/applicationidentity/schema.sql
@@ -61,8 +61,6 @@
 -------------------------
 
 DROP TABLE PCRect;
-DROP TABLE PCRectString;
-DROP TABLE PCRectStringAnnotated;
 DROP TABLE PCPoint;
 DROP TABLE VersionedPCPoint;
 DROP TABLE PCPoint2;
@@ -98,20 +96,6 @@
     CONSTRAINT PCRCT_CONST PRIMARY KEY (ID)
 );
 
-CREATE TABLE PCRectString (
-    ID BIGINT NOT NULL,
-    UPPER_LEFT VARCHAR(30),
-    LOWER_RIGHT VARCHAR(30),
-    CONSTRAINT PCRCTSTR_CONST PRIMARY KEY (ID)
-);
-
-CREATE TABLE PCRectStringAnnotated (
-    ID BIGINT NOT NULL,
-    UPPER_LEFT VARCHAR(30),
-    LOWER_RIGHT VARCHAR(30),
-    CONSTRAINT PCRCTANN_CONST PRIMARY KEY (ID)
-);
-
 CREATE TABLE PrimitiveTypes (
     ID BIGINT NOT NULL,
     booleanNotNull CHAR(1) NOT NULL CHECK (booleanNotNull IN ('Y','N')),
@@ -146,6 +130,27 @@
 );
 
 -------------------------
+-- converter
+-------------------------
+
+DROP TABLE PCPointConv;
+DROP TABLE PCRectConv;
+
+CREATE TABLE PCRectConv (
+    ID BIGINT NOT NULL,
+    UPPER_LEFT VARCHAR(30),
+    LOWER_RIGHT VARCHAR(30),
+    CONSTRAINT PCRCTCNV_CONST PRIMARY KEY (ID)
+);
+
+CREATE TABLE PCPointConv (
+    ID BIGINT NOT NULL,
+    X VARCHAR(30),
+    Y VARCHAR(30),
+    CONSTRAINT PCPNTCNV_CONST PRIMARY KEY (ID)
+);
+
+-------------------------
 -- query
 -------------------------
 
diff --git a/tck/src/main/resources/sql/derby/datastoreidentity/schema.sql b/tck/src/main/resources/sql/derby/datastoreidentity/schema.sql
index 7fc3f17..9fe42c6 100644
--- a/tck/src/main/resources/sql/derby/datastoreidentity/schema.sql
+++ b/tck/src/main/resources/sql/derby/datastoreidentity/schema.sql
@@ -41,8 +41,6 @@
 -------------------------
 
 DROP TABLE PCRect;
-DROP TABLE PCRectString;
-DROP TABLE PCRectStringAnnotated;
 DROP TABLE PCPoint;
 DROP TABLE VersionedPCPoint;
 DROP TABLE PCPoint2;
@@ -82,22 +80,6 @@
     CONSTRAINT PCRCT_CONST PRIMARY KEY (DATASTORE_IDENTITY)
 );
 
-CREATE TABLE PCRectString (
-    DATASTORE_IDENTITY BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
-    ID BIGINT,
-    UPPER_LEFT VARCHAR(30),
-    LOWER_RIGHT VARCHAR(30),
-    CONSTRAINT PCRCTSTR_CONST PRIMARY KEY (DATASTORE_IDENTITY)
-);
-
-CREATE TABLE PCRectStringAnnotated (
-    DATASTORE_IDENTITY BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
-    ID BIGINT,
-    UPPER_LEFT VARCHAR(30),
-    LOWER_RIGHT VARCHAR(30),
-    CONSTRAINT PCRCTANN_CONST PRIMARY KEY (DATASTORE_IDENTITY)
-);
-
 CREATE TABLE PrimitiveTypes (
     DATASTORE_IDENTITY BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
     ID BIGINT,
@@ -134,6 +116,29 @@
 );
 
 -------------------------
+-- converter
+-------------------------
+
+DROP TABLE PCPointConv;
+DROP TABLE PCRectConv;
+
+CREATE TABLE PCRectConv (
+    DATASTORE_IDENTITY BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
+    ID BIGINT,
+    UPPER_LEFT VARCHAR(30),
+    LOWER_RIGHT VARCHAR(30),
+    CONSTRAINT PCRCTCNV_CONST PRIMARY KEY (DATASTORE_IDENTITY)
+);
+
+CREATE TABLE PCPointConv (
+    DATASTORE_IDENTITY BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY,
+    ID BIGINT,
+    X VARCHAR(30),
+    Y VARCHAR(30),
+    CONSTRAINT PCPNTCNV_CONST PRIMARY KEY (DATASTORE_IDENTITY)
+);
+
+-------------------------
 -- query
 -------------------------