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

HHH-19739 Don't unintentionally deduplicate attributes by property name #10824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
beikov wants to merge 1 commit into hibernate:7.1
base: 7.1
Choose a base branch
Loading
from beikov:HHH-19739-7.1
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public ReflectionOptimizer getReflectionOptimizer(
final Method[] getters = new Method[getterNames.length];
final Method[] setters = new Method[setterNames.length];
try {
findAccessors( clazz, getterNames, setterNames, types, getters, setters );
unwrapPropertyInfos( clazz, getterNames, setterNames, types, getters, setters );
}
catch (InvalidPropertyAccessorException ex) {
LOG.unableToGenerateReflectionOptimizer( clazz.getName(), ex.getMessage() );
Expand Down Expand Up @@ -198,6 +198,18 @@ public ReflectionOptimizer getReflectionOptimizer(

@Override
public @Nullable ReflectionOptimizer getReflectionOptimizer(Class<?> clazz, Map<String, PropertyAccess> propertyAccessMap) {
final PropertyInfo[] propertyInfos = new PropertyInfo[propertyAccessMap.size()];
int i = 0;
for ( Map.Entry<String, PropertyAccess> entry : propertyAccessMap.entrySet() ) {
final String propertyName = entry.getKey();
final PropertyAccess propertyAccess = entry.getValue();
propertyInfos[i++] = new PropertyInfo( propertyName, propertyAccess );
}
return getReflectionOptimizer( clazz, propertyInfos );
}

@Override
public @Nullable ReflectionOptimizer getReflectionOptimizer(Class<?> clazz, PropertyInfo[] propertyInfos) {
final Class<?> fastClass;
if ( !clazz.isInterface() && !Modifier.isAbstract( clazz.getModifiers() ) ) {
// we only provide a fast class instantiator if the class can be instantiated
Expand All @@ -222,17 +234,17 @@ public ReflectionOptimizer getReflectionOptimizer(
fastClass = null;
}

final Member[] getters = new Member[propertyAccessMap.size()];
final Member[] setters = new Member[propertyAccessMap.size()];
final Member[] getters = new Member[propertyInfos.length];
final Member[] setters = new Member[propertyInfos.length];
final String[] propertyNames = new String[propertyInfos.length];
try {
findAccessors( clazz, propertyAccessMap, getters, setters );
unwrapPropertyInfos( clazz, propertyInfos, propertyNames, getters, setters );
}
catch (InvalidPropertyAccessorException ex) {
LOG.unableToGenerateReflectionOptimizer( clazz.getName(), ex.getMessage() );
return null;
}

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

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

private static void findAccessors(
private static void unwrapPropertyInfos(
Class<?> clazz,
String[] getterNames,
String[] setterNames,
Expand Down Expand Up @@ -1238,14 +1250,17 @@ else if ( Modifier.isPrivate( setters[i].getModifiers() ) ) {
}
}

private static void findAccessors(
private static void unwrapPropertyInfos(
Class<?> clazz,
Map<String, PropertyAccess> propertyAccessMap,
PropertyInfo[] propertyInfos,
String[] propertyNames,
Member[] getters,
Member[] setters) {
int i = 0;
for ( Map.Entry<String, PropertyAccess> entry : propertyAccessMap.entrySet() ) {
final PropertyAccess propertyAccess = entry.getValue();
for ( PropertyInfo propertyInfo : propertyInfos ) {
final String propertyName = propertyInfo.propertyName();
final PropertyAccess propertyAccess = propertyInfo.propertyAccess();
propertyNames[i] = propertyName;
if ( propertyAccess instanceof PropertyAccessEmbeddedImpl ) {
getters[i] = EMBEDDED_MEMBER;
setters[i] = EMBEDDED_MEMBER;
Expand All @@ -1254,14 +1269,14 @@ private static void findAccessors(
}
final Getter getter = propertyAccess.getGetter();
if ( getter == null ) {
throw new InvalidPropertyAccessorException( "invalid getter for property [" + entry.getKey() + "]" );
throw new InvalidPropertyAccessorException( "invalid getter for property [" + propertyName + "]" );
}
final Setter setter = propertyAccess.getSetter();
if ( setter == null ) {
throw new InvalidPropertyAccessorException(
String.format(
"cannot find a setter for [%s] on type [%s]",
entry.getKey(),
propertyName,
clazz.getName()
)
);
Expand All @@ -1277,7 +1292,7 @@ else if ( getter instanceof GetterFieldImpl getterField ) {
throw new InvalidPropertyAccessorException(
String.format(
"cannot find a getter for [%s] on type [%s]",
entry.getKey(),
propertyName,
clazz.getName()
)
);
Expand All @@ -1296,7 +1311,7 @@ else if ( setter instanceof SetterFieldImpl setterField ) {
throw new InvalidPropertyAccessorException(
String.format(
"cannot find a setter for [%s] on type [%s]",
entry.getKey(),
propertyName,
clazz.getName()
)
);
Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package org.hibernate.bytecode.spi;

import java.util.HashMap;
import java.util.Map;

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

/**
* Retrieve the ReflectionOptimizer delegate for this provider
* capable of generating reflection optimization components.
*
* @param clazz The class to be reflected upon.
* @param propertyInfos The ordered property infos
* @return The reflection optimization delegate.
*/
default @Nullable ReflectionOptimizer getReflectionOptimizer(Class<?> clazz, PropertyInfo[] propertyInfos) {
final Map<String, PropertyAccess> map = new HashMap<>();
for ( int i = 0; i < propertyInfos.length; i++ ) {
map.put( propertyInfos[i].propertyName(), propertyInfos[i].propertyAccess() );
}
return getReflectionOptimizer( clazz, map );
}

/**
* Information about a property of a class, needed for generating reflection optimizers.
*
* @param propertyName The name of the property
* @param propertyAccess The property access
*/
record PropertyInfo(String propertyName, PropertyAccess propertyAccess) {}

/**
* Returns a byte code enhancer that implements the enhancements described in the supplied enhancement context.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
Expand Down Expand Up @@ -197,15 +197,15 @@ private static ReflectionOptimizer buildReflectionOptimizer(
&& bootDescriptor.getCustomInstantiator() == null
&& bootDescriptor.getInstantiator() == null
&& !bootDescriptor.isPolymorphic() ) {
final Map<String, PropertyAccess> propertyAccessMap = new LinkedHashMap<>();
int i = 0;
for ( Property property : bootDescriptor.getProperties() ) {
propertyAccessMap.put( property.getName(), propertyAccesses[i] );
i++;
final List<Property> properties = bootDescriptor.getProperties();
final BytecodeProvider.PropertyInfo[] propertyInfos = new BytecodeProvider.PropertyInfo[properties.size()];
for ( int i = 0; i < properties.size(); i++ ) {
final Property property = properties.get( i );
propertyInfos[i] = new BytecodeProvider.PropertyInfo( property.getName(), propertyAccesses[i] );
}
return creationContext.getServiceRegistry()
.requireService( BytecodeProvider.class )
.getReflectionOptimizer( bootDescriptor.getComponentClass(), propertyAccessMap );
.getReflectionOptimizer( bootDescriptor.getComponentClass(), propertyInfos );
}
else {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
package org.hibernate.metamodel.internal;

import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -59,6 +60,7 @@ public class EntityRepresentationStrategyPojoStandard implements EntityRepresent

private final String identifierPropertyName;
private final PropertyAccess identifierPropertyAccess;
private final BytecodeProvider.PropertyInfo[] propertyInfos;
private final Map<String, PropertyAccess> propertyAccessMap;
private final EmbeddableRepresentationStrategyPojo mapsIdRepresentationStrategy;

Expand Down Expand Up @@ -119,7 +121,8 @@ public EntityRepresentationStrategyPojoStandard(
creationContext
);

propertyAccessMap = buildPropertyAccessMap( bootDescriptor );
propertyInfos = buildPropertyInfos( bootDescriptor );
propertyAccessMap = buildPropertyAccessMap( propertyInfos );
reflectionOptimizer = resolveReflectionOptimizer( bytecodeProvider );

instantiator = determineInstantiator( bootDescriptor, runtimeDescriptor.getEntityMetamodel() );
Expand Down Expand Up @@ -155,12 +158,22 @@ private ProxyFactory resolveProxyFactory(
}
}

private Map<String, PropertyAccess> buildPropertyAccessMap(PersistentClass bootDescriptor) {
final Map<String, PropertyAccess> propertyAccessMap = new LinkedHashMap<>();
for ( Property property : bootDescriptor.getPropertyClosure() ) {
propertyAccessMap.put( property.getName(), makePropertyAccess( property ) );
private Map<String, PropertyAccess> buildPropertyAccessMap(BytecodeProvider.PropertyInfo[] propertyInfos) {
final Map<String, PropertyAccess> map = new HashMap<>( propertyInfos.length );
for ( BytecodeProvider.PropertyInfo propertyInfo : propertyInfos ) {
map.put( propertyInfo.propertyName(), propertyInfo.propertyAccess() );
}
return propertyAccessMap;
return map;
}

private BytecodeProvider.PropertyInfo[] buildPropertyInfos(PersistentClass bootDescriptor) {
final List<Property> properties = bootDescriptor.getPropertyClosure();
final BytecodeProvider.PropertyInfo[] propertyInfos = new BytecodeProvider.PropertyInfo[properties.size()];
for ( int i = 0; i < properties.size(); i++ ) {
final Property property = properties.get( i );
propertyInfos[i] = new BytecodeProvider.PropertyInfo( property.getName(), makePropertyAccess( property ) );
}
return propertyInfos;
}

private EntityInstantiator determineInstantiator(PersistentClass bootDescriptor, EntityMetamodel entityMetamodel) {
Expand Down Expand Up @@ -303,11 +316,11 @@ private static ProxyFactory instantiateProxyFactory(
}

private ReflectionOptimizer resolveReflectionOptimizer(BytecodeProvider bytecodeProvider) {
return bytecodeProvider.getReflectionOptimizer( mappedJtd.getJavaTypeClass(), propertyAccessMap );
return bytecodeProvider.getReflectionOptimizer( mappedJtd.getJavaTypeClass(), propertyInfos );
}

private PropertyAccess makePropertyAccess(Property bootAttributeDescriptor) {
final Class<?> mappedClass = mappedJtd.getJavaTypeClass();
final Class<?> mappedClass = bootAttributeDescriptor.getPersistentClass().getMappedClass();
final String descriptorName = bootAttributeDescriptor.getName();
final var strategy = propertyAccessStrategy( bootAttributeDescriptor, mappedClass, strategySelector );
if ( strategy == null ) {
Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -4822,26 +4822,27 @@ private void inheritSupertypeSpecialAttributeMappings() {
final NonIdentifierAttribute[] properties = entityMetamodel.getProperties();
final AttributeMappingsMap.Builder mappingsBuilder = AttributeMappingsMap.builder();
int fetchableIndex = getFetchableIndexOffset();
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
final NonIdentifierAttribute runtimeAttributeDefinition = properties[i];
final String attributeName = runtimeAttributeDefinition.getName();
final Property bootProperty = bootEntityDescriptor.getProperty( attributeName );
if ( superMappingType == null
|| superMappingType.findAttributeMapping( bootProperty.getName() ) == null ) {
mappingsBuilder.put(
attributeName,
generateNonIdAttributeMapping(
runtimeAttributeDefinition,
bootProperty,
stateArrayPosition++,
fetchableIndex++,
creationProcess
)
);
}
declaredAttributeMappings = mappingsBuilder.build();
// otherwise, it's defined on the supertype, skip it here
// For every property that is "owned" by this persistent class, create a declared attribute mapping
final List<Property> bootProperties = bootEntityDescriptor.getProperties();
// EntityMetamodel uses getPropertyClosure(), which includes the properties of the super type,
// so use that property span as offset when indexing into the EntityMetamodel NonIdentifierAttribute[]
final int superclassPropertiesOffset = superMappingType == null ? 0
: superMappingType.getEntityPersister().getEntityMetamodel().getPropertySpan();
for ( int i = 0; i < bootProperties.size(); i++ ) {
final Property bootProperty = bootProperties.get( i );
assert properties[superclassPropertiesOffset + i].getName().equals( bootProperty.getName() );
mappingsBuilder.put(
bootProperty.getName(),
generateNonIdAttributeMapping(
properties[superclassPropertiesOffset + i],
bootProperty,
stateArrayPosition++,
fetchableIndex++,
creationProcess
)
);
}
declaredAttributeMappings = mappingsBuilder.build();
}

private static BeforeExecutionGenerator createVersionGenerator
Expand Down
Loading
Loading

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