29
29
import java .util .Properties ;
30
30
import java .util .Set ;
31
31
import java .util .TreeSet ;
32
+ import java .util .concurrent .CompletableFuture ;
33
+ import java .util .concurrent .ConcurrentLinkedDeque ;
34
+ import java .util .concurrent .ExecutionException ;
35
+ import java .util .concurrent .ExecutorService ;
36
+ import java .util .concurrent .Future ;
32
37
import java .util .function .BiConsumer ;
33
38
import java .util .stream .Collectors ;
34
39
111
116
import io .quarkus .hibernate .orm .PersistenceUnit ;
112
117
import io .quarkus .hibernate .orm .deployment .integration .HibernateOrmIntegrationRuntimeConfiguredBuildItem ;
113
118
import io .quarkus .hibernate .orm .deployment .integration .HibernateOrmIntegrationStaticConfiguredBuildItem ;
119
+ import io .quarkus .hibernate .orm .deployment .integration .QuarkusClassFileLocator ;
114
120
import io .quarkus .hibernate .orm .deployment .spi .AdditionalJpaModelBuildItem ;
115
121
import io .quarkus .hibernate .orm .deployment .spi .DatabaseKindDialectBuildItem ;
116
122
import io .quarkus .hibernate .orm .dev .HibernateOrmDevIntegrator ;
144
150
import net .bytebuddy .dynamic .ClassFileLocator ;
145
151
import net .bytebuddy .dynamic .DynamicType ;
146
152
import net .bytebuddy .pool .TypePool ;
153
+ import net .bytebuddy .pool .TypePool .CacheProvider ;
154
+ import net .bytebuddy .pool .TypePool .Default .ReaderMode ;
147
155
148
156
/**
149
157
* Simulacrum of JPA bootstrap.
@@ -462,7 +470,8 @@ public BytecodeRecorderConstantDefinitionBuildItem pregenProxies(
462
470
List <PersistenceUnitDescriptorBuildItem > persistenceUnitDescriptorBuildItems ,
463
471
List <AdditionalJpaModelBuildItem > additionalJpaModelBuildItems ,
464
472
BuildProducer <GeneratedClassBuildItem > generatedClassBuildItemBuildProducer ,
465
- LiveReloadBuildItem liveReloadBuildItem ) {
473
+ LiveReloadBuildItem liveReloadBuildItem ,
474
+ ExecutorService buildExecutor ) throws ExecutionException , InterruptedException {
466
475
Set <String > managedClassAndPackageNames = new HashSet <>(jpaModel .getEntityClassNames ());
467
476
for (PersistenceUnitDescriptorBuildItem pud : persistenceUnitDescriptorBuildItems ) {
468
477
// Note: getManagedClassNames() can also return *package* names
@@ -476,9 +485,9 @@ public BytecodeRecorderConstantDefinitionBuildItem pregenProxies(
476
485
managedClassAndPackageNames .add (additionalJpaModelBuildItem .getClassName ());
477
486
}
478
487
479
- PreGeneratedProxies proxyDefinitions = generatedProxies (managedClassAndPackageNames ,
488
+ PreGeneratedProxies proxyDefinitions = generateProxies (managedClassAndPackageNames ,
480
489
indexBuildItem .getIndex (), transformedClassesBuildItem ,
481
- generatedClassBuildItemBuildProducer , liveReloadBuildItem );
490
+ generatedClassBuildItemBuildProducer , liveReloadBuildItem , buildExecutor );
482
491
483
492
// Make proxies available through a constant;
484
493
// this is a hack to avoid introducing circular dependencies between build steps.
@@ -1369,53 +1378,65 @@ private static MultiTenancyStrategy getMultiTenancyStrategy(Optional<String> mul
1369
1378
return multiTenancyStrategy ;
1370
1379
}
1371
1380
1372
- private PreGeneratedProxies generatedProxies (Set <String > managedClassAndPackageNames , IndexView combinedIndex ,
1381
+ private PreGeneratedProxies generateProxies (Set <String > managedClassAndPackageNames , IndexView combinedIndex ,
1373
1382
TransformedClassesBuildItem transformedClassesBuildItem ,
1374
1383
BuildProducer <GeneratedClassBuildItem > generatedClassBuildItemBuildProducer ,
1375
- LiveReloadBuildItem liveReloadBuildItem ) {
1384
+ LiveReloadBuildItem liveReloadBuildItem ,
1385
+ ExecutorService buildExecutor ) throws ExecutionException , InterruptedException {
1376
1386
ProxyCache proxyCache = liveReloadBuildItem .getContextObject (ProxyCache .class );
1377
1387
if (proxyCache == null ) {
1378
1388
proxyCache = new ProxyCache ();
1379
1389
liveReloadBuildItem .setContextObject (ProxyCache .class , proxyCache );
1380
1390
}
1381
- Set <String > changedClasses = Collections . emptySet ();
1391
+ Set <String > changedClasses = Set . of ();
1382
1392
if (liveReloadBuildItem .getChangeInformation () != null ) {
1383
1393
changedClasses = liveReloadBuildItem .getChangeInformation ().getChangedClasses ();
1384
1394
} else {
1385
1395
//we don't have class change info, invalidate the cache
1386
1396
proxyCache .cache .clear ();
1387
1397
}
1388
1398
//create a map of entity to proxy type
1389
- PreGeneratedProxies preGeneratedProxies = new PreGeneratedProxies ();
1390
1399
TypePool transformedClassesTypePool = createTransformedClassesTypePool (transformedClassesBuildItem ,
1391
1400
managedClassAndPackageNames );
1401
+
1402
+ PreGeneratedProxies preGeneratedProxies = new PreGeneratedProxies ();
1403
+
1392
1404
try (ProxyBuildingHelper proxyHelper = new ProxyBuildingHelper (transformedClassesTypePool )) {
1405
+ final ConcurrentLinkedDeque <Future <CachedProxy >> generatedProxyQueue = new ConcurrentLinkedDeque <>();
1406
+ Set <String > proxyInterfaceNames = Set .of (ClassNames .HIBERNATE_PROXY .toString ());
1407
+
1393
1408
for (String managedClassOrPackageName : managedClassAndPackageNames ) {
1394
- CachedProxy result ;
1395
1409
if (proxyCache .cache .containsKey (managedClassOrPackageName )
1396
1410
&& !isModified (managedClassOrPackageName , changedClasses , combinedIndex )) {
1397
- result = proxyCache .cache .get (managedClassOrPackageName );
1411
+ CachedProxy proxy = proxyCache .cache .get (managedClassOrPackageName );
1412
+ generatedProxyQueue .add (CompletableFuture .completedFuture (proxy ));
1398
1413
} else {
1399
- Set <String > proxyInterfaceNames = new TreeSet <>();
1400
- proxyInterfaceNames .add (ClassNames .HIBERNATE_PROXY .toString ()); //always added
1401
- if (!proxyHelper .isProxiable (managedClassOrPackageName )) {
1402
- // we need to make sure the actual class is proxiable
1414
+ if (!proxyHelper .isProxiable (combinedIndex .getClassByName (managedClassOrPackageName ))) {
1415
+ // we need to make sure we have a class and not a package and that it is proxiable
1403
1416
continue ;
1404
1417
}
1405
- final String mappedClass = managedClassOrPackageName ;
1406
- DynamicType .Unloaded <?> unloaded = proxyHelper .buildUnloadedProxy (mappedClass , proxyInterfaceNames );
1407
- result = new CachedProxy (unloaded , proxyInterfaceNames );
1408
- proxyCache .cache .put (managedClassOrPackageName , result );
1418
+ // we now are sure we have a proper class and not a package, let's avoid the confusion
1419
+ String managedClass = managedClassOrPackageName ;
1420
+ generatedProxyQueue .add (buildExecutor .submit (() -> {
1421
+ DynamicType .Unloaded <?> unloaded = proxyHelper .buildUnloadedProxy (managedClass ,
1422
+ proxyInterfaceNames );
1423
+ return new CachedProxy (managedClass , unloaded , proxyInterfaceNames );
1424
+ }));
1409
1425
}
1410
- for (Entry <TypeDescription , byte []> i : result .proxyDef .getAllTypes ().entrySet ()) {
1426
+ }
1427
+
1428
+ for (Future <CachedProxy > proxyFuture : generatedProxyQueue ) {
1429
+ CachedProxy proxy = proxyFuture .get ();
1430
+ proxyCache .cache .put (proxy .managedClassName , proxy );
1431
+ for (Entry <TypeDescription , byte []> i : proxy .proxyDef .getAllTypes ().entrySet ()) {
1411
1432
generatedClassBuildItemBuildProducer
1412
1433
.produce (new GeneratedClassBuildItem (true , i .getKey ().getName (), i .getValue ()));
1413
1434
}
1414
- preGeneratedProxies .getProxies ().put (managedClassOrPackageName ,
1415
- new PreGeneratedProxies .ProxyClassDetailsHolder (result .proxyDef .getTypeDescription ().getName (),
1416
- result .interfaces ));
1435
+ preGeneratedProxies .getProxies ().put (proxy .managedClassName , new PreGeneratedProxies .ProxyClassDetailsHolder (
1436
+ proxy .proxyDef .getTypeDescription ().getName (), proxy .interfaces ));
1417
1437
}
1418
1438
}
1439
+
1419
1440
return preGeneratedProxies ;
1420
1441
}
1421
1442
@@ -1435,9 +1456,15 @@ private TypePool createTransformedClassesTypePool(TransformedClassesBuildItem tr
1435
1456
}
1436
1457
}
1437
1458
}
1438
- return TypePool .Default .of (new ClassFileLocator .Compound (
1459
+
1460
+ ClassFileLocator classFileLocator = new ClassFileLocator .Compound (
1439
1461
new ClassFileLocator .Simple (transformedClasses ),
1440
- ClassFileLocator .ForClassLoader .of (Thread .currentThread ().getContextClassLoader ())));
1462
+ QuarkusClassFileLocator .INSTANCE );
1463
+
1464
+ // we can reuse the core TypePool but we may not reuse the full enhancer TypePool
1465
+ // or PublicFieldWithProxyAndLazyLoadingAndInheritanceTest will fail
1466
+ return new TypePool .Default (new CacheProvider .Simple (), classFileLocator , ReaderMode .FAST ,
1467
+ HibernateEntityEnhancer .CORE_TYPE_POOL );
1441
1468
}
1442
1469
1443
1470
private boolean isModified (String entity , Set <String > changedClasses , IndexView index ) {
@@ -1455,7 +1482,7 @@ private boolean isModified(String entity, Set<String> changedClasses, IndexView
1455
1482
}
1456
1483
}
1457
1484
DotName superName = clazz .superName ();
1458
- if (superName != null ) {
1485
+ if (superName != null && ! DotName . OBJECT_NAME . equals ( superName ) ) {
1459
1486
return isModified (superName .toString (), changedClasses , index );
1460
1487
}
1461
1488
return false ;
@@ -1467,10 +1494,12 @@ private static final class ProxyCache {
1467
1494
}
1468
1495
1469
1496
static final class CachedProxy {
1497
+ final String managedClassName ;
1470
1498
final DynamicType .Unloaded <?> proxyDef ;
1471
1499
final Set <String > interfaces ;
1472
1500
1473
- CachedProxy (DynamicType .Unloaded <?> proxyDef , Set <String > interfaces ) {
1501
+ CachedProxy (String managedClassName , DynamicType .Unloaded <?> proxyDef , Set <String > interfaces ) {
1502
+ this .managedClassName = managedClassName ;
1474
1503
this .proxyDef = proxyDef ;
1475
1504
this .interfaces = interfaces ;
1476
1505
}
0 commit comments