28
28
import java .io .ByteArrayOutputStream ;
29
29
import java .io .DataOutputStream ;
30
30
import java .io .IOException ;
31
+ import java .util .IdentityHashMap ;
31
32
32
33
import javassist .CannotCompileException ;
33
34
import javassist .ClassPool ;
34
35
import javassist .CtClass ;
35
36
import javassist .CtField ;
37
+ import javassist .CtMethod ;
36
38
import javassist .CtNewMethod ;
37
39
import javassist .Modifier ;
38
40
import javassist .bytecode .AnnotationsAttribute ;
44
46
45
47
import org .hibernate .HibernateException ;
46
48
import org .hibernate .bytecode .enhance .EnhancementException ;
47
- import org .hibernate .bytecode . internal . javassist . FieldHandled ;
49
+ import org .hibernate .engine . spi . Managed ;
48
50
import org .hibernate .engine .spi .ManagedComposite ;
49
51
import org .hibernate .engine .spi .ManagedEntity ;
50
52
import org .hibernate .engine .spi .EntityEntry ;
57
59
public class Enhancer {
58
60
private static final CoreMessageLogger log = Logger .getMessageLogger ( CoreMessageLogger .class , Enhancer .class .getName () );
59
61
62
+ private static final String PERSISTENT_FIELD_READER_PREFIX = "$hibernate_read_" ;
63
+ private static final String PERSISTENT_FIELD_WRITER_PREFIX = "$hibernate_write_" ;
64
+
60
65
public static final String ENTITY_INSTANCE_GETTER_NAME = "hibernate_getEntityInstance" ;
61
66
62
67
public static final String ENTITY_ENTRY_FIELD_NAME = "$hibernate_entityEntryHolder" ;
@@ -168,7 +173,7 @@ private void enhance(CtClass managedCtClass) {
168
173
169
174
final String [] interfaceNames = managedCtClass .getClassFile2 ().getInterfaces ();
170
175
for ( String interfaceName : interfaceNames ) {
171
- if ( FieldHandled .class .getName ().equals ( interfaceName ) ) {
176
+ if ( Managed .class .getName ().equals ( interfaceName ) ) {
172
177
log .debug ( "skipping enhancement : already enhanced" );
173
178
return ;
174
179
}
@@ -191,13 +196,18 @@ private void enhanceAsEntity(CtClass managedCtClass) {
191
196
// add the ManagedEntity interface
192
197
managedCtClass .addInterface ( managedEntityCtClass );
193
198
194
- addEntityInstanceHandling ( managedCtClass , constPool );
195
- addEntityEntryHandling ( managedCtClass , constPool );
196
- addLinkedPreviousHandling ( managedCtClass , constPool );
197
- addLinkedNextHandling ( managedCtClass , constPool );
199
+ // enhancePersistentAttributes( managedCtClass );
200
+
201
+ addEntityInstanceHandling ( managedCtClass );
202
+ addEntityEntryHandling ( managedCtClass );
203
+ addLinkedPreviousHandling ( managedCtClass );
204
+ addLinkedNextHandling ( managedCtClass );
198
205
}
199
206
200
- private void addEntityInstanceHandling (CtClass managedCtClass , ConstPool constPool ) {
207
+ private void enhanceAsComposite (CtClass classFile ) {
208
+ }
209
+
210
+ private void addEntityInstanceHandling (CtClass managedCtClass ) {
201
211
// add the ManagedEntity#hibernate_getEntityInstance method
202
212
try {
203
213
managedCtClass .addMethod (
@@ -224,7 +234,9 @@ private void addEntityInstanceHandling(CtClass managedCtClass, ConstPool constPo
224
234
// essentially add `return this;`
225
235
}
226
236
227
- private void addEntityEntryHandling (CtClass managedCtClass , ConstPool constPool ) {
237
+ private void addEntityEntryHandling (CtClass managedCtClass ) {
238
+ final ConstPool constPool = managedCtClass .getClassFile ().getConstPool ();
239
+
228
240
// add field to hold EntityEntry
229
241
final CtField entityEntryField ;
230
242
try {
@@ -243,6 +255,7 @@ private void addEntityEntryHandling(CtClass managedCtClass, ConstPool constPool)
243
255
244
256
// make that new field transient and @Transient
245
257
entityEntryField .setModifiers ( entityEntryField .getModifiers () | Modifier .TRANSIENT );
258
+ entityEntryField .setModifiers ( Modifier .setPrivate ( entityEntryField .getModifiers () ) );
246
259
AnnotationsAttribute annotationsAttribute = getVisibleAnnotations ( entityEntryField .getFieldInfo () );
247
260
annotationsAttribute .addAnnotation ( new Annotation ( Transient .class .getName (), constPool ) );
248
261
@@ -279,11 +292,13 @@ private void addEntityEntryHandling(CtClass managedCtClass, ConstPool constPool)
279
292
}
280
293
}
281
294
282
- private void addLinkedPreviousHandling (CtClass managedCtClass , ConstPool constPool ) {
295
+ private void addLinkedPreviousHandling (CtClass managedCtClass ) {
296
+ final ConstPool constPool = managedCtClass .getClassFile ().getConstPool ();
297
+
283
298
// add field to hold "previous" ManagedEntity
284
299
final CtField previousField ;
285
300
try {
286
- previousField = new CtField ( managedCtClass , PREVIOUS_FIELD_NAME , managedCtClass );
301
+ previousField = new CtField ( managedEntityCtClass , PREVIOUS_FIELD_NAME , managedCtClass );
287
302
managedCtClass .addField ( previousField );
288
303
}
289
304
catch (CannotCompileException e ) {
@@ -298,6 +313,7 @@ private void addLinkedPreviousHandling(CtClass managedCtClass, ConstPool constPo
298
313
299
314
// make that new field transient and @Transient
300
315
previousField .setModifiers ( previousField .getModifiers () | Modifier .TRANSIENT );
316
+ previousField .setModifiers ( Modifier .setPrivate ( previousField .getModifiers () ) );
301
317
AnnotationsAttribute annotationsAttribute = getVisibleAnnotations ( previousField .getFieldInfo () );
302
318
annotationsAttribute .addAnnotation ( new Annotation ( Transient .class .getName (), constPool ) );
303
319
@@ -330,11 +346,13 @@ private void addLinkedPreviousHandling(CtClass managedCtClass, ConstPool constPo
330
346
}
331
347
}
332
348
333
- private void addLinkedNextHandling (CtClass managedCtClass , ConstPool constPool ) {
349
+ private void addLinkedNextHandling (CtClass managedCtClass ) {
350
+ final ConstPool constPool = managedCtClass .getClassFile ().getConstPool ();
351
+
334
352
// add field to hold "next" ManagedEntity
335
353
final CtField nextField ;
336
354
try {
337
- nextField = new CtField ( managedCtClass , NEXT_FIELD_NAME , managedCtClass );
355
+ nextField = new CtField ( managedEntityCtClass , NEXT_FIELD_NAME , managedCtClass );
338
356
managedCtClass .addField ( nextField );
339
357
}
340
358
catch (CannotCompileException e ) {
@@ -347,8 +365,9 @@ private void addLinkedNextHandling(CtClass managedCtClass, ConstPool constPool)
347
365
);
348
366
}
349
367
350
- // make that new field transient and @Transient
368
+ // make that new field (1) private, (2) transient and (3) @Transient
351
369
nextField .setModifiers ( nextField .getModifiers () | Modifier .TRANSIENT );
370
+ nextField .setModifiers ( Modifier .setPrivate ( nextField .getModifiers () ) );
352
371
AnnotationsAttribute annotationsAttribute = getVisibleAnnotations ( nextField .getFieldInfo () );
353
372
annotationsAttribute .addAnnotation ( new Annotation ( Transient .class .getName (), constPool ) );
354
373
@@ -390,8 +409,84 @@ private AnnotationsAttribute getVisibleAnnotations(FieldInfo fieldInfo) {
390
409
return annotationsAttribute ;
391
410
}
392
411
393
- private void enhanceAsComposite (CtClass classFile ) {
412
+ private void enhancePersistentAttributes (CtClass managedCtClass ) {
413
+ final IdentityHashMap <CtField ,FieldVirtualReadWritePair > fieldToMethodsXref = new IdentityHashMap <CtField , FieldVirtualReadWritePair >();
414
+
415
+ for ( CtField ctField : managedCtClass .getFields () ) {
416
+ if ( ! enhancementContext .isPersistentField ( ctField ) ) {
417
+ continue ;
418
+ }
419
+
420
+ final FieldVirtualReadWritePair methodPair = addReadAndWriteMethod ( managedCtClass , ctField );
421
+ fieldToMethodsXref .put ( ctField , methodPair );
422
+ }
423
+
424
+ transformFieldAccessesIntoReadsAndWrites ( managedCtClass , fieldToMethodsXref );
425
+ }
426
+
427
+ private FieldVirtualReadWritePair addReadAndWriteMethod (CtClass managedCtClass , CtField persistentField ) {
428
+ // add the "reader"
429
+ final CtMethod reader = generateFieldReader ( managedCtClass , persistentField );
430
+
431
+ // add the "writer"
432
+ final CtMethod writer = generateFieldWriter ( managedCtClass , persistentField );
433
+
434
+ return new FieldVirtualReadWritePair ( reader , writer );
394
435
}
395
436
437
+ private CtMethod generateFieldReader (CtClass managedCtClass , CtField persistentField ) {
438
+ // todo : temporary; still need to add hooks into lazy-loading
439
+ try {
440
+ final String name = PERSISTENT_FIELD_READER_PREFIX + persistentField .getName ();
441
+ CtMethod reader = CtNewMethod .getter ( name , persistentField );
442
+ managedCtClass .addMethod ( reader );
443
+ return reader ;
444
+ }
445
+ catch (CannotCompileException e ) {
446
+ throw new EnhancementException (
447
+ String .format (
448
+ "Could not enhance entity class [%s] to add virtual reader method for field [%s]" ,
449
+ managedCtClass .getName (),
450
+ persistentField .getName ()
451
+ ),
452
+ e
453
+ );
454
+ }
455
+ }
456
+
457
+ private CtMethod generateFieldWriter (CtClass managedCtClass , CtField persistentField ) {
458
+ // todo : temporary; still need to add hooks into lazy-loading and dirtying
459
+ try {
460
+ final String name = PERSISTENT_FIELD_WRITER_PREFIX + persistentField .getName ();
461
+ CtMethod writer = CtNewMethod .setter ( name , persistentField );
462
+ managedCtClass .addMethod ( writer );
463
+ return writer ;
464
+ }
465
+ catch (CannotCompileException e ) {
466
+ throw new EnhancementException (
467
+ String .format (
468
+ "Could not enhance entity class [%s] to add virtual writer method for field [%s]" ,
469
+ managedCtClass .getName (),
470
+ persistentField .getName ()
471
+ ),
472
+ e
473
+ );
474
+ }
475
+ }
476
+
477
+ private void transformFieldAccessesIntoReadsAndWrites (
478
+ CtClass managedCtClass ,
479
+ IdentityHashMap <CtField , FieldVirtualReadWritePair > fieldToMethodsXref ) {
480
+ }
481
+
482
+ private static class FieldVirtualReadWritePair {
483
+ private final CtMethod readMethod ;
484
+ private final CtMethod writeMethod ;
485
+
486
+ private FieldVirtualReadWritePair (CtMethod readMethod , CtMethod writeMethod ) {
487
+ this .readMethod = readMethod ;
488
+ this .writeMethod = writeMethod ;
489
+ }
490
+ }
396
491
397
492
}
0 commit comments