Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9bce058

Browse files
committed
HHH-19739 Don't unintentionally deduplicate attributes by property name
1 parent 7cbb301 commit 9bce058

File tree

6 files changed

+237
-48
lines changed

6 files changed

+237
-48
lines changed

‎hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BytecodeProviderImpl.java

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ public ReflectionOptimizer getReflectionOptimizer(
163163
final Method[] getters = new Method[getterNames.length];
164164
final Method[] setters = new Method[setterNames.length];
165165
try {
166-
findAccessors( clazz, getterNames, setterNames, types, getters, setters );
166+
unwrapPropertyInfos( clazz, getterNames, setterNames, types, getters, setters );
167167
}
168168
catch (InvalidPropertyAccessorException ex) {
169169
LOG.unableToGenerateReflectionOptimizer( clazz.getName(), ex.getMessage() );
@@ -198,6 +198,18 @@ public ReflectionOptimizer getReflectionOptimizer(
198198

199199
@Override
200200
public @Nullable ReflectionOptimizer getReflectionOptimizer(Class<?> clazz, Map<String, PropertyAccess> propertyAccessMap) {
201+
final PropertyInfo[] propertyInfos = new PropertyInfo[propertyAccessMap.size()];
202+
int i = 0;
203+
for ( Map.Entry<String, PropertyAccess> entry : propertyAccessMap.entrySet() ) {
204+
final String propertyName = entry.getKey();
205+
final PropertyAccess propertyAccess = entry.getValue();
206+
propertyInfos[i++] = new PropertyInfo( propertyName, propertyAccess );
207+
}
208+
return getReflectionOptimizer( clazz, propertyInfos );
209+
}
210+
211+
@Override
212+
public @Nullable ReflectionOptimizer getReflectionOptimizer(Class<?> clazz, PropertyInfo[] propertyInfos) {
201213
final Class<?> fastClass;
202214
if ( !clazz.isInterface() && !Modifier.isAbstract( clazz.getModifiers() ) ) {
203215
// we only provide a fast class instantiator if the class can be instantiated
@@ -222,17 +234,17 @@ public ReflectionOptimizer getReflectionOptimizer(
222234
fastClass = null;
223235
}
224236

225-
final Member[] getters = new Member[propertyAccessMap.size()];
226-
final Member[] setters = new Member[propertyAccessMap.size()];
237+
final Member[] getters = new Member[propertyInfos.length];
238+
final Member[] setters = new Member[propertyInfos.length];
239+
final String[] propertyNames = new String[propertyInfos.length];
227240
try {
228-
findAccessors( clazz, propertyAccessMap, getters, setters );
241+
unwrapPropertyInfos( clazz, propertyInfos, propertyNames, getters, setters );
229242
}
230243
catch (InvalidPropertyAccessorException ex) {
231244
LOG.unableToGenerateReflectionOptimizer( clazz.getName(), ex.getMessage() );
232245
return null;
233246
}
234247

235-
final String[] propertyNames = propertyAccessMap.keySet().toArray( new String[0] );
236248
final Class<?> superClass = determineAccessOptimizerSuperClass( clazz, propertyNames, getters, setters );
237249

238250
final String className = clazz.getName() + "$" + OPTIMIZER_PROXY_NAMING_SUFFIX + encodeName( propertyNames, getters, setters );
@@ -1196,7 +1208,7 @@ else if ( setterMember instanceof Field field ) {
11961208
}
11971209
}
11981210

1199-
private static void findAccessors(
1211+
private static void unwrapPropertyInfos(
12001212
Class<?> clazz,
12011213
String[] getterNames,
12021214
String[] setterNames,
@@ -1238,14 +1250,17 @@ else if ( Modifier.isPrivate( setters[i].getModifiers() ) ) {
12381250
}
12391251
}
12401252

1241-
private static void findAccessors(
1253+
private static void unwrapPropertyInfos(
12421254
Class<?> clazz,
1243-
Map<String, PropertyAccess> propertyAccessMap,
1255+
PropertyInfo[] propertyInfos,
1256+
String[] propertyNames,
12441257
Member[] getters,
12451258
Member[] setters) {
12461259
int i = 0;
1247-
for ( Map.Entry<String, PropertyAccess> entry : propertyAccessMap.entrySet() ) {
1248-
final PropertyAccess propertyAccess = entry.getValue();
1260+
for ( PropertyInfo propertyInfo : propertyInfos ) {
1261+
final String propertyName = propertyInfo.propertyName();
1262+
final PropertyAccess propertyAccess = propertyInfo.propertyAccess();
1263+
propertyNames[i] = propertyName;
12491264
if ( propertyAccess instanceof PropertyAccessEmbeddedImpl ) {
12501265
getters[i] = EMBEDDED_MEMBER;
12511266
setters[i] = EMBEDDED_MEMBER;
@@ -1254,14 +1269,14 @@ private static void findAccessors(
12541269
}
12551270
final Getter getter = propertyAccess.getGetter();
12561271
if ( getter == null ) {
1257-
throw new InvalidPropertyAccessorException( "invalid getter for property [" + entry.getKey() + "]" );
1272+
throw new InvalidPropertyAccessorException( "invalid getter for property [" + propertyName + "]" );
12581273
}
12591274
final Setter setter = propertyAccess.getSetter();
12601275
if ( setter == null ) {
12611276
throw new InvalidPropertyAccessorException(
12621277
String.format(
12631278
"cannot find a setter for [%s] on type [%s]",
1264-
entry.getKey(),
1279+
propertyName,
12651280
clazz.getName()
12661281
)
12671282
);
@@ -1277,7 +1292,7 @@ else if ( getter instanceof GetterFieldImpl getterField ) {
12771292
throw new InvalidPropertyAccessorException(
12781293
String.format(
12791294
"cannot find a getter for [%s] on type [%s]",
1280-
entry.getKey(),
1295+
propertyName,
12811296
clazz.getName()
12821297
)
12831298
);
@@ -1296,7 +1311,7 @@ else if ( setter instanceof SetterFieldImpl setterField ) {
12961311
throw new InvalidPropertyAccessorException(
12971312
String.format(
12981313
"cannot find a setter for [%s] on type [%s]",
1299-
entry.getKey(),
1314+
propertyName,
13001315
clazz.getName()
13011316
)
13021317
);

‎hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeProvider.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.bytecode.spi;
66

7+
import java.util.HashMap;
78
import java.util.Map;
89

910
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
@@ -55,9 +56,35 @@ public interface BytecodeProvider extends Service {
5556
* @param clazz The class to be reflected upon.
5657
* @param propertyAccessMap The ordered property access map
5758
* @return The reflection optimization delegate.
59+
* @deprecated Use {@link #getReflectionOptimizer(Class, PropertyInfo[])} instead
5860
*/
61+
@Deprecated(forRemoval = true)
5962
@Nullable ReflectionOptimizer getReflectionOptimizer(Class<?> clazz, Map<String, PropertyAccess> propertyAccessMap);
6063

64+
/**
65+
* Retrieve the ReflectionOptimizer delegate for this provider
66+
* capable of generating reflection optimization components.
67+
*
68+
* @param clazz The class to be reflected upon.
69+
* @param propertyInfos The ordered property infos
70+
* @return The reflection optimization delegate.
71+
*/
72+
default @Nullable ReflectionOptimizer getReflectionOptimizer(Class<?> clazz, PropertyInfo[] propertyInfos) {
73+
final Map<String, PropertyAccess> map = new HashMap<>();
74+
for ( int i = 0; i < propertyInfos.length; i++ ) {
75+
map.put( propertyInfos[i].propertyName(), propertyInfos[i].propertyAccess() );
76+
}
77+
return getReflectionOptimizer( clazz, map );
78+
}
79+
80+
/**
81+
* Information about a property of a class, needed for generating reflection optimizers.
82+
*
83+
* @param propertyName The name of the property
84+
* @param propertyAccess The property access
85+
*/
86+
record PropertyInfo(String propertyName, PropertyAccess propertyAccess) {}
87+
6188
/**
6289
* Returns a byte code enhancer that implements the enhancements described in the supplied enhancement context.
6390
*

‎hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableRepresentationStrategyPojo.java

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

77
import java.util.Collection;
88
import java.util.HashMap;
9-
import java.util.LinkedHashMap;
9+
import java.util.List;
1010
import java.util.Locale;
1111
import java.util.Map;
1212
import java.util.function.Supplier;
@@ -197,15 +197,15 @@ private static ReflectionOptimizer buildReflectionOptimizer(
197197
&& bootDescriptor.getCustomInstantiator() == null
198198
&& bootDescriptor.getInstantiator() == null
199199
&& !bootDescriptor.isPolymorphic() ) {
200-
final Map<String, PropertyAccess> propertyAccessMap = newLinkedHashMap<>();
201-
inti = 0;
202-
for ( Propertyproperty : bootDescriptor.getProperties() ) {
203-
propertyAccessMap.put( property.getName(), propertyAccesses[i] );
204-
i++;
200+
final List<Property> properties = bootDescriptor.getProperties();
201+
finalBytecodeProvider.PropertyInfo[] propertyInfos = newBytecodeProvider.PropertyInfo[properties.size()];
202+
for ( inti = 0; i < properties.size(); i++ ) {
203+
finalPropertyproperty = properties.get( i );
204+
propertyInfos[i] = newBytecodeProvider.PropertyInfo( property.getName(), propertyAccesses[i] );
205205
}
206206
return creationContext.getServiceRegistry()
207207
.requireService( BytecodeProvider.class )
208-
.getReflectionOptimizer( bootDescriptor.getComponentClass(), propertyAccessMap );
208+
.getReflectionOptimizer( bootDescriptor.getComponentClass(), propertyInfos );
209209
}
210210
else {
211211
return null;

‎hibernate-core/src/main/java/org/hibernate/metamodel/internal/EntityRepresentationStrategyPojoStandard.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
package org.hibernate.metamodel.internal;
66

77
import java.lang.reflect.Method;
8-
import java.util.LinkedHashMap;
8+
import java.util.HashMap;
99
import java.util.LinkedHashSet;
10+
import java.util.List;
1011
import java.util.Locale;
1112
import java.util.Map;
1213
import java.util.Set;
@@ -59,6 +60,7 @@ public class EntityRepresentationStrategyPojoStandard implements EntityRepresent
5960

6061
private final String identifierPropertyName;
6162
private final PropertyAccess identifierPropertyAccess;
63+
private final BytecodeProvider.PropertyInfo[] propertyInfos;
6264
private final Map<String, PropertyAccess> propertyAccessMap;
6365
private final EmbeddableRepresentationStrategyPojo mapsIdRepresentationStrategy;
6466

@@ -119,7 +121,8 @@ public EntityRepresentationStrategyPojoStandard(
119121
creationContext
120122
);
121123

122-
propertyAccessMap = buildPropertyAccessMap( bootDescriptor );
124+
propertyInfos = buildPropertyInfos( bootDescriptor );
125+
propertyAccessMap = buildPropertyAccessMap( propertyInfos );
123126
reflectionOptimizer = resolveReflectionOptimizer( bytecodeProvider );
124127

125128
instantiator = determineInstantiator( bootDescriptor, runtimeDescriptor.getEntityMetamodel() );
@@ -155,12 +158,22 @@ private ProxyFactory resolveProxyFactory(
155158
}
156159
}
157160

158-
private Map<String, PropertyAccess> buildPropertyAccessMap(PersistentClassbootDescriptor) {
159-
final Map<String, PropertyAccess> propertyAccessMap = new LinkedHashMap<>();
160-
for ( Propertyproperty : bootDescriptor.getPropertyClosure() ) {
161-
propertyAccessMap.put( property.getName(), makePropertyAccess( property) );
161+
private Map<String, PropertyAccess> buildPropertyAccessMap(BytecodeProvider.PropertyInfo[] propertyInfos) {
162+
final Map<String, PropertyAccess> map = new HashMap<>(propertyInfos.length);
163+
for ( BytecodeProvider.PropertyInfopropertyInfo : propertyInfos ) {
164+
map.put( propertyInfo.propertyName(), propertyInfo.propertyAccess() );
162165
}
163-
return propertyAccessMap;
166+
return map;
167+
}
168+
169+
private BytecodeProvider.PropertyInfo[] buildPropertyInfos(PersistentClass bootDescriptor) {
170+
final List<Property> properties = bootDescriptor.getPropertyClosure();
171+
final BytecodeProvider.PropertyInfo[] propertyInfos = new BytecodeProvider.PropertyInfo[properties.size()];
172+
for ( int i = 0; i < properties.size(); i++ ) {
173+
final Property property = properties.get( i );
174+
propertyInfos[i] = new BytecodeProvider.PropertyInfo( property.getName(), makePropertyAccess( property ) );
175+
}
176+
return propertyInfos;
164177
}
165178

166179
private EntityInstantiator determineInstantiator(PersistentClass bootDescriptor, EntityMetamodel entityMetamodel) {
@@ -303,7 +316,7 @@ private static ProxyFactory instantiateProxyFactory(
303316
}
304317

305318
private ReflectionOptimizer resolveReflectionOptimizer(BytecodeProvider bytecodeProvider) {
306-
return bytecodeProvider.getReflectionOptimizer( mappedJtd.getJavaTypeClass(), propertyAccessMap );
319+
return bytecodeProvider.getReflectionOptimizer( mappedJtd.getJavaTypeClass(), propertyInfos );
307320
}
308321

309322
private PropertyAccess makePropertyAccess(Property bootAttributeDescriptor) {

‎hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4822,26 +4822,27 @@ private void inheritSupertypeSpecialAttributeMappings() {
48224822
final NonIdentifierAttribute[] properties = entityMetamodel.getProperties();
48234823
final AttributeMappingsMap.Builder mappingsBuilder = AttributeMappingsMap.builder();
48244824
int fetchableIndex = getFetchableIndexOffset();
4825-
for ( inti = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
4826-
final NonIdentifierAttributeruntimeAttributeDefinition = properties[i];
4827-
finalStringattributeName = runtimeAttributeDefinition.getName();
4828-
finalPropertybootProperty = bootEntityDescriptor.getProperty( attributeName );
4829-
if ( superMappingType == null
4830-
|| superMappingType.findAttributeMapping( bootProperty.getName() ) == null ) {
4831-
mappingsBuilder.put(
4832-
attributeName,
4833-
generateNonIdAttributeMapping(
4834-
runtimeAttributeDefinition,
4835-
bootProperty,
4836-
stateArrayPosition++,
4837-
fetchableIndex++,
4838-
creationProcess
4839-
)
4840-
);
4841-
}
4842-
declaredAttributeMappings = mappingsBuilder.build();
4843-
// otherwise, it's defined on the supertype, skip it here
4825+
// For every property that is "owned" by this persistent class, create a declared attribute mapping
4826+
final List<Property> bootProperties = bootEntityDescriptor.getProperties();
4827+
// EntityMetamodel uses getPropertyClosure(), which includes the properties of the super type,
4828+
// so use that property span as offset when indexing into the EntityMetamodel NonIdentifierAttribute[]
4829+
finalintsuperclassPropertiesOffset = superMappingType == null ? 0
4830+
: superMappingType.getEntityPersister().getEntityMetamodel().getPropertySpan();
4831+
for ( inti = 0; i < bootProperties.size(); i++ ) {
4832+
finalPropertybootProperty = bootProperties.get( i );
4833+
assertproperties[superclassPropertiesOffset + i].getName().equals( bootProperty.getName() );
4834+
mappingsBuilder.put(
4835+
bootProperty.getName(),
4836+
generateNonIdAttributeMapping(
4837+
properties[superclassPropertiesOffset + i],
4838+
bootProperty,
4839+
stateArrayPosition++,
4840+
fetchableIndex++,
4841+
creationProcess
4842+
)
4843+
);
48444844
}
4845+
declaredAttributeMappings = mappingsBuilder.build();
48454846
}
48464847

48474848
private static BeforeExecutionGenerator createVersionGenerator

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /