DATAJDBC-204 - Support for annotation based auditing.

When enabled by using @EnableJdbcAuditing entities will get properties annotated with

* @CreatedBy
* @CreatedDate
* @LastModifiedBy
* @LastModifiedDate

updated when saved.

Original pull request: #64.
This commit is contained in:
Kazuki Shimizu
2018-04-14 16:25:54 +09:00
committed by Jens Schauder
parent 9873db6fff
commit 92cd333854
6 changed files with 487 additions and 1 deletions

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2018 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.jdbc.domain.support;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.jdbc.mapping.event.BeforeSaveEvent;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Spring JDBC event listener to capture auditing information on persisting and updating entities.
* <p>
* You can enable this class just a matter of activating auditing using {@link org.springframework.data.jdbc.repository.config.EnableJdbcAuditing} in your Spring config:
*
* <pre>
* &#064;Configuration
* &#064;EnableJdbcRepositories
* &#064;EnableJdbcAuditing
* class JdbcRepositoryConfig {
* }
* </pre>
*
* @author Kazuki Shimizu
* @see org.springframework.data.jdbc.repository.config.EnableJdbcAuditing
* @since 1.0
*/
public class JdbcAuditingEventListener implements ApplicationListener<BeforeSaveEvent> {
@Nullable
private AuditingHandler handler;
/**
* Configures the {@link AuditingHandler} to be used to set the current auditor on the domain types touched.
*
* @param auditingHandler must not be {@literal null}.
*/
public void setAuditingHandler(ObjectFactory<AuditingHandler> auditingHandler) {
Assert.notNull(auditingHandler, "AuditingHandler must not be null!");
this.handler = auditingHandler.getObject();
}
/**
* {@inheritDoc}
* @param event a notification event for indicating before save
*/
@Override
public void onApplicationEvent(BeforeSaveEvent event) {
if (handler != null) {
event.getOptionalEntity().ifPresent(entity -> {
if (event.getId().getOptionalValue().isPresent()) {
handler.markModified(entity);
} else {
handler.markCreated(entity);
}
});
}
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2018 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.jdbc.repository.config;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.domain.AuditorAware;
/**
* Annotation to enable auditing in JDBC via annotation configuration.
*
* If you use the auditing feature, you should be configures beans of Spring Data JDBC
* using {@link org.springframework.data.jdbc.repository.config.EnableJdbcRepositories} in your Spring config:
*
* <pre>
* &#064;Configuration
* &#064;EnableJdbcRepositories
* &#064;EnableJdbcAuditing
* class JdbcRepositoryConfig {
* }
* </pre>
*
* <p>
* Note: This feature cannot use to a entity that implements {@link org.springframework.data.domain.Auditable}
* because the Spring Data JDBC does not support an {@link java.util.Optional} property yet.
* </p>
*
* @see EnableJdbcRepositories
* @author Kazuki Shimizu
* @since 1.0
*/
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(JdbcAuditingRegistrar.class)
public @interface EnableJdbcAuditing {
/**
* Configures the {@link AuditorAware} bean to be used to lookup the current principal.
*
* @return
* @see AuditorAware
*/
String auditorAwareRef() default "";
/**
* Configures whether the creation and modification dates are set.
*
* @return
*/
boolean setDates() default true;
/**
* Configures whether the entity shall be marked as modified on creation.
*
* @return
*/
boolean modifyOnCreate() default true;
/**
* Configures a {@link DateTimeProvider} bean name that allows customizing the {@link java.time.LocalDateTime} to be
* used for setting creation and modification dates.
*
* @return
* @see DateTimeProvider
*/
String dateTimeProviderRef() default "";
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2018 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.jdbc.repository.config;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
import org.springframework.data.auditing.config.AuditingConfiguration;
import org.springframework.data.config.ParsingUtils;
import org.springframework.data.jdbc.domain.support.JdbcAuditingEventListener;
/**
* {@link ImportBeanDefinitionRegistrar} to enable {@link EnableJdbcAuditing} annotation.
*
* @see EnableJdbcAuditing
* @author Kazuki Shimizu
* @since 1.0
*/
class JdbcAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
/**
* {@inheritDoc}
* @return return the {@link EnableJdbcAuditing}
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAnnotation()
*/
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableJdbcAuditing.class;
}
/**
* {@inheritDoc}
* @return return "{@literal jdbcAuditingHandler}"
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditingHandlerBeanName()
*/
@Override
protected String getAuditingHandlerBeanName() {
return "jdbcAuditingHandler";
}
/*
* (non-Javadoc)
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditHandlerBeanDefinitionBuilder(org.springframework.data.auditing.config.AuditingConfiguration)
*/
@Override
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
BeanDefinitionBuilder builder = super.getAuditHandlerBeanDefinitionBuilder(configuration);
return builder.addConstructorArgReference("jdbcMappingContext");
}
/**
* Register the bean definition of {@link JdbcAuditingEventListener}.
* {@inheritDoc}
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#registerAuditListenerBeanDefinition(BeanDefinition, BeanDefinitionRegistry)
*/
@Override
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
BeanDefinitionRegistry registry) {
Class<?> listenerClass = JdbcAuditingEventListener.class;
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(listenerClass);
builder.addPropertyValue("auditingHandler",
ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), null));
registerInfrastructureBeanWithId(builder.getRawBeanDefinition(), listenerClass.getName(), registry);
}
}