This commit is contained in:
Steve Ebersole 2024-05-01 19:24:41 -05:00
parent c7a15a835d
commit e414373f85
8 changed files with 167 additions and 45 deletions

View File

@ -43,7 +43,7 @@ import org.hibernate.models.spi.MemberDetails;
import org.jboss.logging.Logger;
import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.getPath;
import static org.hibernate.boot.model.internal.BinderHelper.getRelativePath;
import static org.hibernate.internal.util.StringHelper.isEmpty;

View File

@ -28,7 +28,7 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.JoinTable;
import static org.hibernate.boot.model.internal.BinderHelper.getCascadeStrategy;
import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.getPath;
public class AnyBinder {

View File

@ -21,7 +21,6 @@ import java.util.function.Consumer;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.annotations.AnyDiscriminatorValue;
import org.hibernate.annotations.AnyDiscriminatorValues;

View File

@ -166,7 +166,7 @@ import static org.hibernate.boot.model.internal.BinderHelper.createSyntheticProp
import static org.hibernate.boot.model.internal.BinderHelper.extractFromPackage;
import static org.hibernate.boot.model.internal.BinderHelper.getCascadeStrategy;
import static org.hibernate.boot.model.internal.BinderHelper.getFetchMode;
import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.getPath;
import static org.hibernate.boot.model.internal.BinderHelper.isDefault;
import static org.hibernate.boot.model.internal.BinderHelper.isPrimitive;

View File

@ -44,7 +44,7 @@ import static org.hibernate.boot.model.internal.AnnotatedColumn.buildColumnFromA
import static org.hibernate.boot.model.internal.AnnotatedColumn.buildColumnFromNoAnnotation;
import static org.hibernate.boot.model.internal.AnnotatedColumn.buildColumnsFromAnnotations;
import static org.hibernate.boot.model.internal.AnnotatedColumn.buildFormulaFromAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.getPath;
import static org.hibernate.boot.model.internal.BinderHelper.getPropertyOverriddenByMapperOrMapsId;
import static org.hibernate.boot.models.internal.AnnotationUsageHelper.applyAttributeIfSpecified;

View File

@ -0,0 +1,119 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.boot.model.internal;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.annotations.DialectOverride;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect;
import org.hibernate.models.spi.AnnotationTarget;
import org.hibernate.models.spi.AnnotationUsage;
import org.hibernate.models.spi.ClassDetails;
/**
* @author Steve Ebersole
*/
public class DialectOverridesAnnotationHelper {
private static Map<Class<? extends Annotation>, Class<? extends Annotation>> OVERRIDE_MAP = buildOverrideMap();
private static Map<Class<? extends Annotation>, Class<? extends Annotation>> buildOverrideMap() {
// not accessed concurrently
final Map<Class<? extends Annotation>, Class<? extends Annotation>> results = new HashMap<>();
final Class<?>[] dialectOverrideMembers = DialectOverride.class.getNestMembers();
for ( Class<?> dialectOverrideMember : dialectOverrideMembers ) {
if ( !dialectOverrideMember.isAnnotation() ) {
continue;
}
final DialectOverride.OverridesAnnotation overrideAnnotation = dialectOverrideMember.getAnnotation( DialectOverride.OverridesAnnotation.class );
if ( overrideAnnotation == null ) {
continue;
}
// The "real" annotation. e.g. `org.hibernate.annotations.Formula`
final Class<? extends Annotation> baseAnnotation = overrideAnnotation.value();
// the "override" annotation. e.g. `org.hibernate.annotations.DialectOverride.Formula`
//noinspection unchecked
final Class<? extends Annotation> dialectOverrideAnnotation = (Class<? extends Annotation>) dialectOverrideMember;
results.put( baseAnnotation, dialectOverrideAnnotation );
}
return results;
}
public static <A extends Annotation, O extends Annotation> Class<O> getOverrideAnnotation(Class<A> annotationType) {
final Class<O> overrideAnnotation = findOverrideAnnotation( annotationType );
if ( overrideAnnotation != null ) {
return overrideAnnotation;
}
throw new HibernateException(
String.format(
Locale.ROOT,
"Specified Annotation type (%s) does not have an override form",
annotationType.getName()
)
);
}
public static <A extends Annotation, O extends Annotation> Class<O> findOverrideAnnotation(Class<A> annotationType) {
//noinspection unchecked
return (Class<O>) OVERRIDE_MAP.get( annotationType );
}
public static <T extends Annotation> AnnotationUsage<T> getOverridableAnnotation(
AnnotationTarget element,
Class<T> annotationType,
MetadataBuildingContext context) {
final Class<? extends Annotation> overrideAnnotation = OVERRIDE_MAP.get( annotationType );
if ( overrideAnnotation != null ) {
// the requested annotation does have a DialectOverride variant - look for matching one of those...
final Dialect dialect = context.getMetadataCollector().getDatabase().getDialect();
final DatabaseVersion version = dialect.getVersion();
final List<? extends AnnotationUsage<? extends Annotation>> overrides = element.getRepeatedAnnotationUsages( overrideAnnotation );
for ( AnnotationUsage<? extends Annotation> override : overrides ) {
if ( overrideMatchesDialect( override, dialect ) ) {
// we found an override match...
// the override's `override` attribute is the thing to return
return override.getNestedUsage( "override" );
}
}
}
// no override was found. return the base annotation (if one)
return element.getSingleAnnotationUsage( annotationType );
}
public static boolean overrideMatchesDialect(AnnotationUsage<? extends Annotation> override, Dialect dialect) {
final ClassDetails overrideDialect = override.getClassDetails( "dialect" );
final Class<? extends Dialect> overrideDialectJavaType = overrideDialect.toJavaClass();
if ( !overrideDialectJavaType.isAssignableFrom( dialect.getClass() ) ) {
return false;
}
final AnnotationUsage<DialectOverride.Version> beforeAnn = override.getNestedUsage( "before" );
final AnnotationUsage<DialectOverride.Version> sameOrAfterAnn = override.getNestedUsage( "sameOrAfter" );
final DatabaseVersion version = dialect.getVersion();
if ( version.isBefore( beforeAnn.getInteger( "major" ), beforeAnn.getInteger( "minor" ) )
&& version.isSameOrAfter( sameOrAfterAnn.getInteger( "major" ), sameOrAfterAnn.getInteger( "minor" ) ) ) {
return true;
}
return false;
}
}

View File

@ -144,13 +144,13 @@ import static org.hibernate.boot.model.internal.AnnotatedDiscriminatorColumn.bui
import static org.hibernate.boot.model.internal.AnnotatedJoinColumn.buildInheritanceJoinColumn;
import static org.hibernate.boot.model.internal.BinderHelper.extractFromPackage;
import static org.hibernate.boot.model.internal.BinderHelper.getMappedSuperclassOrNull;
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.getOverrideAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation;
import static org.hibernate.boot.model.internal.BinderHelper.noConstraint;
import static org.hibernate.boot.model.internal.BinderHelper.overrideMatchesDialect;
import static org.hibernate.boot.model.internal.BinderHelper.toAliasEntityMap;
import static org.hibernate.boot.model.internal.BinderHelper.toAliasTableMap;
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverridableAnnotation;
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.getOverrideAnnotation;
import static org.hibernate.boot.model.internal.DialectOverridesAnnotationHelper.overrideMatchesDialect;
import static org.hibernate.boot.model.internal.EmbeddableBinder.fillEmbeddable;
import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator;
import static org.hibernate.boot.model.internal.InheritanceState.getInheritanceStateOfSuperEntity;
@ -1368,7 +1368,7 @@ public class EntityBinder {
persistentClass.setCached( isCached );
persistentClass.setLazy( lazy );
persistentClass.setQueryCacheLayout( queryCacheLayout );
if ( proxyClass != null ) {
if ( proxyClass != null && proxyClass != ClassDetails.VOID_CLASS_DETAILS ) {
persistentClass.setProxyInterfaceName( proxyClass.getName() );
}
@ -1641,7 +1641,7 @@ public class EntityBinder {
final AnnotationUsage<Proxy> proxy = annotatedClass.getAnnotationUsage( Proxy.class );
if ( proxy != null ) {
lazy = proxy.getBoolean( "lazy" );
proxyClass = lazy ? proxy.getClassDetails( "proxyClass" ) : null;
proxyClass = lazy ? resolveProxyClass( proxy, annotatedClass ) : null;
}
else {
//needed to allow association lazy loading.
@ -1650,6 +1650,14 @@ public class EntityBinder {
}
}
private static ClassDetails resolveProxyClass(AnnotationUsage<Proxy> proxy, ClassDetails annotatedClass) {
final ClassDetails proxyClass = proxy.getClassDetails( "proxyClass" );
if ( proxyClass == ClassDetails.VOID_CLASS_DETAILS ) {
return annotatedClass;
}
return proxyClass;
}
public void bindConcreteProxy() {
final AnnotationUsage<ConcreteProxy> annotationUsage = annotatedClass.getAnnotationUsage( ConcreteProxy.class );
if ( annotationUsage != null ) {

View File

@ -6,17 +6,6 @@
*/
package org.hibernate.bytecode.internal.bytebuddy;
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static net.bytebuddy.matcher.ElementMatchers.isFinalizer;
import static net.bytebuddy.matcher.ElementMatchers.isSynthetic;
import static net.bytebuddy.matcher.ElementMatchers.isVirtual;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;
import static org.hibernate.internal.CoreLogging.messageLogger;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
@ -48,6 +37,17 @@ import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.pool.TypePool;
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static net.bytebuddy.matcher.ElementMatchers.isFinalizer;
import static net.bytebuddy.matcher.ElementMatchers.isSynthetic;
import static net.bytebuddy.matcher.ElementMatchers.isVirtual;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;
import static org.hibernate.internal.CoreLogging.messageLogger;
/**
* A utility to hold all ByteBuddy related state, as in the current version of
* Hibernate the Bytecode Provider state is held in a static field, yet ByteBuddy
@ -86,6 +86,7 @@ public final class ByteBuddyState {
this.byteBuddy = new ByteBuddy( classFileVersion ).with( TypeValidation.DISABLED );
this.proxyCache = new TypeCache( TypeCache.Sort.WEAK );
this.basicProxyCache = new TypeCache( TypeCache.Sort.WEAK );
this.classRewriter = new StandardClassRewriter();
}
/**
@ -232,30 +233,6 @@ public final class ByteBuddyState {
return this.enhancerConstants;
}
private static class GetDeclaredMethodAction implements PrivilegedAction<Method> {
private final Class<?> clazz;
private final String methodName;
private final Class<?>[] parameterTypes;
private GetDeclaredMethodAction(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
this.clazz = clazz;
this.methodName = methodName;
this.parameterTypes = parameterTypes;
}
@Override
public Method run() {
try {
Method method = clazz.getDeclaredMethod( methodName, parameterTypes );
return method;
}
catch (NoSuchMethodException e) {
throw new HibernateException( "Unable to prepare getDeclaredMethod()/getMethod() substitution", e );
}
}
}
/**
* Shared proxy definition helpers. They are immutable so we can safely share them.
*/
@ -320,6 +297,25 @@ public final class ByteBuddyState {
}
}
private interface ClassRewriter {
DynamicType.Builder<?> installReflectionMethodVisitors(DynamicType.Builder<?> builder);
void registerAuthorizedClass(Unloaded<?> unloadedClass);
}
private static class StandardClassRewriter implements ClassRewriter {
@Override
public DynamicType.Builder<?> installReflectionMethodVisitors(DynamicType.Builder<?> builder) {
// do nothing
return builder;
}
@Override
public void registerAuthorizedClass(Unloaded<?> unloadedClass) {
// do nothing
}
}
private static ClassLoadingStrategy<ClassLoader> resolveClassLoadingStrategy(Class<?> originalClass) {
try {
return ClassLoadingStrategy.UsingLookup.of( MethodHandles.privateLookupIn( originalClass, LOOKUP ) );