Skip to content

Commit 6c5f7fd

Browse files
committed
Prevent multiple contributions to Panache's "entityToPersistenceUnit" from overriding each other
This should fix the seemingly random "Entity not found" when using Kotlin.
1 parent daaf4da commit 6c5f7fd

File tree

10 files changed

+44
-23
lines changed

10 files changed

+44
-23
lines changed

extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/AbstractJpaOperations.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,22 @@
2525
import io.quarkus.panache.hibernate.common.runtime.PanacheJpaUtil;
2626

2727
public abstract class AbstractJpaOperations<PanacheQueryType> {
28-
private static volatile Map<String, String> entityToPersistenceUnit = Collections.emptyMap();
29-
private static volatile boolean entityToPersistenceUnitIsIncomplete = true;
30-
31-
public static void setEntityToPersistenceUnit(Map<String, String> map, boolean incomplete) {
32-
entityToPersistenceUnit = Collections.unmodifiableMap(map);
33-
entityToPersistenceUnitIsIncomplete = incomplete;
28+
private static final Map<String, String> entityToPersistenceUnit = new HashMap<>();
29+
private static volatile Boolean entityToPersistenceUnitIsIncomplete = null;
30+
31+
// Putting synchronized here because fields involved were marked as volatile initially,
32+
// so I expect recorders can be called concurrently?
33+
public static synchronized void addEntityTypesToPersistenceUnit(Map<String, String> map, boolean incomplete) {
34+
// Note: this may be called multiple times if an app uses both Java and Kotlin.
35+
// We don't really test what happens if entities are defined both in Java and Kotlin at the moment,
36+
// so we mostly care about the case where this gets called once with an empty map, and once with a non-empty map:
37+
// in that case, we don't want the empty map to erase the other one.
38+
entityToPersistenceUnit.putAll(map);
39+
if (entityToPersistenceUnitIsIncomplete == null) {
40+
entityToPersistenceUnitIsIncomplete = incomplete;
41+
} else {
42+
entityToPersistenceUnitIsIncomplete = entityToPersistenceUnitIsIncomplete || incomplete;
43+
}
3444
}
3545

3646
protected abstract PanacheQueryType createPanacheQuery(Session session, String query, String originalQuery, String orderBy,
@@ -58,7 +68,7 @@ public Session getSession(Class<?> clazz) {
5868
String clazzName = clazz.getName();
5969
String persistentUnitName = entityToPersistenceUnit.get(clazzName);
6070
if (persistentUnitName == null) {
61-
if (entityToPersistenceUnitIsIncomplete) {
71+
if (entityToPersistenceUnitIsIncomplete == null || entityToPersistenceUnitIsIncomplete) {
6272
// When using persistence.xml, `entityToPersistenceUnit` is most likely empty,
6373
// so we'll just return the default PU and hope for the best.
6474
// The error will be thrown later by Hibernate ORM if necessary;

extensions/panache/hibernate-orm-panache-kotlin/deployment/src/main/java/io/quarkus/hibernate/orm/panache/kotlin/deployment/KotlinPanacheResourceProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ private void processEntities(CombinedIndexBuildItem index,
165165

166166
panacheEntityToPersistenceUnit.put(entityName, selectedPersistenceUnits.get(0));
167167
}
168-
recorder.setEntityToPersistenceUnit(panacheEntityToPersistenceUnit, incomplete);
168+
// This is called even if there are no entity types, so that Panache gets properly initialized.
169+
recorder.addEntityTypesToPersistenceUnit(panacheEntityToPersistenceUnit, incomplete);
169170
}
170171

171172
private void processRepositories(CombinedIndexBuildItem index,

extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/PanacheKotlinHibernateOrmRecorder.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import io.quarkus.runtime.annotations.Recorder
55

66
@Recorder
77
open class PanacheKotlinHibernateOrmRecorder {
8-
open fun setEntityToPersistenceUnit(
8+
open fun addEntityTypesToPersistenceUnit(
99
entityToPersistenceUnit: Map<String?, String?>?,
1010
incomplete: Boolean,
1111
) {
12-
AbstractJpaOperations.setEntityToPersistenceUnit(entityToPersistenceUnit, incomplete)
12+
AbstractJpaOperations.addEntityTypesToPersistenceUnit(entityToPersistenceUnit, incomplete)
1313
}
1414
}

extensions/panache/hibernate-orm-panache/deployment/src/main/java/io/quarkus/hibernate/orm/panache/deployment/PanacheHibernateResourceProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ void recordEntityToPersistenceUnit(Optional<JpaModelPersistenceUnitMappingBuildI
141141
for (EntityToPersistenceUnitBuildItem item : items) {
142142
map.put(item.getEntityClass(), item.getPersistenceUnitName());
143143
}
144-
recorder.setEntityToPersistenceUnit(map,
144+
// This is called even if there are no entity types, so that Panache gets properly initialized.
145+
recorder.addEntityTypesToPersistenceUnit(map,
145146
jpaModelPersistenceUnitMapping.map(JpaModelPersistenceUnitMappingBuildItem::isIncomplete)
146147
// This happens if there is no persistence unit, in which case we definitely know this metadata is complete.
147148
.orElse(false));

extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/PanacheHibernateOrmRecorder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
@Recorder
99
public class PanacheHibernateOrmRecorder {
10-
public void setEntityToPersistenceUnit(Map<String, String> entityToPersistenceUnit, boolean incomplete) {
11-
AbstractJpaOperations.setEntityToPersistenceUnit(entityToPersistenceUnit, incomplete);
10+
public void addEntityTypesToPersistenceUnit(Map<String, String> entityToPersistenceUnit, boolean incomplete) {
11+
AbstractJpaOperations.addEntityTypesToPersistenceUnit(entityToPersistenceUnit, incomplete);
1212
}
1313
}

extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/AbstractJpaOperations.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.ArrayList;
66
import java.util.Arrays;
77
import java.util.Collections;
8+
import java.util.HashMap;
89
import java.util.List;
910
import java.util.Map;
1011
import java.util.Map.Entry;
@@ -23,10 +24,16 @@
2324
import io.smallrye.mutiny.Uni;
2425

2526
public abstract class AbstractJpaOperations<PanacheQueryType> {
26-
private static volatile Map<String, String> entityToPersistenceUnit = Collections.emptyMap();
27-
28-
public static void setEntityToPersistenceUnit(Map<String, String> map) {
29-
entityToPersistenceUnit = Collections.unmodifiableMap(map);
27+
private static final Map<String, String> entityToPersistenceUnit = new HashMap<>();
28+
29+
// Putting synchronized here because fields involved were marked as volatile initially,
30+
// so I expect recorders can be called concurrently?
31+
public static void addEntityTypesToPersistenceUnit(Map<String, String> map) {
32+
// Note: this may be called multiple times if an app uses both Java and Kotlin.
33+
// We don't really test what happens if entities are defined both in Java and Kotlin at the moment,
34+
// so we mostly care about the case where this gets called once with an empty map, and once with a non-empty map:
35+
// in that case, we don't want the empty map to erase the other one.
36+
entityToPersistenceUnit.putAll(map);
3037
}
3138

3239
// FIXME: make it configurable?

extensions/panache/hibernate-reactive-panache-kotlin/deployment/src/main/java/io/quarkus/hibernate/reactive/panache/kotlin/deployment/HibernateReactivePanacheKotlinProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ private void processEntities(CombinedIndexBuildItem index, BuildProducer<Bytecod
139139

140140
panacheEntityToPersistenceUnit.put(entityName, selectedPersistenceUnits.get(0));
141141
}
142-
recorder.setEntityToPersistenceUnit(panacheEntityToPersistenceUnit, incomplete);
142+
// This is called even if there are no entity types, so that Panache gets properly initialized.
143+
recorder.addEntityTypesToPersistenceUnit(panacheEntityToPersistenceUnit, incomplete);
143144
}
144145

145146
private void processCompanions(CombinedIndexBuildItem index, BuildProducer<BytecodeTransformerBuildItem> transformers,

extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/PanacheKotlinReactiveRecorder.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import io.quarkus.runtime.annotations.Recorder
55

66
@Recorder
77
open class PanacheKotlinReactiveRecorder {
8-
open fun setEntityToPersistenceUnit(
8+
open fun addEntityTypesToPersistenceUnit(
99
entityToPersistenceUnit: Map<String?, String?>?,
1010
incomplete: Boolean,
1111
) {
12-
AbstractJpaOperations.setEntityToPersistenceUnit(entityToPersistenceUnit)
12+
AbstractJpaOperations.addEntityTypesToPersistenceUnit(entityToPersistenceUnit)
1313
}
1414
}

extensions/panache/hibernate-reactive-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/panache/deployment/PanacheHibernateResourceProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ void recordEntityToPersistenceUnit(List<EntityToPersistenceUnitBuildItem> items,
160160
for (EntityToPersistenceUnitBuildItem item : items) {
161161
map.put(item.getEntityClass(), item.getPersistenceUnitName());
162162
}
163-
recorder.setEntityToPersistenceUnit(map);
163+
// This is called even if there are no entity types, so that Panache gets properly initialized.
164+
recorder.addEntityTypesToPersistenceUnit(map);
164165
}
165166

166167
@BuildStep

extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/PanacheHibernateReactiveRecorder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
@Recorder
99
public class PanacheHibernateReactiveRecorder {
10-
public void setEntityToPersistenceUnit(Map<String, String> entityToPersistenceUnit) {
11-
AbstractJpaOperations.setEntityToPersistenceUnit(entityToPersistenceUnit);
10+
public void addEntityTypesToPersistenceUnit(Map<String, String> entityToPersistenceUnit) {
11+
AbstractJpaOperations.addEntityTypesToPersistenceUnit(entityToPersistenceUnit);
1212
}
1313
}

0 commit comments

Comments
 (0)