HHH-18541 Migrate hibernate-envers from hcann to hibernate-models
This commit is contained in:
parent
f1d7d86c2d
commit
00680b37fd
|
@ -65,7 +65,7 @@ public class ConverterHelper {
|
|||
}
|
||||
}
|
||||
else {
|
||||
throw new HibernateException( "Unexpected java.lang.reflect.Member type from org.hibernate.annotations.common.reflection.java.JavaXMember : " + member );
|
||||
throw new HibernateException( "Unexpected java.lang.reflect.Member type from org.hibernate.models.spi.MemberDetails : " + member );
|
||||
}
|
||||
|
||||
throw new HibernateException(
|
||||
|
|
|
@ -17,7 +17,7 @@ dependencies {
|
|||
implementation jakartaLibs.jaxbApi
|
||||
implementation jakartaLibs.jaxb
|
||||
implementation libs.jandex
|
||||
implementation libs.hcann
|
||||
implementation libs.hibernateModels
|
||||
|
||||
compileOnly libs.ant
|
||||
|
||||
|
|
|
@ -6,19 +6,19 @@
|
|||
*/
|
||||
package org.hibernate.envers.boot.internal;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||
import org.hibernate.boot.spi.BootstrapContext;
|
||||
import org.hibernate.boot.spi.EffectiveMappingDefaults;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.MetadataBuildingOptions;
|
||||
import org.hibernate.envers.boot.spi.EnversMetadataBuildingContext;
|
||||
import org.hibernate.envers.configuration.Configuration;
|
||||
import org.hibernate.envers.configuration.internal.MappingCollector;
|
||||
import org.hibernate.envers.configuration.internal.metadata.AuditEntityConfigurationRegistry;
|
||||
import org.hibernate.envers.configuration.internal.metadata.AuditEntityNameRegister;
|
||||
import org.hibernate.models.spi.ClassDetailsRegistry;
|
||||
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
|
@ -102,8 +102,13 @@ public class EnversMetadataBuildingContextImpl implements EnversMetadataBuilding
|
|||
}
|
||||
|
||||
@Override
|
||||
public ReflectionManager getReflectionManager() {
|
||||
return configuration.getReflectionManager();
|
||||
public SourceModelBuildingContext getSourceModelBuildingContext() {
|
||||
return metadataCollector.getSourceModelBuildingContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDetailsRegistry getClassDetailsRegistry() {
|
||||
return metadataCollector.getClassDetailsRegistry();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -98,6 +98,7 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
|
|||
|
||||
initialized = true;
|
||||
|
||||
final InFlightMetadataCollector metadataCollector = (InFlightMetadataCollector) metadata;
|
||||
this.serviceRegistry = metadata.getMetadataBuildingOptions().getServiceRegistry();
|
||||
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
|
||||
|
||||
|
@ -105,12 +106,12 @@ public class EnversServiceImpl implements EnversService, Configurable, Stoppable
|
|||
final Properties properties = new Properties();
|
||||
properties.putAll( cfgService.getSettings() );
|
||||
|
||||
this.configuration = new Configuration( properties, this, metadata );
|
||||
this.configuration = new Configuration( properties, this, metadataCollector );
|
||||
this.auditProcessManager = new AuditProcessManager( configuration.getRevisionInfo().getRevisionInfoGenerator() );
|
||||
|
||||
final EnversMetadataBuildingContext metadataBuildingContext = new EnversMetadataBuildingContextImpl(
|
||||
configuration,
|
||||
(InFlightMetadataCollector) metadata,
|
||||
metadataCollector,
|
||||
effectiveMappingDefaults,
|
||||
mappingCollector
|
||||
);
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
*/
|
||||
package org.hibernate.envers.boot.spi;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.envers.configuration.Configuration;
|
||||
import org.hibernate.envers.configuration.internal.MappingCollector;
|
||||
import org.hibernate.envers.configuration.internal.metadata.AuditEntityConfigurationRegistry;
|
||||
import org.hibernate.envers.configuration.internal.metadata.AuditEntityNameRegister;
|
||||
import org.hibernate.models.spi.ClassDetailsRegistry;
|
||||
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
|
@ -26,7 +27,9 @@ public interface EnversMetadataBuildingContext extends MetadataBuildingContext {
|
|||
|
||||
ServiceRegistry getServiceRegistry();
|
||||
|
||||
ReflectionManager getReflectionManager();
|
||||
SourceModelBuildingContext getSourceModelBuildingContext();
|
||||
|
||||
ClassDetailsRegistry getClassDetailsRegistry();
|
||||
|
||||
AuditEntityNameRegister getAuditEntityNameRegistry();
|
||||
|
||||
|
|
|
@ -11,11 +11,9 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.HSQLDialect;
|
||||
import org.hibernate.envers.RevisionListener;
|
||||
|
@ -75,7 +73,6 @@ public class Configuration {
|
|||
private final boolean globalLegacyRelationTargetNotFound;
|
||||
|
||||
private final boolean trackEntitiesChanged;
|
||||
private final JavaReflectionManager reflectionManager;
|
||||
private boolean trackEntitiesOverride;
|
||||
|
||||
private final String auditTablePrefix;
|
||||
|
@ -98,7 +95,7 @@ public class Configuration {
|
|||
|
||||
private final RevisionInfoConfiguration revisionInfo;
|
||||
|
||||
public Configuration(Properties properties, EnversService enversService, MetadataImplementor metadata) {
|
||||
public Configuration(Properties properties, EnversService enversService, InFlightMetadataCollector metadata) {
|
||||
this.enversService = enversService;
|
||||
|
||||
final ConfigurationProperties configProps = new ConfigurationProperties( properties );
|
||||
|
@ -185,14 +182,7 @@ public class Configuration {
|
|||
revisionPropertyBasePath = originalIdPropertyName + "." + revisionFieldName + ".";
|
||||
revisionNumberPath = revisionPropertyBasePath + "id";
|
||||
|
||||
// todo: there are places that need bits built from the revinfo entity configuration
|
||||
// this exists here as a way to pass it down in an immutable way to any consumer of this class
|
||||
this.reflectionManager = new JavaReflectionManager();
|
||||
this.revisionInfo = new RevisionInfoConfiguration( this, metadata, reflectionManager );
|
||||
}
|
||||
|
||||
public JavaReflectionManager getReflectionManager() {
|
||||
return reflectionManager;
|
||||
this.revisionInfo = new RevisionInfoConfiguration( this, metadata );
|
||||
}
|
||||
|
||||
public boolean isGenerateRevisionsForCollections() {
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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.envers.configuration.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.envers.configuration.internal.metadata.reader.PersistentPropertiesSource;
|
||||
import org.hibernate.models.internal.ClassTypeDetailsImpl;
|
||||
import org.hibernate.models.internal.ModifierUtils;
|
||||
import org.hibernate.models.internal.dynamic.DynamicFieldDetails;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
import org.hibernate.models.spi.FieldDetails;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
import org.hibernate.models.spi.MethodDetails;
|
||||
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||
import org.hibernate.models.spi.TypeDetails;
|
||||
|
||||
/**
|
||||
* Simple helper class to streamline hibernate-models interactions.
|
||||
*
|
||||
* @author Marco Belladelli
|
||||
*/
|
||||
public class ModelsHelper {
|
||||
/**
|
||||
* Provides a list of the provided class' {@link MemberDetails} based on the provided access type.
|
||||
*
|
||||
* @param classDetails The class details to extract the members from
|
||||
* @param accessType The access type to use, accepted values are {@code field}, {@code property} and {@code record}
|
||||
*
|
||||
* @return The list of member details
|
||||
*/
|
||||
public static List<? extends MemberDetails> getMemberDetails(ClassDetails classDetails, String accessType) {
|
||||
return switch ( accessType ) {
|
||||
case "field" -> classDetails.getFields();
|
||||
case "property" -> classDetails.getMethods();
|
||||
case "record" -> classDetails.getRecordComponents();
|
||||
default -> throw new IllegalArgumentException( "Unknown access type " + accessType );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link MemberDetails member} of the class, being either the field or the getter,
|
||||
* with the provided name if one exists, {@code null} otherwise.
|
||||
*
|
||||
* @param classDetails The class details containing the desired member
|
||||
* @param name The name of the member to find
|
||||
*
|
||||
* @return The requested member, null if not found
|
||||
*/
|
||||
public static MemberDetails getMember(ClassDetails classDetails, String name) {
|
||||
final FieldDetails field = classDetails.findFieldByName( name );
|
||||
if ( field != null ) {
|
||||
return field;
|
||||
}
|
||||
|
||||
for ( MethodDetails method : classDetails.getMethods() ) {
|
||||
if ( method.resolveAttributeName().equals( name ) ) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link DynamicFieldDetails} from the provided properties source with the specified name
|
||||
*
|
||||
* @param propertiesSource The property source containing the virtual field
|
||||
* @param propertyName The property name of the dynamic field
|
||||
* @param sourceModelBuildingContext Context object for models
|
||||
*
|
||||
* @return The newly created dynamic field details
|
||||
*/
|
||||
public static FieldDetails dynamicFieldDetails(
|
||||
PersistentPropertiesSource propertiesSource,
|
||||
String propertyName,
|
||||
SourceModelBuildingContext sourceModelBuildingContext) {
|
||||
return new DynamicFieldDetails(
|
||||
propertyName,
|
||||
new ClassTypeDetailsImpl( propertiesSource.getClassDetails(), TypeDetails.Kind.CLASS ),
|
||||
propertiesSource.getClassDetails(),
|
||||
ModifierUtils.DYNAMIC_ATTRIBUTE_MODIFIERS,
|
||||
false,
|
||||
false,
|
||||
sourceModelBuildingContext
|
||||
);
|
||||
}
|
||||
}
|
|
@ -13,10 +13,7 @@ import java.util.Locale;
|
|||
import java.util.Set;
|
||||
import jakarta.persistence.Column;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.hibernate.envers.DefaultRevisionEntity;
|
||||
import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
|
||||
|
@ -48,8 +45,13 @@ import org.hibernate.envers.internal.revisioninfo.RevisionInfoQueryCreator;
|
|||
import org.hibernate.envers.internal.revisioninfo.RevisionTimestampValueResolver;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
import org.hibernate.models.spi.TypeDetails;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
import static org.hibernate.envers.configuration.internal.ModelsHelper.getMemberDetails;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
|
@ -80,11 +82,11 @@ public class RevisionInfoConfiguration {
|
|||
private final Class<?> revisionInfoClass;
|
||||
private final boolean useDefaultRevisionInfoMapping;
|
||||
|
||||
public RevisionInfoConfiguration(Configuration config, MetadataImplementor metadata, ReflectionManager reflectionManager) {
|
||||
public RevisionInfoConfiguration(Configuration config, InFlightMetadataCollector metadata) {
|
||||
this.configuration = config;
|
||||
|
||||
// Generate the resolver metadata
|
||||
RevisionEntityResolver resolver = new RevisionEntityResolver( metadata, reflectionManager );
|
||||
final RevisionEntityResolver resolver = new RevisionEntityResolver( metadata );
|
||||
|
||||
// initialize attributes from resolver
|
||||
this.revisionInfoClass = resolver.revisionInfoClass;
|
||||
|
@ -262,8 +264,7 @@ public class RevisionInfoConfiguration {
|
|||
|
||||
private class RevisionEntityResolver {
|
||||
|
||||
private final MetadataImplementor metadata;
|
||||
private final ReflectionManager reflectionManager;
|
||||
private final InFlightMetadataCollector metadata;
|
||||
|
||||
private boolean revisionEntityFound;
|
||||
private boolean revisionNumberFound;
|
||||
|
@ -282,9 +283,8 @@ public class RevisionInfoConfiguration {
|
|||
private String revisionPropSqlType;
|
||||
private RevisionTimestampValueResolver timestampValueResolver;
|
||||
|
||||
public RevisionEntityResolver(MetadataImplementor metadata, ReflectionManager reflectionManager) {
|
||||
public RevisionEntityResolver(InFlightMetadataCollector metadata) {
|
||||
this.metadata = metadata;
|
||||
this.reflectionManager = reflectionManager;
|
||||
this.revisionInfoEntityName = getDefaultEntityName();
|
||||
this.revisionInfoIdData = createPropertyData( "id", "field" );
|
||||
this.revisionInfoTimestampData = createPropertyData( "timestamp", "field" );
|
||||
|
@ -312,8 +312,10 @@ public class RevisionInfoConfiguration {
|
|||
continue;
|
||||
}
|
||||
|
||||
XClass clazz = reflectionManager.toXClass( persistentClass.getMappedClass() );
|
||||
final RevisionEntity revisionEntity = clazz.getAnnotation( RevisionEntity.class );
|
||||
final ClassDetails classDetails = metadata.getClassDetailsRegistry().resolveClassDetails(
|
||||
persistentClass.getClassName()
|
||||
);
|
||||
final RevisionEntity revisionEntity = classDetails.getDirectAnnotationUsage( RevisionEntity.class );
|
||||
if ( revisionEntity == null ) {
|
||||
// not annotated, skip
|
||||
continue;
|
||||
|
@ -324,13 +326,13 @@ public class RevisionInfoConfiguration {
|
|||
}
|
||||
|
||||
// Verify that the revision entity isn't audited
|
||||
if ( clazz.getAnnotation( Audited.class ) != null ) {
|
||||
if ( classDetails.hasDirectAnnotationUsage( Audited.class ) ) {
|
||||
throw new EnversMappingException( "The @RevisionEntity entity cannot be audited" );
|
||||
}
|
||||
|
||||
revisionEntityFound = true;
|
||||
|
||||
resolveConfiguration( clazz );
|
||||
resolveConfiguration( classDetails );
|
||||
|
||||
if ( !revisionNumberFound || !revisionTimestampFound ) {
|
||||
// A revision number and timestamp fields must be annotated or the revision entity mapping
|
||||
|
@ -436,115 +438,116 @@ public class RevisionInfoConfiguration {
|
|||
|| modifiedEntityNamesFound;
|
||||
}
|
||||
|
||||
private void resolveConfiguration(XClass clazz) {
|
||||
final XClass superclazz = clazz.getSuperclass();
|
||||
if ( !Object.class.getName().equals( superclazz.getName() ) ) {
|
||||
private void resolveConfiguration(ClassDetails classDetails) {
|
||||
final ClassDetails superclass = classDetails.getSuperClass();
|
||||
if ( !Object.class.getName().equals( superclass.getName() ) ) {
|
||||
// traverse to the top of the entity hierarchy
|
||||
resolveConfiguration( superclazz );
|
||||
resolveConfiguration( superclass );
|
||||
}
|
||||
resolveConfigurationFromProperties( clazz, "field" );
|
||||
resolveConfigurationFromProperties( clazz, "property" );
|
||||
resolveConfigurationFromProperties( classDetails, "field" );
|
||||
resolveConfigurationFromProperties( classDetails, "property" );
|
||||
}
|
||||
|
||||
private void resolveConfigurationFromProperties(XClass clazz, String accessType) {
|
||||
for ( XProperty property : clazz.getDeclaredProperties( accessType ) ) {
|
||||
final RevisionNumber revisionNumber = property.getAnnotation( RevisionNumber.class );
|
||||
private void resolveConfigurationFromProperties(ClassDetails classDetails, String accessType) {
|
||||
for ( MemberDetails member : getMemberDetails( classDetails, accessType ) ) {
|
||||
final RevisionNumber revisionNumber = member.getDirectAnnotationUsage( RevisionNumber.class );
|
||||
if ( revisionNumber != null ) {
|
||||
resolveRevisionNumberFromProperty( property, accessType );
|
||||
resolveRevisionNumberFromProperty( member, accessType );
|
||||
}
|
||||
|
||||
final RevisionTimestamp revisionTimestamp = property.getAnnotation( RevisionTimestamp.class );
|
||||
final RevisionTimestamp revisionTimestamp = member.getDirectAnnotationUsage( RevisionTimestamp.class );
|
||||
if ( revisionTimestamp != null ) {
|
||||
resolveRevisionTimestampFromProperty( property, accessType );
|
||||
resolveRevisionTimestampFromProperty( member, accessType );
|
||||
}
|
||||
|
||||
final ModifiedEntityNames modifiedEntityNames = property.getAnnotation( ModifiedEntityNames.class );
|
||||
final ModifiedEntityNames modifiedEntityNames = member.getDirectAnnotationUsage( ModifiedEntityNames.class );
|
||||
if ( modifiedEntityNames != null ) {
|
||||
resolveModifiedEntityNamesFromProperty( property, accessType );
|
||||
resolveModifiedEntityNamesFromProperty( member, accessType );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveRevisionNumberFromProperty(XProperty property, String accessType) {
|
||||
private void resolveRevisionNumberFromProperty(MemberDetails memberDetails, String accessType) {
|
||||
if ( revisionNumberFound ) {
|
||||
throw new EnversMappingException( "Only one property can be defined with @RevisionNumber" );
|
||||
}
|
||||
|
||||
final XClass propertyType = property.getType();
|
||||
if ( isAnyType( propertyType, Integer.class, Integer.TYPE ) ) {
|
||||
revisionInfoIdData = createPropertyData( property, accessType );
|
||||
final TypeDetails type = memberDetails.getType();
|
||||
if ( isAnyType( type, Integer.class, Integer.TYPE ) ) {
|
||||
revisionInfoIdData = createPropertyData( memberDetails, accessType );
|
||||
revisionNumberFound = true;
|
||||
}
|
||||
else if ( isAnyType( propertyType, Long.class, Long.TYPE ) ) {
|
||||
revisionInfoIdData = createPropertyData( property, accessType );
|
||||
else if ( isAnyType( type, Long.class, Long.TYPE ) ) {
|
||||
revisionInfoIdData = createPropertyData( memberDetails, accessType );
|
||||
revisionPropType = "long";
|
||||
revisionNumberFound = true;
|
||||
}
|
||||
else {
|
||||
throwUnexpectedAnnotatedType( property, RevisionNumber.class, "int, Integer, long, or Long" );
|
||||
throwUnexpectedAnnotatedType( memberDetails, RevisionNumber.class, "int, Integer, long, or Long" );
|
||||
}
|
||||
|
||||
// Getting the @Column definition of the revision number property, to later use that information
|
||||
// to generate the same mapping for the relation from an audit table's revision number to the
|
||||
// revision entity's revision number field.
|
||||
final Column column = property.getAnnotation( Column.class );
|
||||
final Column column = memberDetails.getDirectAnnotationUsage( Column.class );
|
||||
if ( column != null ) {
|
||||
revisionPropSqlType = column.columnDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveRevisionTimestampFromProperty(XProperty property, String accessType) {
|
||||
private void resolveRevisionTimestampFromProperty(MemberDetails memberDetails, String accessType) {
|
||||
if ( revisionTimestampFound ) {
|
||||
throw new EnversMappingException( "Only one property can be defined with @RevisionTimestamp" );
|
||||
}
|
||||
|
||||
final XClass propertyType = property.getType();
|
||||
if ( isAnyType( propertyType, Long.class, Long.TYPE, Date.class, LocalDateTime.class, Instant.class, java.sql.Date.class ) ) {
|
||||
revisionInfoTimestampData = createPropertyData( property, accessType );
|
||||
final TypeDetails type = memberDetails.getType();
|
||||
if ( isAnyType( type, Long.class, Long.TYPE, Date.class, LocalDateTime.class, Instant.class, java.sql.Date.class ) ) {
|
||||
revisionInfoTimestampData = createPropertyData( memberDetails, accessType );
|
||||
revisionTimestampFound = true;
|
||||
}
|
||||
else {
|
||||
throwUnexpectedAnnotatedType( property, RevisionTimestamp.class, "long, Long, Date, LocalDateTime, Instant, or java.sql.Date" );
|
||||
throwUnexpectedAnnotatedType( memberDetails, RevisionTimestamp.class, "long, Long, Date, LocalDateTime, Instant, or java.sql.Date" );
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveModifiedEntityNamesFromProperty(XProperty property, String accessType) {
|
||||
private void resolveModifiedEntityNamesFromProperty(MemberDetails memberDetails, String accessType) {
|
||||
if ( modifiedEntityNamesFound ) {
|
||||
throw new EnversMappingException( "Only one property can be defined with @ModifiedEntityNames" );
|
||||
}
|
||||
|
||||
final XClass propertyType = property.getType();
|
||||
if ( isAnyType( propertyType, Set.class ) ) {
|
||||
final XClass elementType = property.getElementClass();
|
||||
final TypeDetails type = memberDetails.getType();
|
||||
if ( isAnyType( type, Set.class ) ) {
|
||||
final TypeDetails elementType = memberDetails.getElementType();
|
||||
if ( isAnyType( elementType, String.class ) ) {
|
||||
modifiedEntityNamesData = createPropertyData( property, accessType );
|
||||
modifiedEntityNamesData = createPropertyData( memberDetails, accessType );
|
||||
modifiedEntityNamesFound = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throwUnexpectedAnnotatedType( property, ModifiedEntityNames.class, "Set<String>" );
|
||||
throwUnexpectedAnnotatedType( memberDetails, ModifiedEntityNames.class, "Set<String>" );
|
||||
}
|
||||
|
||||
private PropertyData createPropertyData(XProperty property, String accessType) {
|
||||
return createPropertyData( property.getName(), accessType );
|
||||
private PropertyData createPropertyData(MemberDetails memberDetails, String accessType) {
|
||||
return createPropertyData( memberDetails.resolveAttributeName(), accessType );
|
||||
}
|
||||
|
||||
private PropertyData createPropertyData(String name, String accessType) {
|
||||
return new PropertyData( name, name, accessType );
|
||||
}
|
||||
|
||||
private boolean isAnyType(XClass clazz, Class<?>... types) {
|
||||
private boolean isAnyType(TypeDetails typeDetails, Class<?>... types) {
|
||||
for ( Class<?> type : types ) {
|
||||
if ( isType( clazz, type ) ) {
|
||||
if ( isType( typeDetails, type ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isType(XClass clazz, Class<?> type) {
|
||||
return reflectionManager.equals( clazz, type );
|
||||
private boolean isType(TypeDetails typeDetails, Class<?> type) {
|
||||
final String className = typeDetails != null ? typeDetails.determineRawClass().getClassName() : null;
|
||||
return className != null && className.equals( type.getName() );
|
||||
}
|
||||
|
||||
private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> defaultListener) {
|
||||
|
@ -554,12 +557,12 @@ public class RevisionInfoConfiguration {
|
|||
return defaultListener;
|
||||
}
|
||||
|
||||
private void throwUnexpectedAnnotatedType(XProperty property, Class<?> annotation, String allowedTypes) {
|
||||
private void throwUnexpectedAnnotatedType(MemberDetails memberDetails, Class<?> annotation, String allowedTypes) {
|
||||
throw new EnversMappingException(
|
||||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"The field '%s' annotated with '@%s' must be of type: %s",
|
||||
property.getName(),
|
||||
memberDetails.resolveAttributeName(),
|
||||
annotation.getName(),
|
||||
allowedTypes
|
||||
)
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.envers.configuration.internal.metadata.reader;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.envers.AuditTable;
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.hibernate.envers.RelationTargetAuditMode;
|
||||
|
@ -16,6 +15,7 @@ import org.hibernate.envers.SecondaryAuditTable;
|
|||
import org.hibernate.envers.SecondaryAuditTables;
|
||||
import org.hibernate.envers.boot.spi.EnversMetadataBuildingContext;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
|
||||
/**
|
||||
* A helper class to read versioning meta-data from annotations on a persistent class.
|
||||
|
@ -31,8 +31,8 @@ public final class AnnotationsMetadataReader {
|
|||
this.metadataBuildingContext = metadataBuildingContext;
|
||||
}
|
||||
|
||||
private RelationTargetAuditMode getDefaultAudited(XClass clazz) {
|
||||
final Audited defaultAudited = clazz.getAnnotation( Audited.class );
|
||||
private RelationTargetAuditMode getDefaultAudited(ClassDetails classDetails) {
|
||||
final Audited defaultAudited = classDetails.getDirectAnnotationUsage( Audited.class );
|
||||
|
||||
if ( defaultAudited != null ) {
|
||||
return defaultAudited.targetAuditMode();
|
||||
|
@ -42,8 +42,8 @@ public final class AnnotationsMetadataReader {
|
|||
}
|
||||
}
|
||||
|
||||
private void addAuditTable(ClassAuditingData auditData, XClass clazz) {
|
||||
final AuditTable auditTable = clazz.getAnnotation( AuditTable.class );
|
||||
private void addAuditTable(ClassAuditingData auditData, ClassDetails classDetails) {
|
||||
final AuditTable auditTable = classDetails.getDirectAnnotationUsage( AuditTable.class );
|
||||
if ( auditTable != null ) {
|
||||
auditData.setAuditTable( auditTable );
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ public final class AnnotationsMetadataReader {
|
|||
}
|
||||
}
|
||||
|
||||
private void addAuditSecondaryTables(ClassAuditingData auditData, XClass clazz) {
|
||||
private void addAuditSecondaryTables(ClassAuditingData auditData, ClassDetails classDetails) {
|
||||
// Getting information on secondary tables
|
||||
final SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation( SecondaryAuditTable.class );
|
||||
final SecondaryAuditTable secondaryVersionsTable1 = classDetails.getDirectAnnotationUsage( SecondaryAuditTable.class );
|
||||
if ( secondaryVersionsTable1 != null ) {
|
||||
auditData.getSecondaryTableDictionary().put(
|
||||
secondaryVersionsTable1.secondaryTableName(),
|
||||
|
@ -62,7 +62,7 @@ public final class AnnotationsMetadataReader {
|
|||
);
|
||||
}
|
||||
|
||||
final SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation( SecondaryAuditTables.class );
|
||||
final SecondaryAuditTables secondaryAuditTables = classDetails.getDirectAnnotationUsage( SecondaryAuditTables.class );
|
||||
if ( secondaryAuditTables != null ) {
|
||||
for ( SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value() ) {
|
||||
auditData.getSecondaryTableDictionary().put(
|
||||
|
@ -75,21 +75,23 @@ public final class AnnotationsMetadataReader {
|
|||
|
||||
public ClassAuditingData getAuditData(PersistentClass persistentClass) {
|
||||
final ClassAuditingData auditData = new ClassAuditingData( persistentClass );
|
||||
final XClass xclass = metadataBuildingContext.getReflectionManager().toXClass( persistentClass.getMappedClass() );
|
||||
final ClassDetails classDetails = metadataBuildingContext.getClassDetailsRegistry().resolveClassDetails(
|
||||
persistentClass.getClassName()
|
||||
);
|
||||
|
||||
final RelationTargetAuditMode auditMode = getDefaultAudited( xclass );
|
||||
final RelationTargetAuditMode auditMode = getDefaultAudited( classDetails );
|
||||
if ( auditMode != null ) {
|
||||
auditData.setDefaultAudited( true );
|
||||
}
|
||||
|
||||
new AuditedPropertiesReader(
|
||||
metadataBuildingContext,
|
||||
PersistentPropertiesSource.forClass( persistentClass, xclass ),
|
||||
PersistentPropertiesSource.forClass( persistentClass, classDetails ),
|
||||
auditData
|
||||
).read();
|
||||
|
||||
addAuditTable( auditData, xclass );
|
||||
addAuditSecondaryTables( auditData, xclass );
|
||||
addAuditTable( auditData, classDetails );
|
||||
addAuditSecondaryTables( auditData, classDetails );
|
||||
|
||||
return auditData;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,6 @@ import java.util.Set;
|
|||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.envers.AuditJoinTable;
|
||||
import org.hibernate.envers.AuditMappedBy;
|
||||
import org.hibernate.envers.AuditOverride;
|
||||
|
@ -33,12 +30,15 @@ import org.hibernate.envers.boot.EnversMappingException;
|
|||
import org.hibernate.envers.boot.internal.ModifiedColumnNameResolver;
|
||||
import org.hibernate.envers.boot.spi.EnversMetadataBuildingContext;
|
||||
import org.hibernate.envers.internal.tools.MappingTools;
|
||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||
import org.hibernate.envers.internal.tools.StringTools;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
import org.hibernate.models.spi.FieldDetails;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
||||
import jakarta.persistence.ElementCollection;
|
||||
|
@ -46,8 +46,11 @@ import jakarta.persistence.Lob;
|
|||
import jakarta.persistence.MapKey;
|
||||
import jakarta.persistence.MapKeyEnumerated;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Transient;
|
||||
import jakarta.persistence.Version;
|
||||
|
||||
import static org.hibernate.envers.configuration.internal.ModelsHelper.dynamicFieldDetails;
|
||||
import static org.hibernate.envers.configuration.internal.ModelsHelper.getMember;
|
||||
import static org.hibernate.envers.internal.tools.Tools.newHashMap;
|
||||
import static org.hibernate.envers.internal.tools.Tools.newHashSet;
|
||||
|
||||
|
@ -79,12 +82,12 @@ public class AuditedPropertiesReader {
|
|||
// Mapping class field to corresponding <properties> element.
|
||||
private final Map<String, String> propertiesGroupMapping;
|
||||
|
||||
private final Set<XProperty> overriddenAuditedProperties;
|
||||
private final Set<XProperty> overriddenNotAuditedProperties;
|
||||
private final Map<XProperty, AuditJoinTable> overriddenAuditedPropertiesJoinTables;
|
||||
private final Set<MemberDetails> overriddenAuditedProperties;
|
||||
private final Set<MemberDetails> overriddenNotAuditedProperties;
|
||||
private final Map<MemberDetails, AuditJoinTable> overriddenAuditedPropertiesJoinTables;
|
||||
|
||||
private final Set<XClass> overriddenAuditedClasses;
|
||||
private final Set<XClass> overriddenNotAuditedClasses;
|
||||
private final Set<ClassDetails> overriddenAuditedClasses;
|
||||
private final Set<ClassDetails> overriddenNotAuditedClasses;
|
||||
|
||||
public AuditedPropertiesReader(
|
||||
EnversMetadataBuildingContext metadataBuildingContext,
|
||||
|
@ -129,7 +132,7 @@ public class AuditedPropertiesReader {
|
|||
else {
|
||||
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
|
||||
// of currently mapped entity or itself.
|
||||
final XClass clazz = persistentPropertiesSource.getXClass();
|
||||
final ClassDetails classDetails = persistentPropertiesSource.getClassDetails();
|
||||
if ( persistentPropertiesSource.hasCompositeUserType() ) {
|
||||
for ( String propertyName : fieldAccessedPersistentProperties ) {
|
||||
final Property property = persistentPropertiesSource.getProperty( propertyName );
|
||||
|
@ -153,9 +156,9 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
}
|
||||
else {
|
||||
readAuditOverrides( clazz );
|
||||
readAuditOverrides( classDetails );
|
||||
// Adding all properties from the given class.
|
||||
addPropertiesFromClass( clazz );
|
||||
addPropertiesFromClass( classDetails );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,16 +167,16 @@ public class AuditedPropertiesReader {
|
|||
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
|
||||
* using {@link AuditOverride} annotation.
|
||||
*
|
||||
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
|
||||
* @param classDetails Class that is being processed. Currently mapped entity shall be passed during first invocation.
|
||||
*/
|
||||
private void readAuditOverrides(XClass clazz) {
|
||||
private void readAuditOverrides(ClassDetails classDetails) {
|
||||
/* TODO: Code to remove with @Audited.auditParents - start. */
|
||||
final ReflectionManager reflectionManager = metadataBuildingContext.getReflectionManager();
|
||||
final Audited allClassAudited = clazz.getAnnotation( Audited.class );
|
||||
final Audited allClassAudited = classDetails.getDirectAnnotationUsage( Audited.class );
|
||||
if ( allClassAudited != null && allClassAudited.auditParents().length > 0 ) {
|
||||
for ( Class c : allClassAudited.auditParents() ) {
|
||||
final XClass parentClass = reflectionManager.toXClass( c );
|
||||
checkSuperclass( clazz, parentClass );
|
||||
final ClassDetails parentClass = metadataBuildingContext.getClassDetailsRegistry()
|
||||
.resolveClassDetails( c.getName() );
|
||||
checkSuperclass( classDetails, parentClass );
|
||||
if ( !overriddenNotAuditedClasses.contains( parentClass ) ) {
|
||||
// If the class has not been marked as not audited by the subclass.
|
||||
overriddenAuditedClasses.add( parentClass );
|
||||
|
@ -181,15 +184,16 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
}
|
||||
/* TODO: Code to remove with @Audited.auditParents - finish. */
|
||||
final List<AuditOverride> auditOverrides = computeAuditOverrides( clazz );
|
||||
final List<AuditOverride> auditOverrides = computeAuditOverrides( classDetails );
|
||||
for ( AuditOverride auditOverride : auditOverrides ) {
|
||||
if ( auditOverride.forClass() != void.class ) {
|
||||
final XClass overrideClass = reflectionManager.toXClass( auditOverride.forClass() );
|
||||
checkSuperclass( clazz, overrideClass );
|
||||
final ClassDetails overrideClass = metadataBuildingContext.getClassDetailsRegistry()
|
||||
.resolveClassDetails( auditOverride.forClass().getName() );
|
||||
checkSuperclass( classDetails, overrideClass );
|
||||
final String propertyName = auditOverride.name();
|
||||
if ( !StringTools.isEmpty( propertyName ) ) {
|
||||
// Override @Audited annotation on property level.
|
||||
final XProperty property = getProperty( overrideClass, propertyName );
|
||||
final MemberDetails property = getProperty( overrideClass, propertyName );
|
||||
if ( auditOverride.isAudited() ) {
|
||||
if ( !overriddenNotAuditedProperties.contains( property ) ) {
|
||||
// If the property has not been marked as not audited by the subclass.
|
||||
|
@ -221,20 +225,20 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
}
|
||||
}
|
||||
final XClass superclass = clazz.getSuperclass();
|
||||
if ( !clazz.isInterface() && !Object.class.getName().equals( superclass.getName() ) ) {
|
||||
final ClassDetails superclass = classDetails.getSuperClass();
|
||||
if ( !classDetails.isInterface() && !Object.class.getName().equals( superclass.getName() ) ) {
|
||||
readAuditOverrides( superclass );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz Source class.
|
||||
* @param classDetails Source class.
|
||||
*
|
||||
* @return List of @AuditOverride annotations applied at class level.
|
||||
*/
|
||||
private List<AuditOverride> computeAuditOverrides(XClass clazz) {
|
||||
final AuditOverrides auditOverrides = clazz.getAnnotation( AuditOverrides.class );
|
||||
final AuditOverride auditOverride = clazz.getAnnotation( AuditOverride.class );
|
||||
private List<AuditOverride> computeAuditOverrides(ClassDetails classDetails) {
|
||||
final AuditOverrides auditOverrides = classDetails.getDirectAnnotationUsage( AuditOverrides.class );
|
||||
final AuditOverride auditOverride = classDetails.getDirectAnnotationUsage( AuditOverride.class );
|
||||
if ( auditOverrides == null && auditOverride != null ) {
|
||||
return Arrays.asList( auditOverride );
|
||||
}
|
||||
|
@ -244,7 +248,7 @@ public class AuditedPropertiesReader {
|
|||
else if ( auditOverrides != null && auditOverride != null ) {
|
||||
throw new EnversMappingException(
|
||||
"@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
|
||||
"Please revise Envers annotations applied to class " + clazz.getName() + "."
|
||||
"Please revise Envers annotations applied to class " + classDetails.getName() + "."
|
||||
);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
|
@ -256,8 +260,8 @@ public class AuditedPropertiesReader {
|
|||
* @param child Subclass.
|
||||
* @param parent Superclass.
|
||||
*/
|
||||
private void checkSuperclass(XClass child, XClass parent) {
|
||||
if ( !parent.isAssignableFrom( child ) ) {
|
||||
private void checkSuperclass(ClassDetails child, ClassDetails parent) {
|
||||
if ( !child.isImplementor( parent.toJavaClass() ) ) {
|
||||
throw new EnversMappingException(
|
||||
"Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
|
||||
"Please revise Envers annotations applied to " + child.getName() + " type."
|
||||
|
@ -268,20 +272,20 @@ public class AuditedPropertiesReader {
|
|||
/**
|
||||
* Checks whether class contains property with a given name. If not {@link EnversMappingException} is thrown.
|
||||
*
|
||||
* @param clazz Class.
|
||||
* @param classDetails Class.
|
||||
* @param propertyName Property name.
|
||||
*
|
||||
* @return Property object.
|
||||
*/
|
||||
private XProperty getProperty(XClass clazz, String propertyName) {
|
||||
final XProperty property = ReflectionTools.getProperty( clazz, propertyName );
|
||||
if ( property == null ) {
|
||||
private MemberDetails getProperty(ClassDetails classDetails, String propertyName) {
|
||||
final MemberDetails member = getMember( classDetails, propertyName );
|
||||
if ( member == null ) {
|
||||
throw new EnversMappingException(
|
||||
"Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
|
||||
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + "."
|
||||
"Property '" + propertyName + "' not found in class " + classDetails.getName() + ". " +
|
||||
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getClassDetails() + "."
|
||||
);
|
||||
}
|
||||
return property;
|
||||
return member;
|
||||
}
|
||||
|
||||
private void readPersistentPropertiesAccess() {
|
||||
|
@ -313,7 +317,7 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param clazz Class which properties are currently being added.
|
||||
* @param classDetails Class which properties are currently being added.
|
||||
*
|
||||
* @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method
|
||||
* checks whether given class exists in {@link AuditedPropertiesReader#overriddenAuditedClasses} collection.
|
||||
|
@ -321,27 +325,27 @@ public class AuditedPropertiesReader {
|
|||
* {@code null}. If processed type exists in {@link AuditedPropertiesReader#overriddenNotAuditedClasses}
|
||||
* collection, the result is also {@code null}.
|
||||
*/
|
||||
private Audited computeAuditConfiguration(XClass clazz) {
|
||||
Audited allClassAudited = clazz.getAnnotation( Audited.class );
|
||||
private Audited computeAuditConfiguration(ClassDetails classDetails) {
|
||||
Audited allClassAudited = classDetails.getDirectAnnotationUsage( Audited.class );
|
||||
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
|
||||
// forced by any of its child entities configuration (@AuditedOverride.forClass).
|
||||
if ( allClassAudited == null && overriddenAuditedClasses.contains( clazz ) ) {
|
||||
if ( allClassAudited == null && overriddenAuditedClasses.contains( classDetails ) ) {
|
||||
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
|
||||
// currently mapped entity.
|
||||
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation( Audited.class );
|
||||
allClassAudited = persistentPropertiesSource.getClassDetails().getDirectAnnotationUsage( Audited.class );
|
||||
if ( allClassAudited == null ) {
|
||||
// If parent class declares @Audited on the field/property level.
|
||||
allClassAudited = DEFAULT_AUDITED;
|
||||
}
|
||||
}
|
||||
else if ( allClassAudited != null && overriddenNotAuditedClasses.contains( clazz ) ) {
|
||||
else if ( allClassAudited != null && overriddenNotAuditedClasses.contains( classDetails ) ) {
|
||||
return null;
|
||||
}
|
||||
return allClassAudited;
|
||||
}
|
||||
|
||||
private void addPropertiesFromDynamicComponent(PersistentPropertiesSource propertiesSource) {
|
||||
Audited audited = computeAuditConfiguration( propertiesSource.getXClass() );
|
||||
Audited audited = computeAuditConfiguration( propertiesSource.getClassDetails() );
|
||||
if ( !fieldAccessedPersistentProperties.isEmpty() ) {
|
||||
throw new EnversMappingException(
|
||||
"Audited dynamic component cannot have properties with access=\"field\" for properties: " +
|
||||
|
@ -354,20 +358,18 @@ public class AuditedPropertiesReader {
|
|||
String accessType = entry.getValue();
|
||||
if ( !auditedPropertiesHolder.contains( property ) ) {
|
||||
final Value propertyValue = persistentPropertiesSource.getProperty( property ).getValue();
|
||||
final SourceModelBuildingContext buildingContext = metadataBuildingContext.getSourceModelBuildingContext();
|
||||
final FieldDetails fieldDetails = dynamicFieldDetails( propertiesSource, property, buildingContext );
|
||||
if ( propertyValue instanceof Component ) {
|
||||
this.addFromComponentProperty(
|
||||
new DynamicProperty( propertiesSource, property ),
|
||||
fieldDetails,
|
||||
accessType,
|
||||
(Component) propertyValue,
|
||||
audited
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.addFromNotComponentProperty(
|
||||
new DynamicProperty( propertiesSource, property ),
|
||||
accessType,
|
||||
audited
|
||||
);
|
||||
this.addFromNotComponentProperty( fieldDetails, accessType, audited );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -376,29 +378,29 @@ public class AuditedPropertiesReader {
|
|||
/**
|
||||
* Recursively adds all audited properties of entity class and its superclasses.
|
||||
*
|
||||
* @param clazz Currently processed class.
|
||||
* @param classDetails Currently processed class.
|
||||
*/
|
||||
private void addPropertiesFromClass(XClass clazz) {
|
||||
final Audited allClassAudited = computeAuditConfiguration( clazz );
|
||||
private void addPropertiesFromClass(ClassDetails classDetails) {
|
||||
final Audited allClassAudited = computeAuditConfiguration( classDetails );
|
||||
|
||||
//look in the class
|
||||
addFromProperties(
|
||||
clazz.getDeclaredProperties( "field" ),
|
||||
classDetails.forEachField( (i, field) -> addFromProperty(
|
||||
field,
|
||||
it -> "field",
|
||||
fieldAccessedPersistentProperties,
|
||||
allClassAudited
|
||||
);
|
||||
addFromProperties(
|
||||
clazz.getDeclaredProperties( "property" ),
|
||||
) );
|
||||
classDetails.forEachMethod( (i, method) -> addFromProperty(
|
||||
method,
|
||||
propertyAccessedPersistentProperties::get,
|
||||
propertyAccessedPersistentProperties.keySet(),
|
||||
allClassAudited
|
||||
);
|
||||
) );
|
||||
|
||||
if ( isClassHierarchyTraversalNeeded( allClassAudited ) ) {
|
||||
final XClass superclazz = clazz.getSuperclass();
|
||||
if ( !clazz.isInterface() && !"java.lang.Object".equals( superclazz.getName() ) ) {
|
||||
addPropertiesFromClass( superclazz );
|
||||
final ClassDetails superclass = classDetails.getSuperClass();
|
||||
if ( !classDetails.isInterface() && !"java.lang.Object".equals( superclass.getName() ) ) {
|
||||
addPropertiesFromClass( superclass );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -407,53 +409,56 @@ public class AuditedPropertiesReader {
|
|||
return allClassAudited != null || !auditedPropertiesHolder.isEmpty();
|
||||
}
|
||||
|
||||
private void addFromProperties(
|
||||
Iterable<XProperty> properties,
|
||||
private void addFromProperty(
|
||||
MemberDetails memberDetails,
|
||||
Function<String, String> accessTypeProvider,
|
||||
Set<String> persistentProperties,
|
||||
Audited allClassAudited) {
|
||||
for ( XProperty property : properties ) {
|
||||
final String accessType = accessTypeProvider.apply( property.getName() );
|
||||
if ( !memberDetails.isPersistable() || memberDetails.hasDirectAnnotationUsage( Transient.class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is not a persistent property, with the same access type as currently checked,
|
||||
// it's not audited as well.
|
||||
// If the property was already defined by the subclass, is ignored by superclasses
|
||||
if ( persistentProperties.contains( property.getName() )
|
||||
&& !auditedPropertiesHolder.contains( property.getName() ) ) {
|
||||
final Value propertyValue = persistentPropertiesSource.getProperty( property.getName() ).getValue();
|
||||
if ( propertyValue instanceof Component ) {
|
||||
this.addFromComponentProperty( property, accessType, (Component) propertyValue, allClassAudited );
|
||||
}
|
||||
else {
|
||||
this.addFromNotComponentProperty( property, accessType, allClassAudited );
|
||||
}
|
||||
final String attributeName = memberDetails.resolveAttributeName();
|
||||
final String accessType = accessTypeProvider.apply( attributeName );
|
||||
|
||||
// If this is not a persistent property, with the same access type as currently checked,
|
||||
// it's not audited as well.
|
||||
// If the property was already defined by the subclass, is ignored by superclasses
|
||||
if ( persistentProperties.contains( attributeName )
|
||||
&& !auditedPropertiesHolder.contains( attributeName ) ) {
|
||||
final Value propertyValue = persistentPropertiesSource.getProperty( attributeName ).getValue();
|
||||
if ( propertyValue instanceof Component ) {
|
||||
this.addFromComponentProperty( memberDetails, accessType, (Component) propertyValue, allClassAudited );
|
||||
}
|
||||
else if ( propertiesGroupMapping.containsKey( property.getName() ) ) {
|
||||
// Retrieve embedded component name based on class field.
|
||||
final String embeddedName = propertiesGroupMapping.get( property.getName() );
|
||||
if ( !auditedPropertiesHolder.contains( embeddedName ) ) {
|
||||
// Manage properties mapped within <properties> tag.
|
||||
final Value propertyValue = persistentPropertiesSource.getProperty( embeddedName ).getValue();
|
||||
this.addFromPropertiesGroup(
|
||||
embeddedName,
|
||||
property,
|
||||
accessType,
|
||||
(Component) propertyValue,
|
||||
allClassAudited
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.addFromNotComponentProperty( memberDetails, accessType, allClassAudited );
|
||||
}
|
||||
}
|
||||
else if ( propertiesGroupMapping.containsKey( attributeName ) ) {
|
||||
// Retrieve embedded component name based on class field.
|
||||
final String embeddedName = propertiesGroupMapping.get( attributeName );
|
||||
if ( !auditedPropertiesHolder.contains( embeddedName ) ) {
|
||||
// Manage properties mapped within <properties> tag.
|
||||
final Value propertyValue = persistentPropertiesSource.getProperty( embeddedName ).getValue();
|
||||
this.addFromPropertiesGroup(
|
||||
embeddedName,
|
||||
memberDetails,
|
||||
accessType,
|
||||
(Component) propertyValue,
|
||||
allClassAudited
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addFromPropertiesGroup(
|
||||
String embeddedName,
|
||||
XProperty property,
|
||||
MemberDetails memberDetails,
|
||||
String accessType,
|
||||
Component propertyValue,
|
||||
Audited allClassAudited) {
|
||||
final ComponentAuditingData componentData = new ComponentAuditingData();
|
||||
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
|
||||
final boolean isAudited = fillPropertyData( memberDetails, componentData, accessType, allClassAudited );
|
||||
if ( isAudited ) {
|
||||
// EntityPersister.getPropertyNames() returns name of embedded component instead of class field.
|
||||
componentData.setName( embeddedName );
|
||||
|
@ -477,17 +482,18 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
|
||||
private void addFromComponentProperty(
|
||||
XProperty property,
|
||||
MemberDetails memberDetails,
|
||||
String accessType,
|
||||
Component propertyValue,
|
||||
Audited allClassAudited) {
|
||||
final ComponentAuditingData componentData = new ComponentAuditingData();
|
||||
final boolean isAudited = fillPropertyData( property, componentData, accessType, allClassAudited );
|
||||
final boolean isAudited = fillPropertyData( memberDetails, componentData, accessType, allClassAudited );
|
||||
|
||||
final PersistentPropertiesSource componentPropertiesSource;
|
||||
if ( propertyValue.isDynamic() ) {
|
||||
final XClass xClass = metadataBuildingContext.getReflectionManager().toXClass( Map.class );
|
||||
componentPropertiesSource = PersistentPropertiesSource.forComponent( propertyValue, xClass, true );
|
||||
final ClassDetails mapClassDetails = metadataBuildingContext.getClassDetailsRegistry()
|
||||
.getClassDetails( Map.class.getName() );
|
||||
componentPropertiesSource = PersistentPropertiesSource.forComponent( propertyValue, mapClassDetails, true );
|
||||
}
|
||||
else {
|
||||
componentPropertiesSource = PersistentPropertiesSource.forComponent( metadataBuildingContext, propertyValue );
|
||||
|
@ -497,23 +503,23 @@ public class AuditedPropertiesReader {
|
|||
metadataBuildingContext,
|
||||
componentPropertiesSource,
|
||||
componentData,
|
||||
propertyNamePrefix + MappingTools.createComponentPrefix( property.getName() )
|
||||
propertyNamePrefix + MappingTools.createComponentPrefix( memberDetails.resolveAttributeName() )
|
||||
);
|
||||
audPropReader.read( allClassAudited );
|
||||
|
||||
if ( isAudited ) {
|
||||
// Now we know that the property is audited
|
||||
auditedPropertiesHolder.addPropertyAuditingData( property.getName(), componentData );
|
||||
auditedPropertiesHolder.addPropertyAuditingData( memberDetails.resolveAttributeName(), componentData );
|
||||
}
|
||||
}
|
||||
|
||||
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited) {
|
||||
private void addFromNotComponentProperty(MemberDetails memberDetails, String accessType, Audited allClassAudited) {
|
||||
final PropertyAuditingData propertyData = new PropertyAuditingData();
|
||||
final boolean isAudited = fillPropertyData( property, propertyData, accessType, allClassAudited );
|
||||
final boolean isAudited = fillPropertyData( memberDetails, propertyData, accessType, allClassAudited );
|
||||
|
||||
if ( isAudited ) {
|
||||
// Now we know that the property is audited
|
||||
auditedPropertiesHolder.addPropertyAuditingData( property.getName(), propertyData );
|
||||
auditedPropertiesHolder.addPropertyAuditingData( memberDetails.resolveAttributeName(), propertyData );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -521,59 +527,59 @@ public class AuditedPropertiesReader {
|
|||
/**
|
||||
* Checks if a property is audited and if yes, fills all of its data.
|
||||
*
|
||||
* @param property Property to check.
|
||||
* @param memberDetails Property to check.
|
||||
* @param propertyData Property data, on which to set this property's modification store.
|
||||
* @param accessType Access type for the property.
|
||||
*
|
||||
* @return False if this property is not audited.
|
||||
*/
|
||||
private boolean fillPropertyData(
|
||||
XProperty property,
|
||||
MemberDetails memberDetails,
|
||||
PropertyAuditingData propertyData,
|
||||
String accessType,
|
||||
Audited allClassAudited) {
|
||||
|
||||
// check if a property is declared as not audited to exclude it
|
||||
// useful if a class is audited but some properties should be excluded
|
||||
final NotAudited unVer = property.getAnnotation( NotAudited.class );
|
||||
final NotAudited unVer = memberDetails.getDirectAnnotationUsage( NotAudited.class );
|
||||
if ( ( unVer != null
|
||||
&& !overriddenAuditedProperties.contains( property ) )
|
||||
|| overriddenNotAuditedProperties.contains( property ) ) {
|
||||
&& !overriddenAuditedProperties.contains( memberDetails ) )
|
||||
|| overriddenNotAuditedProperties.contains( memberDetails ) ) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// if the optimistic locking field has to be unversioned and the current property
|
||||
// is the optimistic locking field, don't audit it
|
||||
if ( metadataBuildingContext.getConfiguration().isDoNotAuditOptimisticLockingField() ) {
|
||||
final Version jpaVer = property.getAnnotation( Version.class );
|
||||
final Version jpaVer = memberDetails.getDirectAnnotationUsage( Version.class );
|
||||
if ( jpaVer != null ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String propertyName = propertyNamePrefix + property.getName();
|
||||
final String propertyName = propertyNamePrefix + memberDetails.resolveAttributeName();
|
||||
final String modifiedFlagsSuffix = metadataBuildingContext.getConfiguration().getModifiedFlagsSuffix();
|
||||
if ( !this.checkAudited( property, propertyData,propertyName, allClassAudited, modifiedFlagsSuffix ) ) {
|
||||
if ( !this.checkAudited( memberDetails, propertyData,propertyName, allClassAudited, modifiedFlagsSuffix ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
validateLobMappingSupport( property );
|
||||
validateLobMappingSupport( memberDetails );
|
||||
|
||||
propertyData.setName( propertyName );
|
||||
propertyData.setBeanName( property.getName() );
|
||||
propertyData.setBeanName( memberDetails.resolveAttributeName() );
|
||||
propertyData.setAccessType( accessType );
|
||||
|
||||
addPropertyJoinTables( property, propertyData );
|
||||
addPropertyCollectionAuditTable( property, propertyData );
|
||||
addPropertyAuditingOverrides( property, propertyData );
|
||||
if ( !processPropertyAuditingOverrides( property, propertyData ) ) {
|
||||
addPropertyJoinTables( memberDetails, propertyData );
|
||||
addPropertyCollectionAuditTable( memberDetails, propertyData );
|
||||
addPropertyAuditingOverrides( memberDetails, propertyData );
|
||||
if ( !processPropertyAuditingOverrides( memberDetails, propertyData ) ) {
|
||||
// not audited due to AuditOverride annotation
|
||||
return false;
|
||||
}
|
||||
addPropertyMapKey( property, propertyData );
|
||||
setPropertyAuditMappedBy( property, propertyData );
|
||||
setPropertyRelationMappedBy( property, propertyData );
|
||||
addPropertyMapKey( memberDetails, propertyData );
|
||||
setPropertyAuditMappedBy( memberDetails, propertyData );
|
||||
setPropertyRelationMappedBy( memberDetails, propertyData );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -588,8 +594,9 @@ public class AuditedPropertiesReader {
|
|||
|
||||
final PersistentPropertiesSource componentPropertiesSource;
|
||||
if ( propertyValue.isDynamic() ) {
|
||||
final XClass xClass = metadataBuildingContext.getReflectionManager().toXClass( Map.class );
|
||||
componentPropertiesSource = PersistentPropertiesSource.forComponent( propertyValue, xClass, true );
|
||||
final ClassDetails mapClassDetails = metadataBuildingContext.getClassDetailsRegistry()
|
||||
.getClassDetails( Map.class.getName() );
|
||||
componentPropertiesSource = PersistentPropertiesSource.forComponent( propertyValue, mapClassDetails, true );
|
||||
}
|
||||
else {
|
||||
componentPropertiesSource = PersistentPropertiesSource.forComponent( metadataBuildingContext, propertyValue );
|
||||
|
@ -654,12 +661,12 @@ public class AuditedPropertiesReader {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void validateLobMappingSupport(XProperty property) {
|
||||
private void validateLobMappingSupport(MemberDetails memberDetails) {
|
||||
// HHH-9834 - Sanity check
|
||||
try {
|
||||
if ( property.isAnnotationPresent( ElementCollection.class ) ) {
|
||||
if ( property.isAnnotationPresent( Lob.class ) ) {
|
||||
if ( !property.getCollectionClass().isAssignableFrom( Map.class ) ) {
|
||||
if ( memberDetails.hasDirectAnnotationUsage( ElementCollection.class ) ) {
|
||||
if ( memberDetails.hasDirectAnnotationUsage( Lob.class ) ) {
|
||||
if ( !memberDetails.getType().isImplementor( Map.class ) ) {
|
||||
throw new EnversMappingException(
|
||||
"@ElementCollection combined with @Lob is only supported for Map collection types."
|
||||
);
|
||||
|
@ -672,8 +679,8 @@ public class AuditedPropertiesReader {
|
|||
String.format(
|
||||
Locale.ENGLISH,
|
||||
"Invalid mapping in [%s] for property [%s]",
|
||||
property.getDeclaringClass().getName(),
|
||||
property.getName()
|
||||
memberDetails.getDeclaringType().getName(),
|
||||
memberDetails.resolveAttributeName()
|
||||
),
|
||||
e
|
||||
);
|
||||
|
@ -681,23 +688,23 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
|
||||
protected boolean checkAudited(
|
||||
XProperty property,
|
||||
MemberDetails memberDetails,
|
||||
PropertyAuditingData propertyData, String propertyName,
|
||||
Audited allClassAudited, String modifiedFlagSuffix) {
|
||||
// Checking if this property is explicitly audited or if all properties are.
|
||||
Audited aud = ( property.isAnnotationPresent( Audited.class ) )
|
||||
? property.getAnnotation( Audited.class )
|
||||
Audited aud = ( memberDetails.hasDirectAnnotationUsage( Audited.class ) )
|
||||
? memberDetails.getDirectAnnotationUsage( Audited.class )
|
||||
: allClassAudited;
|
||||
if ( aud == null
|
||||
&& overriddenAuditedProperties.contains( property )
|
||||
&& !overriddenNotAuditedProperties.contains( property ) ) {
|
||||
&& overriddenAuditedProperties.contains( memberDetails )
|
||||
&& !overriddenNotAuditedProperties.contains( memberDetails ) ) {
|
||||
// Assigning @Audited defaults. If anyone needs to customize those values in the future,
|
||||
// appropriate fields shall be added to @AuditOverride annotation.
|
||||
aud = DEFAULT_AUDITED;
|
||||
}
|
||||
if ( aud != null ) {
|
||||
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||
propertyData.setRelationTargetNotFoundAction( getRelationNotFoundAction( property, allClassAudited ) );
|
||||
propertyData.setRelationTargetNotFoundAction( getRelationNotFoundAction( memberDetails, allClassAudited ) );
|
||||
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||
propertyData.setModifiedFlagName( ModifiedColumnNameResolver.getName( propertyName, modifiedFlagSuffix ) );
|
||||
if ( !StringTools.isEmpty( aud.modifiedColumnName() ) ) {
|
||||
|
@ -748,15 +755,15 @@ public class AuditedPropertiesReader {
|
|||
return aud.withModifiedFlag();
|
||||
}
|
||||
|
||||
private void setPropertyRelationMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
||||
final OneToMany oneToMany = property.getAnnotation( OneToMany.class );
|
||||
private void setPropertyRelationMappedBy(MemberDetails memberDetails, PropertyAuditingData propertyData) {
|
||||
final OneToMany oneToMany = memberDetails.getDirectAnnotationUsage( OneToMany.class );
|
||||
if ( oneToMany != null && StringHelper.isNotEmpty( oneToMany.mappedBy() ) ) {
|
||||
propertyData.setRelationMappedBy( oneToMany.mappedBy() );
|
||||
}
|
||||
}
|
||||
|
||||
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
||||
final AuditMappedBy auditMappedBy = property.getAnnotation( AuditMappedBy.class );
|
||||
private void setPropertyAuditMappedBy(MemberDetails memberDetails, PropertyAuditingData propertyData) {
|
||||
final AuditMappedBy auditMappedBy = memberDetails.getDirectAnnotationUsage( AuditMappedBy.class );
|
||||
if ( auditMappedBy != null ) {
|
||||
propertyData.setAuditMappedBy( auditMappedBy.mappedBy() );
|
||||
if ( StringHelper.isNotEmpty( auditMappedBy.positionMappedBy() ) ) {
|
||||
|
@ -765,20 +772,20 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
}
|
||||
|
||||
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
|
||||
final MapKey mapKey = property.getAnnotation( MapKey.class );
|
||||
private void addPropertyMapKey(MemberDetails memberDetails, PropertyAuditingData propertyData) {
|
||||
final MapKey mapKey = memberDetails.getDirectAnnotationUsage( MapKey.class );
|
||||
if ( mapKey != null ) {
|
||||
propertyData.setMapKey( mapKey.name() );
|
||||
}
|
||||
else {
|
||||
final MapKeyEnumerated mapKeyEnumerated = property.getAnnotation( MapKeyEnumerated.class );
|
||||
final MapKeyEnumerated mapKeyEnumerated = memberDetails.getDirectAnnotationUsage( MapKeyEnumerated.class );
|
||||
if ( mapKeyEnumerated != null ) {
|
||||
propertyData.setMapKeyEnumType( mapKeyEnumerated.value() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
|
||||
private void addPropertyJoinTables(MemberDetails memberDetails, PropertyAuditingData propertyData) {
|
||||
// The AuditJoinTable annotation source will follow the following priority rules
|
||||
// 1. Use the override if one is specified
|
||||
// 2. Use the site annotation if one is specified
|
||||
|
@ -788,12 +795,12 @@ public class AuditedPropertiesReader {
|
|||
// the join-table specified there should have a higher priority in the event the
|
||||
// super-class defines an equivalent @AuditJoinTable at the site/property level.
|
||||
|
||||
final AuditJoinTable overrideJoinTable = overriddenAuditedPropertiesJoinTables.get( property );
|
||||
final AuditJoinTable overrideJoinTable = overriddenAuditedPropertiesJoinTables.get( memberDetails );
|
||||
if ( overrideJoinTable != null ) {
|
||||
propertyData.setJoinTable( new AuditJoinTableData( overrideJoinTable ) );
|
||||
}
|
||||
else {
|
||||
final AuditJoinTable propertyJoinTable = property.getAnnotation( AuditJoinTable.class );
|
||||
final AuditJoinTable propertyJoinTable = memberDetails.getDirectAnnotationUsage( AuditJoinTable.class );
|
||||
if ( propertyJoinTable != null ) {
|
||||
propertyData.setJoinTable( new AuditJoinTableData( propertyJoinTable ) );
|
||||
}
|
||||
|
@ -803,8 +810,8 @@ public class AuditedPropertiesReader {
|
|||
}
|
||||
}
|
||||
|
||||
private void addPropertyCollectionAuditTable(XProperty property, PropertyAuditingData propertyAuditingData) {
|
||||
final CollectionAuditTable collectionAuditTableAnn = property.getAnnotation( CollectionAuditTable.class );
|
||||
private void addPropertyCollectionAuditTable(MemberDetails memberDetails, PropertyAuditingData propertyAuditingData) {
|
||||
final CollectionAuditTable collectionAuditTableAnn = memberDetails.getDirectAnnotationUsage( CollectionAuditTable.class );
|
||||
if ( collectionAuditTableAnn != null ) {
|
||||
propertyAuditingData.setCollectionAuditTable( collectionAuditTableAnn );
|
||||
}
|
||||
|
@ -813,15 +820,15 @@ public class AuditedPropertiesReader {
|
|||
/**
|
||||
* Add the {@link AuditOverride} annotations.
|
||||
*
|
||||
* @param property the property being processed
|
||||
* @param memberDetails the property being processed
|
||||
* @param propertyData the Envers auditing data for this property
|
||||
*/
|
||||
private void addPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
|
||||
final AuditOverride annotationOverride = property.getAnnotation( AuditOverride.class );
|
||||
private void addPropertyAuditingOverrides(MemberDetails memberDetails, PropertyAuditingData propertyData) {
|
||||
final AuditOverride annotationOverride = memberDetails.getDirectAnnotationUsage( AuditOverride.class );
|
||||
if ( annotationOverride != null ) {
|
||||
propertyData.addAuditingOverride( annotationOverride );
|
||||
}
|
||||
final AuditOverrides annotationOverrides = property.getAnnotation( AuditOverrides.class );
|
||||
final AuditOverrides annotationOverrides = memberDetails.getDirectAnnotationUsage( AuditOverrides.class );
|
||||
if ( annotationOverrides != null ) {
|
||||
propertyData.addAuditingOverrides( annotationOverrides );
|
||||
}
|
||||
|
@ -830,16 +837,16 @@ public class AuditedPropertiesReader {
|
|||
/**
|
||||
* Process the {@link AuditOverride} annotations for this property.
|
||||
*
|
||||
* @param property the property for which the {@link AuditOverride}
|
||||
* @param memberDetails the property for which the {@link AuditOverride}
|
||||
* annotations are being processed
|
||||
* @param propertyData the Envers auditing data for this property
|
||||
*
|
||||
* @return {@code false} if isAudited() of the override annotation was set to
|
||||
*/
|
||||
private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
|
||||
private boolean processPropertyAuditingOverrides(MemberDetails memberDetails, PropertyAuditingData propertyData) {
|
||||
// Only components register audit overrides, classes will have no entries.
|
||||
for ( AuditOverrideData override : auditedPropertiesHolder.getAuditingOverrides() ) {
|
||||
if ( property.getName().equals( override.getName() ) ) {
|
||||
if ( memberDetails.resolveAttributeName().equals( override.getName() ) ) {
|
||||
// the override applies to this property
|
||||
if ( !override.isAudited() ) {
|
||||
return false;
|
||||
|
@ -872,24 +879,24 @@ public class AuditedPropertiesReader {
|
|||
return true;
|
||||
}
|
||||
|
||||
protected boolean isOverriddenNotAudited(XProperty property) {
|
||||
return overriddenNotAuditedProperties.contains( property );
|
||||
protected boolean isOverriddenNotAudited(MemberDetails memberDetails) {
|
||||
return overriddenNotAuditedProperties.contains( memberDetails );
|
||||
}
|
||||
|
||||
protected boolean isOverriddenNotAudited(XClass clazz) {
|
||||
return overriddenNotAuditedClasses.contains( clazz );
|
||||
protected boolean isOverriddenNotAudited(ClassDetails classDetails) {
|
||||
return overriddenNotAuditedClasses.contains( classDetails );
|
||||
}
|
||||
|
||||
protected boolean isOverriddenAudited(XProperty property) {
|
||||
return overriddenAuditedProperties.contains( property );
|
||||
protected boolean isOverriddenAudited(MemberDetails memberDetails) {
|
||||
return overriddenAuditedProperties.contains( memberDetails );
|
||||
}
|
||||
|
||||
protected boolean isOverriddenAudited(XClass clazz) {
|
||||
return overriddenAuditedClasses.contains( clazz );
|
||||
protected boolean isOverriddenAudited(ClassDetails classDetails) {
|
||||
return overriddenAuditedClasses.contains( classDetails );
|
||||
}
|
||||
|
||||
private RelationTargetNotFoundAction getRelationNotFoundAction(XProperty property, Audited classAudited) {
|
||||
final Audited propertyAudited = property.getAnnotation( Audited.class );
|
||||
private RelationTargetNotFoundAction getRelationNotFoundAction(MemberDetails memberDetails, Audited classAudited) {
|
||||
final Audited propertyAudited = memberDetails.getDirectAnnotationUsage( Audited.class );
|
||||
|
||||
// class isn't annotated, check property
|
||||
if ( classAudited == null ) {
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.envers.configuration.internal.metadata.reader;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.envers.AuditOverride;
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.hibernate.envers.boot.internal.ModifiedColumnNameResolver;
|
||||
import org.hibernate.envers.boot.spi.EnversMetadataBuildingContext;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
import org.hibernate.models.spi.MemberDetails;
|
||||
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
|
||||
|
@ -56,13 +55,13 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
|||
|
||||
@Override
|
||||
protected boolean checkAudited(
|
||||
XProperty property,
|
||||
MemberDetails memberDetails,
|
||||
PropertyAuditingData propertyData,
|
||||
String propertyName,
|
||||
Audited allClassAudited,
|
||||
String modifiedFlagSuffix) {
|
||||
// Checking if this property is explicitly audited or if all properties are.
|
||||
final Audited aud = property.getAnnotation( Audited.class );
|
||||
final Audited aud = memberDetails.getDirectAnnotationUsage( Audited.class );
|
||||
if ( aud != null ) {
|
||||
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
|
||||
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );
|
||||
|
@ -74,7 +73,7 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
|||
else {
|
||||
|
||||
// get declaring class for property
|
||||
final XClass declaringClass = property.getDeclaringClass();
|
||||
final ClassDetails declaringClass = memberDetails.getDeclaringType();
|
||||
|
||||
// check component data to make sure that no audit overrides were not defined at
|
||||
// the parent class or the embeddable at the property level.
|
||||
|
@ -88,7 +87,7 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
|||
if ( "".equals( auditOverride.getName() ) ) {
|
||||
classNotAuditedOverride = true;
|
||||
}
|
||||
if ( property.getName().equals( auditOverride.getName() ) ) {
|
||||
if ( memberDetails.resolveAttributeName().equals( auditOverride.getName() ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +95,7 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
|||
if ( "".equals( auditOverride.getName() ) ) {
|
||||
classAuditedOverride = true;
|
||||
}
|
||||
if ( property.getName().equals( auditOverride.getName() ) ) {
|
||||
if ( memberDetails.resolveAttributeName().equals( auditOverride.getName() ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -105,12 +104,12 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
|||
}
|
||||
|
||||
// make sure taht if the class or property are explicitly 'isAudited=false', use that.
|
||||
if ( classNotAuditedOverride || isOverriddenNotAudited( property) || isOverriddenNotAudited( declaringClass ) ) {
|
||||
if ( classNotAuditedOverride || isOverriddenNotAudited( memberDetails ) || isOverriddenNotAudited( declaringClass ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure that if the class or property are explicitly 'isAudited=true', use that.
|
||||
if ( classAuditedOverride || isOverriddenAudited( property ) || isOverriddenAudited( declaringClass ) ) {
|
||||
if ( classAuditedOverride || isOverriddenAudited( memberDetails ) || isOverriddenAudited( declaringClass ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -122,7 +121,7 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
|
|||
// assumption here is if a component reader is looking at a @MappedSuperclass, it should be treated
|
||||
// as not being audited if we have reached htis point; allowing components and any @Embeddable
|
||||
// class being audited by default.
|
||||
if ( declaringClass.isAnnotationPresent( MappedSuperclass.class ) ) {
|
||||
if ( declaringClass.hasDirectAnnotationUsage( MappedSuperclass.class ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* 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.envers.configuration.internal.metadata.reader;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
|
||||
/**
|
||||
* This class pretends to be property but in fact it represents entry in the map (for dynamic component)
|
||||
*
|
||||
* @author Lukasz Zuchowski (author at zuchos dot com)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class DynamicProperty implements XProperty {
|
||||
|
||||
private final PersistentPropertiesSource source;
|
||||
private final String propertyName;
|
||||
|
||||
public DynamicProperty(PersistentPropertiesSource source, String propertyName) {
|
||||
this.source = source;
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XClass getDeclaringClass() {
|
||||
return source.getXClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollection() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Collection<?>> getCollectionClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XClass getType() {
|
||||
return source.getXClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XClass getElementClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XClass getClassOrElementClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XClass getMapKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getModifiers() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAccessible(boolean accessible) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object target, Object... parameters) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object target) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeResolved() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return new Annotation[0];
|
||||
}
|
||||
}
|
|
@ -8,14 +8,13 @@ package org.hibernate.envers.configuration.internal.metadata.reader;
|
|||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||
import org.hibernate.envers.boot.EnversMappingException;
|
||||
import org.hibernate.envers.boot.registry.classloading.ClassLoaderAccessHelper;
|
||||
import org.hibernate.envers.boot.spi.EnversMetadataBuildingContext;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
|
||||
/**
|
||||
* A source of data on persistent properties of a class or component.
|
||||
|
@ -28,7 +27,7 @@ public interface PersistentPropertiesSource {
|
|||
|
||||
Property getProperty(String propertyName);
|
||||
|
||||
XClass getXClass();
|
||||
ClassDetails getClassDetails();
|
||||
|
||||
boolean isDynamicComponent();
|
||||
|
||||
|
@ -38,10 +37,10 @@ public interface PersistentPropertiesSource {
|
|||
* Get a persistent properties source for a persistent class.
|
||||
*
|
||||
* @param persistentClass the persistent class
|
||||
* @param clazz the class
|
||||
* @param classDetails the class details
|
||||
* @return the properties source
|
||||
*/
|
||||
static PersistentPropertiesSource forClass(PersistentClass persistentClass, XClass clazz) {
|
||||
static PersistentPropertiesSource forClass(PersistentClass persistentClass, ClassDetails classDetails) {
|
||||
return new PersistentPropertiesSource() {
|
||||
@Override
|
||||
public Iterator<Property> getPropertyIterator() {
|
||||
|
@ -54,8 +53,8 @@ public interface PersistentPropertiesSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public XClass getXClass() {
|
||||
return clazz;
|
||||
public ClassDetails getClassDetails() {
|
||||
return classDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,9 +79,9 @@ public interface PersistentPropertiesSource {
|
|||
*/
|
||||
static PersistentPropertiesSource forComponent(EnversMetadataBuildingContext context, Component component, boolean dynamic) {
|
||||
try {
|
||||
Class<?> componentClass = ClassLoaderAccessHelper.loadClass( context, component.getComponentClassName() );
|
||||
XClass clazz = context.getReflectionManager().toXClass( componentClass );
|
||||
return forComponent( component, clazz, dynamic );
|
||||
final ClassDetails classDetails = context.getClassDetailsRegistry()
|
||||
.resolveClassDetails( component.getComponentClassName() );
|
||||
return forComponent( component, classDetails, dynamic );
|
||||
}
|
||||
catch (ClassLoadingException e) {
|
||||
throw new EnversMappingException( e );
|
||||
|
@ -97,11 +96,11 @@ public interface PersistentPropertiesSource {
|
|||
* Get a persistent properties source for a component with its class already resolved.
|
||||
*
|
||||
* @param component the component
|
||||
* @param clazz the class
|
||||
* @param classDetails the class details
|
||||
* @param dynamic whether the component is dynamic or not
|
||||
* @return the properties source
|
||||
*/
|
||||
static PersistentPropertiesSource forComponent(Component component, XClass clazz, boolean dynamic) {
|
||||
static PersistentPropertiesSource forComponent(Component component, ClassDetails classDetails, boolean dynamic) {
|
||||
return new PersistentPropertiesSource() {
|
||||
@Override
|
||||
public Iterator<Property> getPropertyIterator() {
|
||||
|
@ -114,8 +113,8 @@ public interface PersistentPropertiesSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public XClass getXClass() {
|
||||
return clazz;
|
||||
public ClassDetails getClassDetails() {
|
||||
return classDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,8 +10,6 @@ import java.lang.reflect.Field;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||
import org.hibernate.envers.exception.AuditException;
|
||||
|
@ -130,36 +128,6 @@ public abstract class ReflectionTools {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz Source class.
|
||||
* @param propertyName Property name.
|
||||
*
|
||||
* @return Property object or {@code null} if none with expected name has been found.
|
||||
*/
|
||||
public static XProperty getProperty(XClass clazz, String propertyName) {
|
||||
XProperty property = getProperty( clazz, propertyName, "field" );
|
||||
if ( property == null ) {
|
||||
property = getProperty( clazz, propertyName, "property" );
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz Source class.
|
||||
* @param propertyName Property name.
|
||||
* @param accessType Expected access type. Legal values are <i>field</i> and <i>property</i>.
|
||||
*
|
||||
* @return Property object or {@code null} if none with expected name and access type has been found.
|
||||
*/
|
||||
public static XProperty getProperty(XClass clazz, String propertyName, String accessType) {
|
||||
for ( XProperty property : clazz.getDeclaredProperties( accessType ) ) {
|
||||
if ( propertyName.equals( property.getName() ) ) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate class with a given name.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue