This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/master by this push:
new 3ac712d0f CAY-2898 Crypto: NPE in a ColumnQuery
3ac712d0f is described below
commit 3ac712d0fb8f2e857c3d9a7e6aaeafc8dda163b0
Author: Nikita Timofeev <[email protected]>
AuthorDate: Thu Oct 2 18:54:45 2025 +0400
CAY-2898 Crypto: NPE in a ColumnQuery
---
RELEASE-NOTES.txt | 1 +
.../reader/CryptoRowReaderFactoryDecorator.java | 2 +-
.../cayenne/crypto/Runtime_AES128_GZIP_IT.java | 68 ++++++++++++++++++++++
.../apache/cayenne/crypto/Runtime_AES128_IT.java | 17 ++++++
4 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index be179ec6b..1c6a8a33a 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -29,6 +29,7 @@ CAY-2879 Negative number for non parameterized ObjectSelect
query not processed
CAY-2883 License and notice templates are not processed by the Gradle build
CAY-2885 Modeler: DbImport fails to load DB schema view
CAY-2896 Inserting two identical objects into two datamaps stores both objects
in the last used datamap
+CAY-2898 Crypto: NPE in a ColumnQuery
----------------------------------
Release: 5.0-M1
diff --git
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
index bb818a8b6..35d8aa9d4 100644
---
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
+++
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java
@@ -159,7 +159,7 @@ public class CryptoRowReaderFactoryDecorator extends
DefaultRowReaderFactory {
@Override
public Object readRow(ResultSet resultSet) {
Object value = delegateReader.readRow(resultSet);
- if(valueDecryptor == null) {
+ if(valueDecryptor == null || value == null) {
return value;
}
return valueDecryptor.decrypt(bytesDecryptor, value);
diff --git
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_GZIP_IT.java
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_GZIP_IT.java
index 85ea2204f..a4803358d 100644
---
a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_GZIP_IT.java
+++
b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/Runtime_AES128_GZIP_IT.java
@@ -190,4 +190,72 @@ public class Runtime_AES128_GZIP_IT extends
Runtime_AES128_Base {
assertEquals(str+"A", result.get(0).getCryptoString());
}
+ @Test
+ public void test_ScalarColumnQuery() throws SQLException {
+ // make sure compression is on...
+ byte[] cryptoBytes1 = CryptoUnitUtils.bytesOfSize(GZIP_THRESHOLD +
101);
+ byte[] cryptoBytes2 = CryptoUnitUtils.bytesOfSize(GZIP_THRESHOLD +
102);
+
+ ObjectContext context = runtime.newContext();
+
+ Table2 t1 = context.newObject(Table2.class);
+ t1.setPlainBytes("a".getBytes());
+ t1.setCryptoBytes(cryptoBytes1);
+
+ Table2 t2 = context.newObject(Table2.class);
+ t2.setPlainBytes("b".getBytes());
+ t2.setCryptoBytes(cryptoBytes2);
+
+ Table2 t3 = context.newObject(Table2.class);
+ t3.setPlainBytes("c".getBytes());
+ t3.setCryptoBytes(null);
+
+ context.commitChanges();
+
+ List<byte[]> result = ObjectSelect.query(Table2.class)
+ .column(Table2.CRYPTO_BYTES)
+ .orderBy(Table2.PLAIN_BYTES.asc())
+ .select(runtime.newContext());
+
+ assertEquals(3, result.size());
+ assertArrayEquals(cryptoBytes1, result.get(0));
+ assertArrayEquals(cryptoBytes2, result.get(1));
+ assertArrayEquals(null, result.get(2));
+ }
+
+ @Test
+ public void test_MultipleColumnsQuery() throws SQLException {
+ // make sure compression is on...
+ byte[] cryptoBytes1 = CryptoUnitUtils.bytesOfSize(GZIP_THRESHOLD +
101);
+ byte[] cryptoBytes2 = CryptoUnitUtils.bytesOfSize(GZIP_THRESHOLD +
102);
+
+ ObjectContext context = runtime.newContext();
+
+ Table2 t1 = context.newObject(Table2.class);
+ t1.setPlainBytes("a".getBytes());
+ t1.setCryptoBytes(cryptoBytes1);
+
+ Table2 t2 = context.newObject(Table2.class);
+ t2.setPlainBytes("b".getBytes());
+ t2.setCryptoBytes(cryptoBytes2);
+
+ Table2 t3 = context.newObject(Table2.class);
+ t3.setPlainBytes("c".getBytes());
+ t3.setCryptoBytes(null);
+
+ context.commitChanges();
+
+ List<Object[]> result = ObjectSelect.query(Table2.class)
+ .columns(Table2.CRYPTO_BYTES, Table2.PLAIN_BYTES)
+ .orderBy(Table2.PLAIN_BYTES.asc())
+ .select(runtime.newContext());
+
+ assertEquals(3, result.size());
+ assertArrayEquals(cryptoBytes1, (byte[])result.get(0)[0]);
+ assertArrayEquals("a".getBytes(), (byte[])result.get(0)[1]);
+ assertArrayEquals(cryptoBytes2, (byte[])result.get(1)[0]);
+ assertArrayEquals("b".getBytes(), (byte[])result.get(1)[1]);
+ assertArrayEquals(null, (byte[])result.get(2)[0]);
+ }
+
}
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 ead0ca076..336d9a7a0 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
@@ -333,6 +333,23 @@ public class Runtime_AES128_IT extends Runtime_AES128_Base
{
assertEquals("test", result.get(0));
}
+ @Test
+ public void test_ColumnQuerySingleScalarNull() {
+ ObjectContext context = runtime.newContext();
+
+ Table1 t1 = context.newObject(Table1.class);
+ t1.setCryptoInt(1);
+ t1.setCryptoString(null);
+ context.commitChanges();
+
+ List<String> result = ObjectSelect
+ .columnQuery(Table1.class, Table1.CRYPTO_STRING)
+ .select(context);
+
+ assertEquals(1, result.size());
+ assertNull(result.get(0));
+ }
+
@Test
public void test_ColumnQueryMultipleScalars() {
ObjectContext context = runtime.newContext();