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