/*
 * Copyright 2012-2020 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
 *
 *      https://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.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

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.convert.Jsr310Converters;
import org.springframework.data.convert.ThreeTenBackPortConverters;
import org.springframework.data.util.Optionals;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.data.util.ReflectionUtils.AnnotationFieldFilter;
import org.springframework.util.Assert;

Inspects the given Class for fields annotated by CreatedBy, CreatedDate, LastModifiedBy , and LastModifiedDate. Only one field per annotation is stored.
Author:Ranie Jade Ramiso, Oliver Gierke, Christoph Strobl
Since:1.5
/** * Inspects the given {@link Class} for fields annotated by {@link CreatedBy}, {@link CreatedDate}, * {@link LastModifiedBy} , and {@link LastModifiedDate}. Only one field per annotation is stored. * * @author Ranie Jade Ramiso * @author Oliver Gierke * @author Christoph Strobl * @since 1.5 */
final class AnnotationAuditingMetadata { private static final AnnotationFieldFilter CREATED_BY_FILTER = new AnnotationFieldFilter(CreatedBy.class); private static final AnnotationFieldFilter CREATED_DATE_FILTER = new AnnotationFieldFilter(CreatedDate.class); private static final AnnotationFieldFilter LAST_MODIFIED_BY_FILTER = new AnnotationFieldFilter(LastModifiedBy.class); private static final AnnotationFieldFilter LAST_MODIFIED_DATE_FILTER = new AnnotationFieldFilter( LastModifiedDate.class); private static final Map<Class<?>, AnnotationAuditingMetadata> METADATA_CACHE = new ConcurrentHashMap<>(); public static final boolean IS_JDK_8 = org.springframework.util.ClassUtils.isPresent("java.time.Clock", AnnotationAuditingMetadata.class.getClassLoader()); static final List<String> SUPPORTED_DATE_TYPES; static { List<String> types = new ArrayList<>(5); types.add("org.joda.time.DateTime"); types.add("org.joda.time.LocalDateTime"); types.add(Date.class.getName()); types.add(Long.class.getName()); types.add(long.class.getName()); SUPPORTED_DATE_TYPES = Collections.unmodifiableList(types); } private final Optional<Field> createdByField; private final Optional<Field> createdDateField; private final Optional<Field> lastModifiedByField; private final Optional<Field> lastModifiedDateField;
Creates a new AnnotationAuditingMetadata instance for the given type.
Params:
  • type – must not be null.
/** * Creates a new {@link AnnotationAuditingMetadata} instance for the given type. * * @param type must not be {@literal null}. */
private AnnotationAuditingMetadata(Class<?> type) { Assert.notNull(type, "Given type must not be null!"); this.createdByField = Optional.ofNullable(ReflectionUtils.findField(type, CREATED_BY_FILTER)); this.createdDateField = Optional.ofNullable(ReflectionUtils.findField(type, CREATED_DATE_FILTER)); this.lastModifiedByField = Optional.ofNullable(ReflectionUtils.findField(type, LAST_MODIFIED_BY_FILTER)); this.lastModifiedDateField = Optional.ofNullable(ReflectionUtils.findField(type, LAST_MODIFIED_DATE_FILTER)); assertValidDateFieldType(createdDateField); assertValidDateFieldType(lastModifiedDateField); }
Checks whether the given field has a type that is a supported date type.
Params:
  • field –
/** * Checks whether the given field has a type that is a supported date type. * * @param field */
private void assertValidDateFieldType(Optional<Field> field) { field.ifPresent(it -> { if (SUPPORTED_DATE_TYPES.contains(it.getType().getName())) { return; } Class<?> type = it.getType(); if (Jsr310Converters.supports(type) || ThreeTenBackPortConverters.supports(type)) { return; } throw new IllegalStateException(String.format( "Found created/modified date field with type %s but only %s as well as java.time types are supported!", type, SUPPORTED_DATE_TYPES)); }); }
Return a AnnotationAuditingMetadata for the given Class.
Params:
  • type – the type to inspect, must not be null.
/** * Return a {@link AnnotationAuditingMetadata} for the given {@link Class}. * * @param type the type to inspect, must not be {@literal null}. */
public static AnnotationAuditingMetadata getMetadata(Class<?> type) { return METADATA_CACHE.computeIfAbsent(type, AnnotationAuditingMetadata::new); }
Returns whether the Class represented in this instance is auditable or not.
/** * Returns whether the {@link Class} represented in this instance is auditable or not. */
public boolean isAuditable() { return Optionals.isAnyPresent(createdByField, createdDateField, lastModifiedByField, lastModifiedDateField); }
Return the field annotated by CreatedBy.
/** * Return the field annotated by {@link CreatedBy}. */
public Optional<Field> getCreatedByField() { return createdByField; }
Return the field annotated by CreatedDate.
/** * Return the field annotated by {@link CreatedDate}. */
public Optional<Field> getCreatedDateField() { return createdDateField; }
Return the field annotated by LastModifiedBy.
/** * Return the field annotated by {@link LastModifiedBy}. */
public Optional<Field> getLastModifiedByField() { return lastModifiedByField; }
Return the field annotated by LastModifiedDate.
/** * Return the field annotated by {@link LastModifiedDate}. */
public Optional<Field> getLastModifiedDateField() { return lastModifiedDateField; } }