DATACMNS-365 - Enhanced auditing subsystem to work with accessor annotations.
Added a MappingAuditableBeanWrapperFactory to be able to use themapping metamodel to lookup annotations on persistent properties. This propagates into AuditingHandler and IsNewAwareAuditingHandler getting new constructors taking a MappingContext to set themselves up correctly. This will probably need store specific updates in the setup of the auditing infrastructure for namespace implementations and annotation based JavaConfig. Introduced ….getPersistentProperty(Class<? extends Annotation> annotationType) on PersistentEntity to be able to access properties with a given annotation. Updated SonarGraph architecture description and moved auditing related config classes into auditing.config package.
This commit is contained in:
@@ -22,7 +22,6 @@ import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDateTime;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.data.domain.Auditable;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
@@ -37,9 +36,6 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
class AuditableBeanWrapperFactory {
|
||||
|
||||
private static boolean IS_JODA_TIME_PRESENT = ClassUtils.isPresent("org.joda.time.DateTime",
|
||||
ReflectionAuditingBeanWrapper.class.getClassLoader());
|
||||
|
||||
/**
|
||||
* Returns an {@link AuditableBeanWrapper} if the given object is capable of being equipped with auditing information.
|
||||
*
|
||||
@@ -112,14 +108,69 @@ class AuditableBeanWrapperFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for {@link AuditableBeanWrapper} implementations that might need to convert {@link Calendar} values into
|
||||
* compatible types when setting date/time information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.8
|
||||
*/
|
||||
static abstract class DateConvertingAuditableBeanWrapper implements AuditableBeanWrapper {
|
||||
|
||||
private static boolean IS_JODA_TIME_PRESENT = ClassUtils.isPresent("org.joda.time.DateTime",
|
||||
ReflectionAuditingBeanWrapper.class.getClassLoader());
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DateConvertingAuditableBeanWrapper}.
|
||||
*/
|
||||
public DateConvertingAuditableBeanWrapper() {
|
||||
|
||||
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
|
||||
|
||||
if (IS_JODA_TIME_PRESENT) {
|
||||
conversionService.addConverter(CalendarToDateTimeConverter.INSTANCE);
|
||||
conversionService.addConverter(CalendarToLocalDateTimeConverter.INSTANCE);
|
||||
}
|
||||
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Calendar} in a type, compatible to the given field.
|
||||
*
|
||||
* @param value can be {@literal null}.
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Object getDateValueToSet(Calendar value, Class<?> targetType, Object source) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Calendar.class.equals(targetType)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (conversionService.canConvert(Calendar.class, targetType)) {
|
||||
return conversionService.convert(value, targetType);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Invalid date type for member %s! Supported types are %s.",
|
||||
source, AnnotationAuditingMetadata.SUPPORTED_DATE_TYPES));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link AuditableBeanWrapper} implementation that sets values on the target object using refelction.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class ReflectionAuditingBeanWrapper implements AuditableBeanWrapper {
|
||||
static class ReflectionAuditingBeanWrapper extends DateConvertingAuditableBeanWrapper {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
private final AnnotationAuditingMetadata metadata;
|
||||
private final Object target;
|
||||
|
||||
@@ -134,15 +185,6 @@ class AuditableBeanWrapperFactory {
|
||||
|
||||
this.metadata = AnnotationAuditingMetadata.getMetadata(target.getClass());
|
||||
this.target = target;
|
||||
|
||||
ConfigurableConversionService conversionService = new DefaultFormattingConversionService();
|
||||
|
||||
if (IS_JODA_TIME_PRESENT) {
|
||||
conversionService.addConverter(CalendarToDateTimeConverter.INSTANCE);
|
||||
conversionService.addConverter(CalendarToLocalDateTimeConverter.INSTANCE);
|
||||
}
|
||||
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -202,38 +244,11 @@ class AuditableBeanWrapperFactory {
|
||||
return;
|
||||
}
|
||||
|
||||
ReflectionUtils.setField(field, target, getDateValueToSet(value, field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DateTime} in a type compatible to the given field.
|
||||
*
|
||||
* @param value
|
||||
* @param field must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private Object getDateValueToSet(Calendar value, Field field) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> targetType = field.getType();
|
||||
|
||||
if (Calendar.class.equals(targetType)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (conversionService.canConvert(Calendar.class, targetType)) {
|
||||
return conversionService.convert(value, targetType);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Invalid date type for field %s! Supported types are %s.",
|
||||
field, AnnotationAuditingMetadata.SUPPORTED_DATE_TYPES));
|
||||
ReflectionUtils.setField(field, target, getDateValueToSet(value, field.getType(), field));
|
||||
}
|
||||
}
|
||||
|
||||
static enum CalendarToDateTimeConverter implements Converter<Calendar, DateTime> {
|
||||
private static enum CalendarToDateTimeConverter implements Converter<Calendar, DateTime> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -243,7 +258,7 @@ class AuditableBeanWrapperFactory {
|
||||
}
|
||||
}
|
||||
|
||||
static enum CalendarToLocalDateTimeConverter implements Converter<Calendar, LocalDateTime> {
|
||||
private static enum CalendarToLocalDateTimeConverter implements Converter<Calendar, LocalDateTime> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.data.domain.Auditable;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -35,16 +38,41 @@ public class AuditingHandler implements InitializingBean {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AuditingHandler.class);
|
||||
|
||||
private final AuditableBeanWrapperFactory factory = new AuditableBeanWrapperFactory();
|
||||
private final AuditableBeanWrapperFactory factory;
|
||||
|
||||
private DateTimeProvider dateTimeProvider = CurrentDateTimeProvider.INSTANCE;
|
||||
private AuditorAware<?> auditorAware;
|
||||
private boolean dateTimeForNow = true;
|
||||
private boolean modifyOnCreation = true;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AuditingHandler}.
|
||||
*
|
||||
* @deprecated use the constructor taking a {@link MappingContext}.
|
||||
*/
|
||||
@Deprecated
|
||||
public AuditingHandler() {
|
||||
this.factory = new AuditableBeanWrapperFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AuditableBeanWrapper} using the given {@link MappingContext} when looking up auditing metadata
|
||||
* via reflection.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
* @since 1.8
|
||||
*/
|
||||
public AuditingHandler(
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext) {
|
||||
|
||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||
this.factory = new MappingAuditableBeanWrapperFactory(mappingContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter to inject a {@code AuditorAware} component to retrieve the current auditor.
|
||||
*
|
||||
* @param auditorAware the auditorAware to set
|
||||
* @param auditorAware must not be {@literal null}.
|
||||
*/
|
||||
public void setAuditorAware(final AuditorAware<?> auditorAware) {
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
||||
import org.springframework.data.support.IsNewStrategy;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -31,14 +35,31 @@ public class IsNewAwareAuditingHandler extends AuditingHandler {
|
||||
|
||||
private final IsNewStrategyFactory isNewStrategyFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link IsNewAwareAuditingHandler} for the given {@link MappingContext}.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
* @since 1.8
|
||||
*/
|
||||
public IsNewAwareAuditingHandler(
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext) {
|
||||
|
||||
super(mappingContext);
|
||||
|
||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||
this.isNewStrategyFactory = new MappingContextIsNewStrategyFactory(mappingContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link IsNewAwareAuditingHandler} using the given {@link IsNewStrategyFactory}.
|
||||
*
|
||||
* @param isNewStrategyFactory must not be {@literal null}.
|
||||
* @deprecated use constructor taking a {@link MappingContext} directly. Will be removed in 1.9.
|
||||
*/
|
||||
@Deprecated
|
||||
public IsNewAwareAuditingHandler(IsNewStrategyFactory isNewStrategyFactory) {
|
||||
|
||||
Assert.notNull(isNewStrategyFactory, "IsNewStrategy must not be null!");
|
||||
Assert.notNull(isNewStrategyFactory, "IsNewStrategyFactory must not be null!");
|
||||
this.isNewStrategyFactory = isNewStrategyFactory;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.domain.Auditable;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link AuditableBeanWrapperFactory} that will create am {@link AuditableBeanWrapper} using mapping information
|
||||
* obtained from a {@link MappingContext} to detect auditing configuration and eventually invoking setting the auditing
|
||||
* values.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.8
|
||||
*/
|
||||
class MappingAuditableBeanWrapperFactory extends AuditableBeanWrapperFactory {
|
||||
|
||||
private final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext;
|
||||
private final Map<Class<?>, MappingAuditingMetadata> metadataCache;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingAuditableBeanWrapperFactory} using the given {@link MappingContext}.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
public MappingAuditableBeanWrapperFactory(
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext) {
|
||||
|
||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||
|
||||
this.mappingContext = mappingContext;
|
||||
this.metadataCache = new HashMap<Class<?>, MappingAuditingMetadata>();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapperFactory#getBeanWrapperFor(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public AuditableBeanWrapper getBeanWrapperFor(Object source) {
|
||||
|
||||
if (source instanceof Auditable) {
|
||||
return super.getBeanWrapperFor(source);
|
||||
}
|
||||
|
||||
Class<?> type = source.getClass();
|
||||
PersistentEntity<?, ?> entity = mappingContext.getPersistentEntity(type);
|
||||
|
||||
if (entity == null) {
|
||||
return super.getBeanWrapperFor(source);
|
||||
}
|
||||
|
||||
MappingAuditingMetadata metadata = metadataCache.get(type);
|
||||
|
||||
if (metadata == null) {
|
||||
metadata = new MappingAuditingMetadata(entity);
|
||||
metadataCache.put(type, metadata);
|
||||
}
|
||||
|
||||
return metadata.isAuditable() ? new MappingMetadataAuditableBeanWrapper(source, metadata) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures {@link PersistentProperty} instances equipped with auditing annotations.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.8
|
||||
*/
|
||||
static class MappingAuditingMetadata {
|
||||
|
||||
private final PersistentProperty<?> createdByProperty, createdDateProperty, lastModifiedByProperty,
|
||||
lastModifiedDateProperty;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingAuditingMetadata} instance from the given {@link PersistentEntity}.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public MappingAuditingMetadata(PersistentEntity<?, ? extends PersistentProperty<?>> entity) {
|
||||
|
||||
Assert.notNull(entity, "PersistentEntity must not be null!");
|
||||
|
||||
this.createdByProperty = entity.getPersistentProperty(CreatedBy.class);
|
||||
this.createdDateProperty = entity.getPersistentProperty(CreatedDate.class);
|
||||
this.lastModifiedByProperty = entity.getPersistentProperty(LastModifiedBy.class);
|
||||
this.lastModifiedDateProperty = entity.getPersistentProperty(LastModifiedDate.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} is auditable at all (read: any of the auditing annotations is
|
||||
* present).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAuditable() {
|
||||
return createdByProperty != null || createdDateProperty != null || lastModifiedByProperty != null
|
||||
|| lastModifiedDateProperty != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AuditableBeanWrapper} using {@link MappingAuditingMetadata} and a {@link BeanWrapper} to set values on
|
||||
* auditing properties.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.8
|
||||
*/
|
||||
static class MappingMetadataAuditableBeanWrapper extends DateConvertingAuditableBeanWrapper {
|
||||
|
||||
private final BeanWrapper<Object> wrapper;
|
||||
private final MappingAuditingMetadata metadata;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingMetadataAuditableBeanWrapper} for the given taregt and
|
||||
* {@link MappingAuditingMetadata}.
|
||||
*
|
||||
* @param target must not be {@literal null}.
|
||||
* @param metadata must not be {@literal null}.
|
||||
*/
|
||||
public MappingMetadataAuditableBeanWrapper(Object target, MappingAuditingMetadata metadata) {
|
||||
|
||||
Assert.notNull(target, "Target object must not be null!");
|
||||
Assert.notNull(metadata, "Auditing metadata must not be null!");
|
||||
|
||||
this.wrapper = BeanWrapper.create(target, null);
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedBy(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void setCreatedBy(Object value) {
|
||||
|
||||
if (metadata.createdByProperty != null) {
|
||||
this.wrapper.setProperty(metadata.createdByProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedDate(java.util.Calendar)
|
||||
*/
|
||||
@Override
|
||||
public void setCreatedDate(Calendar value) {
|
||||
|
||||
PersistentProperty<?> property = metadata.createdDateProperty;
|
||||
|
||||
if (property != null) {
|
||||
this.wrapper.setProperty(property, getDateValueToSet(value, property.getType(), property));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedBy(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void setLastModifiedBy(Object value) {
|
||||
|
||||
if (metadata.lastModifiedByProperty != null) {
|
||||
this.wrapper.setProperty(metadata.lastModifiedByProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedDate(java.util.Calendar)
|
||||
*/
|
||||
@Override
|
||||
public void setLastModifiedDate(Calendar value) {
|
||||
|
||||
PersistentProperty<?> property = metadata.lastModifiedDateProperty;
|
||||
|
||||
if (property != null) {
|
||||
this.wrapper.setProperty(property, getDateValueToSet(value, property.getType(), property));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,17 +13,23 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
package org.springframework.data.auditing.config;
|
||||
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactoryBean;
|
||||
import org.springframework.aop.target.LazyInitTargetSource;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.auditing.AuditingHandler;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
@@ -37,6 +43,30 @@ public class AuditingHandlerBeanDefinitionParser extends AbstractSingleBeanDefin
|
||||
|
||||
private static final String AUDITOR_AWARE_REF = "auditor-aware-ref";
|
||||
|
||||
private final String mappingContextBeanName;
|
||||
private String resolvedBeanName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AuditingHandlerBeanDefinitionParser} to point to a {@link MappingContext} with the given bean
|
||||
* name.
|
||||
*
|
||||
* @param mappingContextBeanName must not be {@literal null} or empty.
|
||||
*/
|
||||
public AuditingHandlerBeanDefinitionParser(String mappingContextBeanName) {
|
||||
|
||||
Assert.hasText(mappingContextBeanName, "MappingContext bean name must not be null!");
|
||||
this.mappingContextBeanName = mappingContextBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the bean definition the {@link AuditingHandler} was registered under.
|
||||
*
|
||||
* @return the resolvedBeanName
|
||||
*/
|
||||
public String getResolvedBeanName() {
|
||||
return resolvedBeanName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
||||
@@ -62,6 +92,8 @@ public class AuditingHandlerBeanDefinitionParser extends AbstractSingleBeanDefin
|
||||
@Override
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
builder.addConstructorArgReference(mappingContextBeanName);
|
||||
|
||||
String auditorAwareRef = element.getAttribute(AUDITOR_AWARE_REF);
|
||||
|
||||
if (StringUtils.hasText(auditorAwareRef)) {
|
||||
@@ -73,6 +105,18 @@ public class AuditingHandlerBeanDefinitionParser extends AbstractSingleBeanDefin
|
||||
ParsingUtils.setPropertyValue(builder, element, "modify-on-creation", "modifyOnCreation");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
this.resolvedBeanName = super.resolveId(element, definition, parserContext);
|
||||
return resolvedBeanName;
|
||||
}
|
||||
|
||||
private BeanDefinition createLazyInitTargetSourceBeanDefinition(String auditorAwareRef) {
|
||||
|
||||
BeanDefinitionBuilder targetSourceBuilder = rootBeanDefinition(LazyInitTargetSource.class);
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.auditing.config;
|
||||
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link AuditingHandlerBeanDefinitionParser} that will register am {@link IsNewAwareAuditingHandler}. Needs to get the
|
||||
* bean id of the {@link MappingContext} it shall refer to.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public class IsNewAwareAuditingHandlerBeanDefinitionParser extends AuditingHandlerBeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* Creates a new {@link IsNewAwareAuditingHandlerBeanDefinitionParser}.
|
||||
*
|
||||
* @param mappingContextBeanName must not be {@literal null} or empty.
|
||||
*/
|
||||
public IsNewAwareAuditingHandlerBeanDefinitionParser(String mappingContextBeanName) {
|
||||
super(mappingContextBeanName);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.config.AuditingHandlerBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return IsNewAwareAuditingHandler.class;
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.config;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link AuditingHandlerBeanDefinitionParser} that will register am {@link IsNewAwareAuditingHandler}. Needs to get the
|
||||
* bean id of the
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class IsNewAwareAuditingHandlerBeanDefinitionParser extends AuditingHandlerBeanDefinitionParser {
|
||||
|
||||
private final String isNewStrategyFactoryBeanId;
|
||||
private String resolvedBeanName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link IsNewAwareAuditingHandlerBeanDefinitionParser}.
|
||||
*
|
||||
* @param isNewStrategyFactoryBeanId must not be {@literal null} or empty.
|
||||
*/
|
||||
public IsNewAwareAuditingHandlerBeanDefinitionParser(String isNewStrategyFactoryBeanId) {
|
||||
|
||||
Assert.hasText(isNewStrategyFactoryBeanId);
|
||||
this.isNewStrategyFactoryBeanId = isNewStrategyFactoryBeanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bean name that was used to register the {@link IsNewAwareAuditingHandler}.
|
||||
*
|
||||
* @return the resolvedBeanName
|
||||
*/
|
||||
public String getResolvedBeanName() {
|
||||
return resolvedBeanName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.config.AuditingHandlerBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return IsNewAwareAuditingHandler.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.config.AuditingHandlerBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
builder.addConstructorArgReference(isNewStrategyFactoryBeanId);
|
||||
super.doParse(element, builder);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
this.resolvedBeanName = super.resolveId(element, definition, parserContext);
|
||||
return resolvedBeanName;
|
||||
}
|
||||
}
|
||||
@@ -96,6 +96,15 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
*/
|
||||
P getPersistentProperty(String name);
|
||||
|
||||
/**
|
||||
* Returns the property equipped with an annotation of the given type.
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.8
|
||||
*/
|
||||
P getPersistentProperty(Class<? extends Annotation> annotationType);
|
||||
|
||||
/**
|
||||
* Returns whether the {@link PersistentEntity} has an id property. If this call returns {@literal true},
|
||||
* {@link #getIdProperty()} will return a non-{@literal null} value.
|
||||
@@ -158,6 +167,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> {
|
||||
*
|
||||
* @param annotationType must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.8
|
||||
*/
|
||||
<A extends Annotation> A findAnnotation(Class<A> annotationType);
|
||||
}
|
||||
|
||||
@@ -228,6 +228,33 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
return propertyCache.get(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public P getPersistentProperty(Class<? extends Annotation> annotationType) {
|
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null!");
|
||||
|
||||
for (P property : properties) {
|
||||
if (property.isAnnotationPresent(annotationType)) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
for (Association<P> association : associations) {
|
||||
|
||||
P property = association.getInverse();
|
||||
|
||||
if (property.isAnnotationPresent(annotationType)) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentEntity#getType()
|
||||
|
||||
Reference in New Issue
Block a user