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

abulatski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit acdfa178dc75e52be39540b2269ba41e2ec03f75
Author: Arseni Bulatski <ancars...@gmail.com>
AuthorDate: Fri Jun 21 11:28:14 2019 +0300

    CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
---
 RELEASE-NOTES.txt                                  |   1 +
 .../crypto/transformer/DefaultMapTransformer.java  |   6 ++
 .../apache/cayenne/crypto/Runtime_AES128_IT.java   | 105 +++++++++++++++++++--
 .../java/org/apache/cayenne/crypto/db/Table7.java  |   9 ++
 .../org/apache/cayenne/crypto/db/auto/_Table1.java |  25 +++++
 .../crypto/db/auto/{_Table1.java => _Table7.java}  |  54 ++++-------
 .../src/test/resources/cayenne-crypto.xml          |   2 +
 cayenne-crypto/src/test/resources/datamap.map.xml  |  20 +++-
 .../cayenne/access/jdbc/ColumnDescriptor.java      |   7 --
 9 files changed, 177 insertions(+), 52 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 1fa3317..337e6e0 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -60,6 +60,7 @@ CAY-2577 Between property with extended type failure
 CAY-2578 Wrong bindings in select of related entity by compound FK
 CAY-2580 Cgen: Can't use custom templates for client mode
 CAY-2582 Double insert of manyToMany relationship mapped to Set
+CAY-2584 Crypto: can't use ColumnSelect with encrypted columns
 
 ----------------------------------
 Release: 4.1.B1
diff --git 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
index 5c778b0..622d8d7 100644
--- 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
+++ 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultMapTransformer.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.crypto.transformer;
 
+import java.util.Arrays;
 import java.util.Map;
 
 import org.apache.cayenne.crypto.transformer.bytes.BytesDecryptor;
@@ -41,6 +42,7 @@ public class DefaultMapTransformer implements MapTransformer {
     @Override
     public void transform(Map<String, Object> map) {
 
+        mapKeys = mergeSameKeys(mapKeys);
         int len = mapKeys.length;
 
         for (int i = 0; i < len; i++) {
@@ -52,4 +54,8 @@ public class DefaultMapTransformer implements MapTransformer {
             }
         }
     }
+
+    private String[] mergeSameKeys(String[] keys) {
+        return Arrays.stream(keys).distinct().toArray(String[]::new);
+    }
 }
diff --git 
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java 
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
index 338e9d8..6dddecd 100644
--- 
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
+++ 
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_IT.java
@@ -18,25 +18,28 @@
  ****************************************************************/
 package org.apache.cayenne.crypto;
 
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.crypto.db.Table1;
 import org.apache.cayenne.crypto.db.Table2;
+import org.apache.cayenne.crypto.db.Table7;
 import org.apache.cayenne.crypto.transformer.value.IntegerConverter;
 import org.apache.cayenne.crypto.unit.CryptoUnitUtils;
 import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SelectQuery;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.sql.SQLException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 public class Runtime_AES128_IT extends Runtime_AES128_Base {
 
@@ -207,10 +210,11 @@ public class Runtime_AES128_IT extends 
Runtime_AES128_Base {
         t1.setCryptoInt(1);
         t1.setPlainInt(2);
         t1.setCryptoString("test");
+        t1.setPlainString("Test");
         context.commitChanges();
 
         List<Object[]> result = ObjectSelect
-                .columnQuery(Table1.class, Property.createSelf(Table1.class), 
Table1.CRYPTO_INT)
+                .columnQuery(Table1.class, 
PropertyFactory.createSelf(Table1.class), Table1.CRYPTO_INT)
                 .select(context);
 
         assertEquals(1, result.size());
@@ -220,6 +224,95 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base 
{
     }
 
     @Test
+    public void testColumnQueryWithRelationshipWithTheSameNames() {
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setPlainInt(3);
+        t1.setCryptoString("test");
+        t1.setPlainString("Test");
+
+        Table7 t7 = context.newObject(Table7.class);
+        t7.setCryptoInt(2);
+        t7.setCryptoString("string");
+
+        t1.addToTable7s(t7);
+
+        context.commitChanges();
+
+        List<Object[]> result = ObjectSelect
+                .columnQuery(Table1.class,
+                        PropertyFactory.createSelf(Table1.class),
+                        Table1.CRYPTO_INT,
+                        Table1.TABLE7S.dot(Table7.CRYPTO_INT),
+                        Table1.TABLE7S.dot(Table7.CRYPTO_STRING))
+                .select(context);
+        assertEquals(1, result.size());
+        assertEquals(1, ((Table1)result.get(0)[0]).getCryptoInt());
+        assertEquals("test", ((Table1)result.get(0)[0]).getCryptoString());
+        assertEquals(1, result.get(0)[1]);
+        assertEquals(2, result.get(0)[2]);
+        assertEquals("string", result.get(0)[3]);
+    }
+
+    @Test
+    public void testSelectWith2Objects() {
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setPlainInt(3);
+        t1.setCryptoString("test");
+        t1.setPlainString("Test");
+
+        Table7 t7 = context.newObject(Table7.class);
+        t7.setCryptoInt(2);
+        t7.setCryptoString("string");
+
+        t1.addToTable7s(t7);
+
+        context.commitChanges();
+
+        List<Object[]> result = ObjectSelect
+                .columnQuery(Table1.class,
+                        PropertyFactory.createSelf(Table1.class),
+                        Table1.TABLE7S.flat())
+                .select(context);
+        assertEquals(1, result.size());
+        assertEquals("test", ((Table1)result.get(0)[0]).getCryptoString());
+        assertTrue(result.get(0)[1] instanceof Table7);
+        assertEquals(2, ((Table7)result.get(0)[1]).getCryptoInt());
+    }
+
+    @Test
+    public void testObjectSelectWithPrefetch() {
+        ObjectContext context = runtime.newContext();
+
+        Table1 t1 = context.newObject(Table1.class);
+        t1.setCryptoInt(1);
+        t1.setPlainInt(3);
+        t1.setCryptoString("test");
+        t1.setPlainString("Test");
+
+        Table7 t7 = context.newObject(Table7.class);
+        t7.setCryptoInt(2);
+        t7.setCryptoString("string");
+
+        t1.addToTable7s(t7);
+
+        context.commitChanges();
+
+        List<Table1> table1s = ObjectSelect.query(Table1.class)
+                .prefetch(Table1.TABLE7S.disjoint())
+                .select(context);
+
+        assertEquals(1, table1s.size());
+        assertEquals("test", table1s.get(0).getCryptoString());
+        assertEquals("string", 
table1s.get(0).getTable7s().get(0).getCryptoString());
+    }
+
+    @Test
     public void test_ColumnQuerySingleScalar() {
         ObjectContext context = runtime.newContext();
 
diff --git 
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table7.java 
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table7.java
new file mode 100644
index 0000000..2d65080
--- /dev/null
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/Table7.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.crypto.db;
+
+import org.apache.cayenne.crypto.db.auto._Table7;
+
+public class Table7 extends _Table7 {
+
+    private static final long serialVersionUID = 1L; 
+
+}
diff --git 
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java 
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
index 0d32a17..71855de 100644
--- 
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
+++ 
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
@@ -3,8 +3,11 @@ package org.apache.cayenne.crypto.db.auto;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.util.List;
 
 import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.crypto.db.Table7;
+import org.apache.cayenne.exp.property.ListProperty;
 import org.apache.cayenne.exp.property.NumericProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.exp.property.StringProperty;
@@ -25,12 +28,14 @@ public abstract class _Table1 extends BaseDataObject {
     public static final StringProperty<String> CRYPTO_STRING = 
PropertyFactory.createString("cryptoString", String.class);
     public static final NumericProperty<Integer> PLAIN_INT = 
PropertyFactory.createNumeric("plainInt", Integer.class);
     public static final StringProperty<String> PLAIN_STRING = 
PropertyFactory.createString("plainString", String.class);
+    public static final ListProperty<Table7> TABLE7S = 
PropertyFactory.createList("table7s", Table7.class);
 
     protected Integer cryptoInt;
     protected String cryptoString;
     protected Integer plainInt;
     protected String plainString;
 
+    protected Object table7s;
 
     public void setCryptoInt(int cryptoInt) {
         beforePropertyWrite("cryptoInt", this.cryptoInt, cryptoInt);
@@ -78,6 +83,19 @@ public abstract class _Table1 extends BaseDataObject {
         return this.plainString;
     }
 
+    public void addToTable7s(Table7 obj) {
+        addToManyTarget("table7s", obj, true);
+    }
+
+    public void removeFromTable7s(Table7 obj) {
+        removeToManyTarget("table7s", obj, true);
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<Table7> getTable7s() {
+        return (List<Table7>)readProperty("table7s");
+    }
+
     @Override
     public Object readPropertyDirectly(String propName) {
         if(propName == null) {
@@ -93,6 +111,8 @@ public abstract class _Table1 extends BaseDataObject {
                 return this.plainInt;
             case "plainString":
                 return this.plainString;
+            case "table7s":
+                return this.table7s;
             default:
                 return super.readPropertyDirectly(propName);
         }
@@ -117,6 +137,9 @@ public abstract class _Table1 extends BaseDataObject {
             case "plainString":
                 this.plainString = (String)val;
                 break;
+            case "table7s":
+                this.table7s = val;
+                break;
             default:
                 super.writePropertyDirectly(propName, val);
         }
@@ -137,6 +160,7 @@ public abstract class _Table1 extends BaseDataObject {
         out.writeObject(this.cryptoString);
         out.writeObject(this.plainInt);
         out.writeObject(this.plainString);
+        out.writeObject(this.table7s);
     }
 
     @Override
@@ -146,6 +170,7 @@ public abstract class _Table1 extends BaseDataObject {
         this.cryptoString = (String)in.readObject();
         this.plainInt = (Integer)in.readObject();
         this.plainString = (String)in.readObject();
+        this.table7s = in.readObject();
     }
 
 }
diff --git 
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java 
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table7.java
similarity index 68%
copy from 
cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
copy to 
cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table7.java
index 0d32a17..3964c74 100644
--- 
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
+++ 
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table7.java
@@ -5,17 +5,19 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
 import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.crypto.db.Table1;
+import org.apache.cayenne.exp.property.EntityProperty;
 import org.apache.cayenne.exp.property.NumericProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.exp.property.StringProperty;
 
 /**
- * Class _Table1 was generated by Cayenne.
+ * Class _Table7 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 _Table1 extends BaseDataObject {
+public abstract class _Table7 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
@@ -23,14 +25,12 @@ public abstract class _Table1 extends BaseDataObject {
 
     public static final NumericProperty<Integer> CRYPTO_INT = 
PropertyFactory.createNumeric("cryptoInt", Integer.class);
     public static final StringProperty<String> CRYPTO_STRING = 
PropertyFactory.createString("cryptoString", String.class);
-    public static final NumericProperty<Integer> PLAIN_INT = 
PropertyFactory.createNumeric("plainInt", Integer.class);
-    public static final StringProperty<String> PLAIN_STRING = 
PropertyFactory.createString("plainString", String.class);
+    public static final EntityProperty<Table1> TO_TABLE1 = 
PropertyFactory.createEntity("toTable1", Table1.class);
 
     protected Integer cryptoInt;
     protected String cryptoString;
-    protected Integer plainInt;
-    protected String plainString;
 
+    protected Object toTable1;
 
     public void setCryptoInt(int cryptoInt) {
         beforePropertyWrite("cryptoInt", this.cryptoInt, cryptoInt);
@@ -55,27 +55,12 @@ public abstract class _Table1 extends BaseDataObject {
         return this.cryptoString;
     }
 
-    public void setPlainInt(int plainInt) {
-        beforePropertyWrite("plainInt", this.plainInt, plainInt);
-        this.plainInt = plainInt;
+    public void setToTable1(Table1 toTable1) {
+        setToOneTarget("toTable1", toTable1, true);
     }
 
-    public int getPlainInt() {
-        beforePropertyRead("plainInt");
-        if(this.plainInt == null) {
-            return 0;
-        }
-        return this.plainInt;
-    }
-
-    public void setPlainString(String plainString) {
-        beforePropertyWrite("plainString", this.plainString, plainString);
-        this.plainString = plainString;
-    }
-
-    public String getPlainString() {
-        beforePropertyRead("plainString");
-        return this.plainString;
+    public Table1 getToTable1() {
+        return (Table1)readProperty("toTable1");
     }
 
     @Override
@@ -89,10 +74,8 @@ public abstract class _Table1 extends BaseDataObject {
                 return this.cryptoInt;
             case "cryptoString":
                 return this.cryptoString;
-            case "plainInt":
-                return this.plainInt;
-            case "plainString":
-                return this.plainString;
+            case "toTable1":
+                return this.toTable1;
             default:
                 return super.readPropertyDirectly(propName);
         }
@@ -111,11 +94,8 @@ public abstract class _Table1 extends BaseDataObject {
             case "cryptoString":
                 this.cryptoString = (String)val;
                 break;
-            case "plainInt":
-                this.plainInt = (Integer)val;
-                break;
-            case "plainString":
-                this.plainString = (String)val;
+            case "toTable1":
+                this.toTable1 = val;
                 break;
             default:
                 super.writePropertyDirectly(propName, val);
@@ -135,8 +115,7 @@ public abstract class _Table1 extends BaseDataObject {
         super.writeState(out);
         out.writeObject(this.cryptoInt);
         out.writeObject(this.cryptoString);
-        out.writeObject(this.plainInt);
-        out.writeObject(this.plainString);
+        out.writeObject(this.toTable1);
     }
 
     @Override
@@ -144,8 +123,7 @@ public abstract class _Table1 extends BaseDataObject {
         super.readState(in);
         this.cryptoInt = (Integer)in.readObject();
         this.cryptoString = (String)in.readObject();
-        this.plainInt = (Integer)in.readObject();
-        this.plainString = (String)in.readObject();
+        this.toTable1 = in.readObject();
     }
 
 }
diff --git a/cayenne-crypto/src/test/resources/cayenne-crypto.xml 
b/cayenne-crypto/src/test/resources/cayenne-crypto.xml
index 1680c10..dea206b 100644
--- a/cayenne-crypto/src/test/resources/cayenne-crypto.xml
+++ b/cayenne-crypto/src/test/resources/cayenne-crypto.xml
@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <domain xmlns="http://cayenne.apache.org/schema/10/domain";
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+        xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain 
https://cayenne.apache.org/schema/10/domain.xsd";
         project-version="10">
        <map name="datamap"/>
        <node name="datanode"
diff --git a/cayenne-crypto/src/test/resources/datamap.map.xml 
b/cayenne-crypto/src/test/resources/datamap.map.xml
index fd572a8..6c40f2c 100644
--- a/cayenne-crypto/src/test/resources/datamap.map.xml
+++ b/cayenne-crypto/src/test/resources/datamap.map.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <data-map xmlns="http://cayenne.apache.org/schema/10/modelMap";
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-        xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap 
http://cayenne.apache.org/schema/10/modelMap.xsd";
+        xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap 
https://cayenne.apache.org/schema/10/modelMap.xsd";
         project-version="10">
        <property name="defaultPackage" value="org.apache.cayenne.crypto.db"/>
        <db-entity name="TABLE1">
@@ -32,6 +32,12 @@
                <db-attribute name="CRYPTO_INT4" type="BLOB"/>
                <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
        </db-entity>
+       <db-entity name="TABLE7">
+               <db-attribute name="CRYPTO_INT" type="BLOB"/>
+               <db-attribute name="CRYPTO_STRING" type="CLOB"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="TABLE1_ID" type="INTEGER"/>
+       </db-entity>
        <obj-entity name="Table1" 
className="org.apache.cayenne.crypto.db.Table1" dbEntityName="TABLE1">
                <obj-attribute name="cryptoInt" type="int" 
db-attribute-path="CRYPTO_INT"/>
                <obj-attribute name="cryptoString" type="java.lang.String" 
db-attribute-path="CRYPTO_STRING"/>
@@ -58,4 +64,16 @@
                <obj-attribute name="cryptoInt1" type="long" 
db-attribute-path="CRYPTO_INT1"/>
                <obj-attribute name="cryptoInt4" type="int" 
db-attribute-path="CRYPTO_INT4"/>
        </obj-entity>
+       <obj-entity name="Table7" 
className="org.apache.cayenne.crypto.db.Table7" dbEntityName="TABLE7">
+               <obj-attribute name="cryptoInt" type="int" 
db-attribute-path="CRYPTO_INT"/>
+               <obj-attribute name="cryptoString" type="java.lang.String" 
db-attribute-path="CRYPTO_STRING"/>
+       </obj-entity>
+       <db-relationship name="table7s" source="TABLE1" target="TABLE7" 
toMany="true">
+               <db-attribute-pair source="ID" target="TABLE1_ID"/>
+       </db-relationship>
+       <db-relationship name="toTable1" source="TABLE7" target="TABLE1">
+               <db-attribute-pair source="TABLE1_ID" target="ID"/>
+       </db-relationship>
+       <obj-relationship name="table7s" source="Table1" target="Table7" 
deleteRule="Deny" db-relationship-path="table7s"/>
+       <obj-relationship name="toTable1" source="Table7" target="Table1" 
deleteRule="Nullify" db-relationship-path="toTable1"/>
 </data-map>
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
index a2eeed9..ea30eb9 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ColumnDescriptor.java
@@ -149,10 +149,6 @@ public class ColumnDescriptor {
         return name;
     }
 
-    public void setAttribute(DbAttribute attribute) {
-        this.attribute = attribute;
-    }
-
     /**
      * Returns a DbAttribute for this column. Since columns descriptors can be
      * initialized in a context where a DbAttribite is unknown, this method may
@@ -164,9 +160,6 @@ public class ColumnDescriptor {
         return attribute;
     }
 
-    /**
-     * @since 4.2
-     */
     public void setAttribute(DbAttribute attribute) {
         this.attribute = attribute;
     }

Reply via email to