0
# Configuration and Customization
1
2
QueryDSL SQL provides a flexible configuration system for customizing SQL generation, type mappings, naming strategies, schema mappings, and execution monitoring through listeners and custom mappings.
3
4
## Capabilities
5
6
### Core Configuration
7
8
Central configuration class that coordinates all aspects of QueryDSL SQL behavior.
9
10
```java { .api }
11
/**
12
* Central configuration class for QueryDSL SQL operations
13
*/
14
public class Configuration {
15
/**
16
* Creates configuration with specified SQL templates
17
* @param templates Database-specific SQL templates
18
*/
19
public Configuration(SQLTemplates templates);
20
21
/**
22
* Gets the SQL templates for this configuration
23
* @return SQL templates instance
24
*/
25
public SQLTemplates getTemplates();
26
27
/**
28
* Registers a custom type for a specific table column
29
* @param table Table name
30
* @param column Column name
31
* @param type Type handler to use
32
*/
33
public void register(String table, String column, Type<?> type);
34
35
/**
36
* Registers a path mapping for schema and table resolution
37
* @param table Table identifier
38
* @param property Property name
39
* @param path Path to map to
40
*/
41
public void register(String table, String property, Path<?> path);
42
43
/**
44
* Registers a global type mapping by SQL type name
45
* @param typeName SQL type name
46
* @param type Type handler to use
47
*/
48
public void registerType(String typeName, Type<?> type);
49
50
/**
51
* Adds a SQL execution listener
52
* @param listener Listener to add
53
*/
54
public void addListener(SQLListener listener);
55
56
/**
57
* Removes a SQL execution listener
58
* @param listener Listener to remove
59
*/
60
public void removeListener(SQLListener listener);
61
}
62
```
63
64
**Usage Examples:**
65
66
```java
67
// Basic configuration setup
68
SQLTemplates templates = PostgreSQLTemplates.builder().build();
69
Configuration config = new Configuration(templates);
70
71
// Register custom type for specific column
72
config.register("user", "status", new EnumByNameType<>(UserStatus.class));
73
74
// Register global type mapping
75
config.registerType("uuid", new UtilUUIDType());
76
77
// Add execution listener
78
config.addListener(new SQLBaseListener() {
79
@Override
80
public void notifyQuery(SQLListenerContext context) {
81
logger.info("Executing query: {}", context.getSQL());
82
}
83
});
84
85
// Create query factory with configuration
86
SQLQueryFactory queryFactory = new SQLQueryFactory(config, dataSource);
87
```
88
89
### Type Registration
90
91
System for registering and managing custom type mappings at various scopes.
92
93
```java { .api }
94
/**
95
* JDBC to Java type mapping registry
96
*/
97
public class JDBCTypeMapping {
98
/**
99
* Registers a type for specific JDBC type codes
100
* @param type Type handler to register
101
* @param jdbcTypes JDBC type codes this handler supports
102
*/
103
public void register(Type<?> type, int... jdbcTypes);
104
105
/**
106
* Gets registered type for JDBC type code
107
* @param jdbcType JDBC type code
108
* @param typeName SQL type name
109
* @param size Column size
110
* @param digits Decimal digits
111
* @return Appropriate type handler
112
*/
113
public Type<?> getType(int jdbcType, String typeName, int size, int digits);
114
}
115
116
/**
117
* Java class to QueryDSL type mapping registry
118
*/
119
public class JavaTypeMapping {
120
/**
121
* Registers a type handler for a Java class
122
* @param javaType Java class
123
* @param type Type handler
124
*/
125
public void register(Class<?> javaType, Type<?> type);
126
127
/**
128
* Gets type handler for Java class
129
* @param javaType Java class to get handler for
130
* @return Type handler or null if not registered
131
*/
132
public Type<?> getType(Class<?> javaType);
133
}
134
```
135
136
**Usage Examples:**
137
138
```java
139
Configuration config = new Configuration(templates);
140
141
// Register type for specific JDBC types
142
JDBCTypeMapping jdbcMapping = config.getJDBCTypeMapping();
143
jdbcMapping.register(new UUIDType(), Types.OTHER, Types.VARCHAR);
144
145
// Register type for Java classes
146
JavaTypeMapping javaMapping = config.getJavaTypeMapping();
147
javaMapping.register(Money.class, new MoneyType());
148
javaMapping.register(PhoneNumber.class, new PhoneNumberType());
149
150
// Column-specific type registration takes precedence
151
config.register("user", "phone", new InternationalPhoneType());
152
```
153
154
### Name Mapping
155
156
Flexible naming strategies for mapping between Java identifiers and SQL identifiers.
157
158
```java { .api }
159
/**
160
* Interface for mapping between Java and SQL identifiers
161
*/
162
public interface NameMapping {
163
/**
164
* Maps Java identifier to SQL identifier
165
* @param javaIdentifier Java field/property name
166
* @return SQL column/table name
167
*/
168
String getColumnOverride(String javaIdentifier);
169
170
/**
171
* Maps SQL identifier to Java identifier
172
* @param sqlIdentifier SQL column/table name
173
* @return Java field/property name
174
*/
175
String getPropertyOverride(String sqlIdentifier);
176
}
177
178
/**
179
* Chains multiple name mappings together
180
*/
181
public class ChainedNameMapping implements NameMapping {
182
public ChainedNameMapping(NameMapping... mappings);
183
public ChainedNameMapping add(NameMapping mapping);
184
}
185
186
/**
187
* Changes letter case of identifiers
188
*/
189
public class ChangeLetterCaseNameMapping implements NameMapping {
190
public enum LetterCase { UPPER, LOWER }
191
192
public ChangeLetterCaseNameMapping(LetterCase letterCase);
193
public ChangeLetterCaseNameMapping(LetterCase columnCase, LetterCase propertyCase);
194
}
195
196
/**
197
* Pre-configured mappings for specific naming conventions
198
*/
199
public class PreConfiguredNameMapping implements NameMapping {
200
public static final NameMapping CAMEL_CASE_TO_LOWER_WITH_UNDERSCORES;
201
public static final NameMapping UPPER_WITH_UNDERSCORES_TO_CAMEL_CASE;
202
203
public PreConfiguredNameMapping(Map<String, String> columnToProperty);
204
}
205
```
206
207
**Usage Examples:**
208
209
```java
210
// Configure camelCase to snake_case mapping
211
NameMapping nameMapping = PreConfiguredNameMapping.CAMEL_CASE_TO_LOWER_WITH_UNDERSCORES;
212
config.setNameMapping(nameMapping);
213
214
// Chain multiple naming strategies
215
NameMapping chainedMapping = new ChainedNameMapping(
216
new ChangeLetterCaseNameMapping(LetterCase.LOWER),
217
PreConfiguredNameMapping.CAMEL_CASE_TO_LOWER_WITH_UNDERSCORES
218
);
219
220
// Custom name mapping
221
Map<String, String> customMappings = new HashMap<>();
222
customMappings.put("user_id", "userId");
223
customMappings.put("created_at", "createdTime");
224
customMappings.put("is_active", "active");
225
226
NameMapping customMapping = new PreConfiguredNameMapping(customMappings);
227
config.setNameMapping(customMapping);
228
```
229
230
### Schema Mapping
231
232
Configuration for handling database schemas and table name resolution.
233
234
```java { .api }
235
/**
236
* Represents schema and table combination
237
*/
238
public class SchemaAndTable {
239
/**
240
* Creates schema and table reference
241
* @param schema Schema name (can be null)
242
* @param table Table name
243
*/
244
public SchemaAndTable(String schema, String table);
245
246
/**
247
* Gets the schema name
248
* @return Schema name or null
249
*/
250
public String getSchema();
251
252
/**
253
* Gets the table name
254
* @return Table name
255
*/
256
public String getTable();
257
258
/**
259
* Creates qualified table name
260
* @return Schema.table or just table if no schema
261
*/
262
public String getQualifiedName();
263
}
264
```
265
266
**Usage Examples:**
267
268
```java
269
// Configure default schema
270
Configuration config = new Configuration(templates);
271
config.setSchema("app_schema");
272
273
// Register table with specific schema
274
config.register(new SchemaAndTable("audit", "user_changes"), qUserAudit);
275
276
// Multi-tenant schema mapping
277
Map<String, String> tenantSchemas = new HashMap<>();
278
tenantSchemas.put("tenant1", "tenant1_schema");
279
tenantSchemas.put("tenant2", "tenant2_schema");
280
281
// Dynamic schema resolution
282
String currentTenant = getCurrentTenant();
283
String schema = tenantSchemas.get(currentTenant);
284
config.setSchema(schema);
285
```
286
287
### SQL Execution Listeners
288
289
Comprehensive listener system for monitoring and customizing SQL execution behavior.
290
291
```java { .api }
292
/**
293
* Core interface for SQL execution listeners
294
*/
295
public interface SQLListener {
296
/**
297
* Called before query execution
298
* @param context Execution context with SQL and parameters
299
*/
300
void notifyQuery(SQLListenerContext context);
301
302
/**
303
* Called before delete execution
304
* @param context Execution context
305
*/
306
void notifyDelete(SQLListenerContext context);
307
308
/**
309
* Called before insert execution
310
* @param context Execution context
311
*/
312
void notifyInsert(SQLListenerContext context);
313
314
/**
315
* Called before update execution
316
* @param context Execution context
317
*/
318
void notifyUpdate(SQLListenerContext context);
319
320
/**
321
* Called before merge execution
322
* @param context Execution context
323
*/
324
void notifyMerge(SQLListenerContext context);
325
}
326
327
/**
328
* Extended listener interface with detailed execution information
329
*/
330
public interface SQLDetailedListener extends SQLListener {
331
/**
332
* Called after successful query execution
333
* @param context Execution context
334
* @param duration Execution duration in milliseconds
335
*/
336
void notifyQueryEnd(SQLListenerContext context, long duration);
337
338
/**
339
* Called when query execution fails
340
* @param context Execution context
341
* @param exception Exception that occurred
342
*/
343
void notifyException(SQLListenerContext context, Exception exception);
344
}
345
```
346
347
**Usage Examples:**
348
349
```java
350
// Logging listener
351
SQLListener loggingListener = new SQLBaseListener() {
352
@Override
353
public void notifyQuery(SQLListenerContext context) {
354
logger.debug("Query: {} with params: {}",
355
context.getSQL(), context.getBindings());
356
}
357
};
358
359
// Performance monitoring listener
360
SQLDetailedListener perfListener = new SQLListenerAdapter() {
361
@Override
362
public void notifyQueryEnd(SQLListenerContext context, long duration) {
363
if (duration > 1000) { // Log slow queries
364
logger.warn("Slow query ({}ms): {}", duration, context.getSQL());
365
}
366
}
367
368
@Override
369
public void notifyException(SQLListenerContext context, Exception exception) {
370
logger.error("Query failed: {} - {}", context.getSQL(), exception.getMessage());
371
}
372
};
373
374
// Add listeners to configuration
375
config.addListener(loggingListener);
376
config.addListener(perfListener);
377
```
378
379
### Listener Context and Utilities
380
381
Context objects and utilities for working with SQL execution listeners.
382
383
```java { .api }
384
/**
385
* Execution context provided to listeners
386
*/
387
public interface SQLListenerContext {
388
/**
389
* Gets the SQL statement being executed
390
* @return SQL string with parameter placeholders
391
*/
392
String getSQL();
393
394
/**
395
* Gets the parameter bindings for the SQL
396
* @return List of parameter values in order
397
*/
398
List<Object> getBindings();
399
400
/**
401
* Gets execution metadata
402
* @return Map of metadata key-value pairs
403
*/
404
Map<String, Object> getData();
405
406
/**
407
* Gets the entity being operated on (for DML operations)
408
* @return Entity path or null for queries
409
*/
410
RelationalPath<?> getEntity();
411
}
412
413
/**
414
* Manages multiple listeners as a single unit
415
*/
416
public class SQLListeners implements SQLDetailedListener {
417
/**
418
* Creates listener collection from individual listeners
419
* @param listeners Individual listener instances
420
*/
421
public SQLListeners(SQLListener... listeners);
422
423
/**
424
* Adds a listener to the collection
425
* @param listener Listener to add
426
*/
427
public void add(SQLListener listener);
428
429
/**
430
* Removes a listener from the collection
431
* @param listener Listener to remove
432
*/
433
public void remove(SQLListener listener);
434
}
435
```
436
437
### Built-in Listener Implementations
438
439
Pre-built listener implementations for common use cases.
440
441
```java { .api }
442
/**
443
* Base listener implementation with no-op methods
444
*/
445
public class SQLBaseListener implements SQLListener {
446
// All methods have empty default implementations
447
}
448
449
/**
450
* Adapter implementation for selective method overriding
451
*/
452
public class SQLListenerAdapter implements SQLDetailedListener {
453
// All methods have empty default implementations
454
}
455
456
/**
457
* Automatically closes database connections after operations
458
*/
459
public class SQLCloseListener implements SQLListener {
460
public static final SQLCloseListener DEFAULT = new SQLCloseListener();
461
462
@Override
463
public void notifyQuery(SQLListenerContext context) {
464
// Closes connection if auto-close is enabled
465
}
466
}
467
468
/**
469
* Listener that doesn't close connections
470
*/
471
public class SQLNoCloseListener implements SQLListener {
472
public static final SQLNoCloseListener DEFAULT = new SQLNoCloseListener();
473
474
// No-op implementation that preserves connections
475
}
476
```
477
478
**Usage Examples:**
479
480
```java
481
// Automatic connection management
482
config.addListener(SQLCloseListener.DEFAULT);
483
484
// Custom composite listener
485
SQLListeners compositeListener = new SQLListeners(
486
new AuditingListener(),
487
new CacheClearingListener(),
488
new MetricsListener()
489
);
490
config.addListener(compositeListener);
491
492
// Conditional listener
493
SQLListener conditionalListener = new SQLBaseListener() {
494
@Override
495
public void notifyQuery(SQLListenerContext context) {
496
if (context.getSQL().contains("SELECT")) {
497
queryCache.invalidate(context.getSQL());
498
}
499
}
500
};
501
```
502
503
### Configuration Builder Pattern
504
505
Builder pattern for constructing complex configurations with multiple customizations.
506
507
```java { .api }
508
/**
509
* Builder pattern for Configuration construction
510
*/
511
public class ConfigurationBuilder {
512
/**
513
* Sets the SQL templates
514
* @param templates Database-specific templates
515
* @return Builder for method chaining
516
*/
517
public ConfigurationBuilder templates(SQLTemplates templates);
518
519
/**
520
* Sets the default schema
521
* @param schema Schema name
522
* @return Builder for method chaining
523
*/
524
public ConfigurationBuilder schema(String schema);
525
526
/**
527
* Sets the name mapping strategy
528
* @param nameMapping Name mapping implementation
529
* @return Builder for method chaining
530
*/
531
public ConfigurationBuilder nameMapping(NameMapping nameMapping);
532
533
/**
534
* Adds a SQL listener
535
* @param listener Listener to add
536
* @return Builder for method chaining
537
*/
538
public ConfigurationBuilder listener(SQLListener listener);
539
540
/**
541
* Registers a custom type
542
* @param table Table name
543
* @param column Column name
544
* @param type Type handler
545
* @return Builder for method chaining
546
*/
547
public ConfigurationBuilder register(String table, String column, Type<?> type);
548
549
/**
550
* Builds the final configuration
551
* @return Configured Configuration instance
552
*/
553
public Configuration build();
554
}
555
```
556
557
**Usage Examples:**
558
559
```java
560
// Complex configuration using builder pattern
561
Configuration config = new ConfigurationBuilder()
562
.templates(PostgreSQLTemplates.builder().build())
563
.schema("application")
564
.nameMapping(PreConfiguredNameMapping.CAMEL_CASE_TO_LOWER_WITH_UNDERSCORES)
565
.listener(new AuditingListener())
566
.listener(new PerformanceListener())
567
.register("user", "status", new EnumByNameType<>(UserStatus.class))
568
.register("order", "amount", new MoneyType())
569
.build();
570
571
SQLQueryFactory queryFactory = new SQLQueryFactory(config, dataSource);
572
```