Skip to content

Commit dba11ed

Browse files
committed
HHH-17282 Introduce a specialized Map for NavigablePath to Initializer
1 parent a71df55 commit dba11ed

File tree

3 files changed

+96
-25
lines changed

3 files changed

+96
-25
lines changed

hibernate-core/src/main/java/org/hibernate/sql/results/internal/InitializersList.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import java.util.ArrayList;
1010
import java.util.Arrays;
1111
import java.util.List;
12-
import java.util.Map;
1312

1413
import org.hibernate.spi.NavigablePath;
1514
import org.hibernate.sql.exec.spi.ExecutionContext;
@@ -36,14 +35,14 @@ public final class InitializersList {
3635
private final Initializer[] sortedNonCollectionsFirst;
3736
private final Initializer[] sortedForResolveInstance;
3837
private final boolean hasCollectionInitializers;
39-
private final Map<NavigablePath, Initializer> initializerMap;
38+
private final NavigablePathMapToInitializer initializerMap;
4039

4140
private InitializersList(
4241
Initializer[] initializers,
4342
Initializer[] sortedNonCollectionsFirst,
4443
Initializer[] sortedForResolveInstance,
4544
boolean hasCollectionInitializers,
46-
Map<NavigablePath, Initializer> initializerMap) {
45+
NavigablePathMapToInitializer initializerMap) {
4746
this.initializers = initializers;
4847
this.sortedNonCollectionsFirst = sortedNonCollectionsFirst;
4948
this.sortedForResolveInstance = sortedForResolveInstance;
@@ -123,7 +122,7 @@ private static boolean initializeFirst(final Initializer initializer) {
123122
&& !(initializer instanceof AbstractBatchEntitySelectFetchInitializer );
124123
}
125124

126-
InitializersList build(final Map<NavigablePath, Initializer> initializerMap) {
125+
InitializersList build(final NavigablePathMapToInitializer initializerMap) {
127126
final int size = initializers.size();
128127
final Initializer[] sortedNonCollectionsFirst = new Initializer[size];
129128
final Initializer[] sortedForResolveInstance = new Initializer[size];
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.sql.results.internal;
8+
9+
import java.util.HashMap;
10+
import java.util.Map;
11+
import java.util.Objects;
12+
13+
import org.hibernate.spi.NavigablePath;
14+
import org.hibernate.sql.results.ResultsLogger;
15+
import org.hibernate.sql.results.graph.Initializer;
16+
17+
18+
/**
19+
* This is in all practical terms a {@code Map<NavigablePath, Initializer>}
20+
* but wrapping an HashMap so to keep the client code readable as we need
21+
* to:
22+
* a) have a way to log all initializers
23+
* b) prevent type pollution from happening on Initializer retrieval
24+
* I also consider it good practice to only expose the minimal set of
25+
* operations the client actually needs.
26+
*/
27+
public final class NavigablePathMapToInitializer {
28+
29+
private HashMap<NavigablePath, InitializerHolder> map = null;
30+
31+
public Initializer get(final NavigablePath navigablePath) {
32+
if ( map != null && navigablePath != null ) {
33+
final InitializerHolder h = map.get( navigablePath );
34+
if ( h != null ) {
35+
return h.initializer;
36+
}
37+
}
38+
return null;
39+
}
40+
41+
public void put(final NavigablePath navigablePath, final Initializer initializer) {
42+
Objects.requireNonNull( navigablePath );
43+
Objects.requireNonNull( initializer );
44+
if ( map == null ) {
45+
map = new HashMap<>();
46+
}
47+
map.put( navigablePath, new InitializerHolder( initializer ) );
48+
}
49+
50+
public void logInitializers() {
51+
ResultsLogger logger = ResultsLogger.RESULTS_MESSAGE_LOGGER;
52+
if ( !logger.isDebugEnabled() ) {
53+
return;
54+
}
55+
if ( map == null ) {
56+
logger.debug( "Initializer list is empty" );
57+
}
58+
else {
59+
//Apparently we want to log this on multiple lines (existing code did this - not sure if that was by design):
60+
//using a StringBuilder to avoid potentially interleaving the logs from different operations.
61+
final StringBuilder sb = new StringBuilder( "Initializer list:\n" );
62+
for ( Map.Entry<NavigablePath, InitializerHolder> holderEntry : map.entrySet() ) {
63+
final NavigablePath navigablePath = holderEntry.getKey();
64+
final Initializer initializer = holderEntry.getValue().initializer;
65+
String formatted = String.format(
66+
" %s -> %s@%s (%s)",
67+
navigablePath,
68+
initializer,
69+
initializer.hashCode(),
70+
initializer.getInitializedPart()
71+
);
72+
sb.append( '\t' );
73+
sb.append( formatted );
74+
sb.append( '\n' );
75+
}
76+
logger.debug( sb.toString() );
77+
}
78+
}
79+
80+
//Custom holder to avoid type pollution:
81+
//we make the type explicit, and this is a concrete class.
82+
private static final class InitializerHolder {
83+
final Initializer initializer;
84+
85+
private InitializerHolder(final Initializer init) {
86+
this.initializer = init;
87+
}
88+
}
89+
90+
}

hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
*/
77
package org.hibernate.sql.results.internal;
88

9-
import java.util.LinkedHashMap;
109
import java.util.List;
11-
import java.util.Map;
1210
import java.util.function.Supplier;
1311

1412
import org.hibernate.CacheMode;
@@ -70,7 +68,8 @@ public static <R> RowReader<R> createRowReader(
7068
JdbcValuesMapping jdbcValuesMapping) {
7169
final SessionFactoryImplementor sessionFactory = executionContext.getSession().getFactory();
7270

73-
final Map<NavigablePath, Initializer> initializerMap = new LinkedHashMap<>();
71+
//custom Map<NavigablePath, Initializer>
72+
final NavigablePathMapToInitializer initializerMap = new NavigablePathMapToInitializer();
7473
final InitializersList.Builder initializersBuilder = new InitializersList.Builder();
7574

7675
final List<DomainResultAssembler<?>> assemblers = jdbcValuesMapping.resolveAssemblers(
@@ -133,30 +132,13 @@ public SqlAstCreationContext getSqlAstCreationContext() {
133132
}
134133
);
135134

136-
logInitializers( initializerMap );
135+
initializerMap.logInitializers();
137136

138137
final InitializersList initializersList = initializersBuilder.build( initializerMap );
139138

140139
return new StandardRowReader<>( assemblers, initializersList, rowTransformer, transformedResultJavaType );
141140
}
142141

143-
private static void logInitializers(Map<NavigablePath, Initializer> initializerMap) {
144-
if ( ! ResultsLogger.RESULTS_MESSAGE_LOGGER.isDebugEnabled() ) {
145-
return;
146-
}
147-
148-
ResultsLogger.RESULTS_MESSAGE_LOGGER.debug( "Initializer list" );
149-
initializerMap.forEach( (navigablePath, initializer) -> {
150-
ResultsLogger.RESULTS_MESSAGE_LOGGER.debugf(
151-
" %s -> %s@%s (%s)",
152-
navigablePath,
153-
initializer,
154-
initializer.hashCode(),
155-
initializer.getInitializedPart()
156-
);
157-
} );
158-
}
159-
160142
public static void finalizeCollectionLoading(
161143
PersistenceContext persistenceContext,
162144
CollectionPersister collectionDescriptor,

0 commit comments

Comments
 (0)