Skip to content

Commit 6b4838d

Browse files
committed
Refactoring row descriptors:
* ColumnDescriptor: ExtendedType type property * Getting rid of RowDescriptor ... ColumnDescriptor[] now gives us a full row * Inline RowDescriptorBuilder into ColumnDescriptor
1 parent 69d35b4 commit 6b4838d

32 files changed

Lines changed: 442 additions & 577 deletions

cayenne-crypto/src/main/java/org/apache/cayenne/crypto/reader/CryptoRowReaderFactoryDecorator.java

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.Map;
2323

2424
import org.apache.cayenne.access.jdbc.ColumnDescriptor;
25-
import org.apache.cayenne.access.jdbc.RowDescriptor;
2625
import org.apache.cayenne.access.jdbc.reader.DefaultRowReaderFactory;
2726
import org.apache.cayenne.access.jdbc.reader.RowReader;
2827
import org.apache.cayenne.access.types.ExtendedType;
@@ -60,80 +59,63 @@ public CryptoRowReaderFactoryDecorator(@Inject TransformerFactory transformerFac
6059
}
6160

6261
@Override
63-
public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata queryMetadata, DbAdapter adapter) {
64-
RowDescriptor encryptedRowDescriptor = encryptedRowDescriptor(descriptor, adapter.getExtendedTypes());
65-
return super.rowReader(encryptedRowDescriptor, queryMetadata, adapter);
62+
public RowReader<?> rowReader(ColumnDescriptor[] columns, QueryMetadata queryMetadata, DbAdapter adapter) {
63+
return super.rowReader(encryptedColumns(columns, adapter.getExtendedTypes()), queryMetadata, adapter);
6664
}
6765

6866
@Override
69-
protected RowReader<?> createScalarRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
67+
protected RowReader<?> createScalarRowReader(ColumnDescriptor[] columns, QueryMetadata queryMetadata,
7068
ScalarResultSegment segment) {
7169
RowReader<?> scalarRowReader = super
72-
.createScalarRowReader(descriptor, queryMetadata, segment);
73-
return new DecoratedScalarRowReader(descriptor.getColumns()[segment.getColumnOffset()], scalarRowReader);
70+
.createScalarRowReader(columns, queryMetadata, segment);
71+
return new DecoratedScalarRowReader(columns[segment.getColumnOffset()], scalarRowReader);
7472
}
7573

7674
@Override
77-
protected RowReader<?> createEntityRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
75+
protected RowReader<?> createEntityRowReader(ColumnDescriptor[] columns, QueryMetadata queryMetadata,
7876
EntityResultSegment resultMetadata) {
7977
RowReader<?> entityRowReader = super
80-
.createEntityRowReader(descriptor, queryMetadata, resultMetadata);
81-
return new DecoratedEntityRowReader(descriptor, entityRowReader, resultMetadata);
78+
.createEntityRowReader(columns, queryMetadata, resultMetadata);
79+
return new DecoratedEntityRowReader(columns, entityRowReader, resultMetadata);
8280
}
8381

8482
@Override
85-
protected RowReader<?> createFullRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata) {
83+
protected RowReader<?> createFullRowReader(ColumnDescriptor[] columns, QueryMetadata queryMetadata) {
8684
RowReader<?> fullRowReader = super
87-
.createFullRowReader(descriptor, queryMetadata);
88-
return new DecoratedFullRowReader(descriptor, fullRowReader);
85+
.createFullRowReader(columns, queryMetadata);
86+
return new DecoratedFullRowReader(columns, fullRowReader);
8987
}
9088

91-
protected RowDescriptor encryptedRowDescriptor(RowDescriptor descriptor, ExtendedTypeMap typeMap) {
89+
protected ColumnDescriptor[] encryptedColumns(ColumnDescriptor[] columns, ExtendedTypeMap typeMap) {
9290

93-
// need to tweak the original descriptor to ensure binary columns are read as binary, eben if the plain Java
94-
// type is not a byte[]
91+
// need to tweak the columns to ensure encrypted columns are read as binary or char, even if the plain Java
92+
// type is not a byte[] / String
9593

96-
ColumnDescriptor[] originalColumns = descriptor.getColumns();
97-
int len = originalColumns.length;
94+
ColumnDescriptor[] encrypted = new ColumnDescriptor[columns.length];
9895

99-
ExtendedType[] originalConverters = descriptor.getConverters();
100-
ExtendedType[] encryptedConverters = new ExtendedType[len];
96+
for (int i = 0; i < columns.length; i++) {
97+
ColumnDescriptor column = columns[i];
98+
DbAttribute attribute = column.attribute();
10199

102-
for (int i = 0; i < len; i++) {
103-
DbAttribute attribute = originalColumns[i].attribute();
104-
105-
ExtendedType t = originalConverters[i];
100+
ExtendedType type = column.type();
106101

107102
if (attribute != null && columnMapper.isEncrypted(attribute)) {
108103

109104
// only char or binary columns can store encrypted data
110105
if (TypesMapping.isBinary(attribute.getType())) {
111-
t = typeMap.getRegisteredType(byte[].class);
106+
type = typeMap.getRegisteredType(byte[].class);
112107
} else if (TypesMapping.isCharacter(attribute.getType())) {
113-
t = typeMap.getRegisteredType(String.class);
108+
type = typeMap.getRegisteredType(String.class);
114109
}
115110
// else - warning?
116111
}
117112

118-
encryptedConverters[i] = t;
119-
}
120-
121-
return new DecoratedRowDescriptor(descriptor, originalColumns, encryptedConverters);
122-
}
123-
124-
private static class DecoratedRowDescriptor extends RowDescriptor {
125-
126-
private final RowDescriptor original;
127-
128-
DecoratedRowDescriptor(RowDescriptor rowDescriptor, ColumnDescriptor[] columns, ExtendedType[] converters) {
129-
this.original = rowDescriptor;
130-
this.columns = columns;
131-
this.converters = converters;
113+
encrypted[i] = type == column.type()
114+
? column
115+
: new ColumnDescriptor(column.name(), column.dataRowKey(), column.jdbcType(), type, attribute);
132116
}
133117

134-
public RowDescriptor unwrap() {
135-
return original;
136-
}
118+
return encrypted;
137119
}
138120

139121
private class DecoratedScalarRowReader implements RowReader<Object> {
@@ -164,16 +146,16 @@ public Object readRow(ResultSet resultSet) {
164146

165147
private abstract class DecoratedEntityFullRowReader implements RowReader<Object> {
166148

167-
final RowDescriptor descriptor;
149+
final ColumnDescriptor[] columns;
168150
final RowReader<?> delegateReader;
169151
final EntityResultSegment resultMetadata;
170152
boolean decryptorCompiled;
171153
MapTransformer decryptor;
172154

173-
DecoratedEntityFullRowReader(RowDescriptor descriptor,
155+
DecoratedEntityFullRowReader(ColumnDescriptor[] columns,
174156
RowReader<?> delegateReader,
175157
EntityResultSegment resultMetadata) {
176-
this.descriptor = descriptor;
158+
this.columns = columns;
177159
this.delegateReader = delegateReader;
178160
this.resultMetadata = resultMetadata;
179161
}
@@ -198,10 +180,10 @@ public Object readRow(ResultSet resultSet) {
198180

199181
private class DecoratedEntityRowReader extends DecoratedEntityFullRowReader {
200182

201-
DecoratedEntityRowReader(RowDescriptor descriptor,
183+
DecoratedEntityRowReader(ColumnDescriptor[] columns,
202184
RowReader<?> delegateReader,
203185
EntityResultSegment resultMetadata) {
204-
super(descriptor, delegateReader, resultMetadata);
186+
super(columns, delegateReader, resultMetadata);
205187
}
206188

207189
void ensureDecryptorCompiled(Object row) {
@@ -211,7 +193,7 @@ void ensureDecryptorCompiled(Object row) {
211193
ColumnDescriptor[] columnDescriptors =
212194
new ColumnDescriptor[fieldsSize];
213195
for(int i = offset, j = 0; i < offset + fieldsSize; i++) {
214-
columnDescriptors[j++] = descriptor.getColumns()[i];
196+
columnDescriptors[j++] = columns[i];
215197
}
216198
decryptor = transformerFactory.decryptor(columnDescriptors, row);
217199
decryptorCompiled = true;
@@ -226,14 +208,14 @@ public Object readRow(ResultSet resultSet) {
226208

227209
private class DecoratedFullRowReader extends DecoratedEntityFullRowReader {
228210

229-
DecoratedFullRowReader(RowDescriptor descriptor,
211+
DecoratedFullRowReader(ColumnDescriptor[] columns,
230212
RowReader<?> delegateReader) {
231-
super(descriptor, delegateReader, null);
213+
super(columns, delegateReader, null);
232214
}
233215

234216
void ensureDecryptorCompiled(Object row) {
235217
if (!decryptorCompiled) {
236-
decryptor = transformerFactory.decryptor(descriptor.getColumns(), row);
218+
decryptor = transformerFactory.decryptor(columns, row);
237219
decryptorCompiled = true;
238220
}
239221
}

cayenne-velocity/src/main/java/org/apache/cayenne/velocity/ResultDirective.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import java.util.Map;
3232

3333
import org.apache.cayenne.access.jdbc.ColumnDescriptor;
34+
import org.apache.cayenne.access.types.ExtendedType;
35+
import org.apache.cayenne.dba.DbAdapter;
3436
import org.apache.cayenne.util.Util;
3537
import org.apache.velocity.context.InternalContextAdapter;
3638
import org.apache.velocity.exception.MethodInvocationException;
@@ -129,14 +131,18 @@ public boolean render(InternalContextAdapter context, Writer writer, Node node)
129131
String type = getChildAsString(context, node, 1);
130132
String javaClass = (type != null) ? guessType(type) : null;
131133

134+
DbAdapter adapter = (DbAdapter) context.getInternalUserContext()
135+
.get(VelocitySQLTemplateTranslator.ADAPTER_KEY);
136+
ExtendedType extendedType = adapter.getExtendedTypes().getRegisteredType(javaClass);
137+
132138
// TODO: andrus 6/27/2007 - this is an unofficial jdbcType parameter
133139
// that is added
134140
// temporarily pending CAY-813 implementation for the sake of EJBQL
135141
// query...
136142
Object jdbcTypeChild = getChild(context, node, 4);
137143
int jdbcType = (jdbcTypeChild instanceof Number) ? ((Number) jdbcTypeChild).intValue() : 0;
138144

139-
ColumnDescriptor columnDescriptor = new ColumnDescriptor(column, label, jdbcType, javaClass, null);
145+
ColumnDescriptor columnDescriptor = new ColumnDescriptor(column, label, jdbcType, extendedType, null);
140146

141147
writer.write(column);
142148

cayenne-velocity/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateTranslator_SelectTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
package org.apache.cayenne.velocity;
2121

2222
import static org.junit.jupiter.api.Assertions.assertEquals;
23-
import static org.junit.jupiter.api.Assertions.assertNull;
23+
import static org.junit.jupiter.api.Assertions.assertSame;
2424
import static org.mockito.ArgumentMatchers.anyInt;
2525
import static org.mockito.Mockito.mock;
2626
import static org.mockito.Mockito.when;
@@ -68,7 +68,7 @@ public void processSelectTemplate1() throws Exception {
6868
assertEquals(0, compiled.bindings().length);
6969
assertEquals(1, compiled.resultColumns().length);
7070
assertEquals("A", compiled.resultColumns()[0].name());
71-
assertNull(compiled.resultColumns()[0].javaClass());
71+
assertSame(adapter.getExtendedTypes().getDefaultType(), compiled.resultColumns()[0].type());
7272
}
7373

7474
@Test
@@ -82,7 +82,7 @@ public void processSelectTemplate2() throws Exception {
8282

8383
assertEquals(1, compiled.resultColumns().length);
8484
assertEquals("A", compiled.resultColumns()[0].name());
85-
assertEquals("java.lang.String", compiled.resultColumns()[0].javaClass());
85+
assertSame(adapter.getExtendedTypes().getRegisteredType(String.class), compiled.resultColumns()[0].type());
8686
}
8787

8888
@Test
@@ -98,7 +98,7 @@ public void processSelectTemplate3() throws Exception {
9898
ColumnDescriptor column = compiled.resultColumns()[0];
9999
assertEquals("A", column.name());
100100
assertEquals("B", column.dataRowKey());
101-
assertEquals("java.lang.String", column.javaClass());
101+
assertSame(adapter.getExtendedTypes().getRegisteredType(String.class), column.type());
102102
}
103103

104104
@Test

cayenne/src/main/java/org/apache/cayenne/access/DataNode.java

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@
2121

2222
import org.apache.cayenne.CayenneRuntimeException;
2323
import org.apache.cayenne.access.dbsync.SchemaUpdateStrategy;
24-
import org.apache.cayenne.access.jdbc.ColumnDescriptor;
25-
import org.apache.cayenne.access.jdbc.RowDescriptor;
26-
import org.apache.cayenne.access.jdbc.reader.RowReader;
2724
import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
2825
import org.apache.cayenne.access.translator.batch.BatchTranslator;
2926
import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
@@ -36,11 +33,9 @@
3633
import org.apache.cayenne.log.NoopJdbcEventLogger;
3734
import org.apache.cayenne.map.DataMap;
3835
import org.apache.cayenne.map.EntityResolver;
39-
import org.apache.cayenne.map.ObjAttribute;
4036
import org.apache.cayenne.query.DeleteBatchQuery;
4137
import org.apache.cayenne.query.InsertBatchQuery;
4238
import org.apache.cayenne.query.Query;
43-
import org.apache.cayenne.query.QueryMetadata;
4439
import org.apache.cayenne.query.UpdateBatchQuery;
4540
import org.apache.cayenne.tx.BaseTransaction;
4641
import org.apache.cayenne.tx.Transaction;
@@ -317,30 +312,6 @@ public String toString() {
317312
return new ToStringBuilder(this).append("name", getName()).toString();
318313
}
319314

320-
321-
/**
322-
* Creates a {@link RowReader} using internal {@link RowReaderFactory}.
323-
*
324-
* @since 4.0
325-
* @deprecated in favor of obtaining the factory via {@link #getRowReaderFactory()} and calling it directly.
326-
*/
327-
@Deprecated(since = "5.0", forRemoval = true)
328-
public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata queryMetadata) {
329-
return rowReaderFactory.rowReader(descriptor, queryMetadata, getAdapter());
330-
}
331-
332-
/**
333-
* Creates a {@link RowReader} using internal {@link RowReaderFactory}.
334-
*
335-
* @since 4.0
336-
* @deprecated in favor of obtaining the factory via {@link #getRowReaderFactory()} and calling it directly.
337-
*/
338-
@Deprecated(since = "5.0", forRemoval = true)
339-
public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
340-
Map<ObjAttribute, ColumnDescriptor> attributeOverrides) {
341-
return rowReader(descriptor, queryMetadata);
342-
}
343-
344315
/**
345316
* @since 4.0
346317
*/

cayenne/src/main/java/org/apache/cayenne/access/jdbc/BaseSQLAction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ public BaseSQLAction(DataNode dataNode) {
4949
* Helper method to process a ResultSet.
5050
*/
5151
@SuppressWarnings({ "rawtypes", "unchecked" })
52-
protected void readResultSet(ResultSet resultSet, RowDescriptor descriptor, Query query, OperationObserver delegate)
52+
protected void readResultSet(ResultSet resultSet, ColumnDescriptor[] columns, Query query, OperationObserver delegate)
5353
throws Exception {
5454

5555
long t1 = System.currentTimeMillis();
5656

5757
QueryMetadata metadata = query.getMetaData(dataNode.getEntityResolver());
5858

59-
RowReader<?> rowReader = dataNode.getRowReaderFactory().rowReader(descriptor, metadata, dataNode.getAdapter());
59+
RowReader<?> rowReader = dataNode.getRowReaderFactory().rowReader(columns, metadata, dataNode.getAdapter());
6060

6161
JDBCResultIterator resultReader = new JDBCResultIterator(null, resultSet, rowReader);
6262

cayenne/src/main/java/org/apache/cayenne/access/jdbc/BatchAction.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.cayenne.access.OptimisticLockException;
2828
import org.apache.cayenne.access.jdbc.reader.RowReader;
2929
import org.apache.cayenne.access.translator.ParameterBinding;
30+
import org.apache.cayenne.access.types.ExtendedType;
3031
import org.apache.cayenne.access.translator.batch.TranslatedBatch;
3132
import org.apache.cayenne.dba.DbAdapter;
3233
import org.apache.cayenne.log.JdbcEventLogger;
@@ -57,7 +58,7 @@ public class BatchAction extends BaseSQLAction {
5758

5859
protected boolean runningAsBatch;
5960
protected BatchQuery query;
60-
protected RowDescriptor keyRowDescriptor;
61+
protected ColumnDescriptor[] keyColumns;
6162

6263
/**
6364
* @since 4.0
@@ -267,9 +268,9 @@ protected void processGeneratedKeys(Statement statement, OperationObserver obser
267268
// (this way we can support multiple columns..
268269
// although need to check how well this works with most common drivers)
269270

270-
RowDescriptorBuilder builder = new RowDescriptorBuilder();
271+
ColumnDescriptor.RowBuilder rowBuilder = ColumnDescriptor.rowBuilder();
271272

272-
if (this.keyRowDescriptor == null) {
273+
if (this.keyColumns == null) {
273274
// attempt to figure out the right descriptor from the mapping...
274275
Collection<DbAttribute> generated = query.getDbEntity().getGeneratedAttributes();
275276
if (generated.size() == 1 && keysRS.getMetaData().getColumnCount() == 1) {
@@ -286,17 +287,18 @@ protected void processGeneratedKeys(Statement statement, OperationObserver obser
286287
columnName = "column_1";
287288
}
288289
}
289-
columns[0] = new ColumnDescriptor(columnName, columnName, key.getType(), typeForGeneratedPK(key), null);
290-
builder.setColumns(columns);
290+
ExtendedType type = dataNode.getAdapter().getExtendedTypes().getRegisteredType(typeForGeneratedPK(key));
291+
columns[0] = new ColumnDescriptor(columnName, columnName, key.getType(), type, null);
292+
rowBuilder.columns(columns);
291293
} else {
292-
builder.setResultSet(keysRS);
294+
rowBuilder.resultSet(keysRS);
293295
}
294296

295-
this.keyRowDescriptor = builder.getDescriptor(dataNode.getAdapter().getExtendedTypes());
297+
this.keyColumns = rowBuilder.build(dataNode.getAdapter().getExtendedTypes());
296298
}
297299

298300
RowReader<?> rowReader = dataNode.getRowReaderFactory()
299-
.rowReader(keyRowDescriptor, query.getMetaData(dataNode.getEntityResolver()), dataNode.getAdapter());
301+
.rowReader(keyColumns, query.getMetaData(dataNode.getEntityResolver()), dataNode.getAdapter());
300302
ResultIterator iterator = new JDBCResultIterator(null, keysRS, rowReader);
301303

302304
List<ObjectId> objectIds = new ArrayList<>(rows.size());
@@ -307,7 +309,7 @@ protected void processGeneratedKeys(Statement statement, OperationObserver obser
307309
}
308310

309311
private String typeForGeneratedPK(DbAttribute key) {
310-
String entityName = getQuery().getRows().get(0).getObjectId().getEntityName();
312+
String entityName = getQuery().getRows().getFirst().getObjectId().getEntityName();
311313
ObjEntity objEntity = dataNode.getEntityResolver().getObjEntity(entityName);
312314
if(objEntity != null) {
313315
ObjAttribute attributeForDbAttribute = objEntity.getAttributeForDbAttribute(key);

0 commit comments

Comments
 (0)