diff --git a/src/main/java/org/springframework/data/auditing/AnnotationAuditingMetadata.java b/src/main/java/org/springframework/data/auditing/AnnotationAuditingMetadata.java index ee98c3f16..40b624b5a 100644 --- a/src/main/java/org/springframework/data/auditing/AnnotationAuditingMetadata.java +++ b/src/main/java/org/springframework/data/auditing/AnnotationAuditingMetadata.java @@ -1,3 +1,18 @@ +/* + * 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; import java.lang.reflect.Field; @@ -8,7 +23,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.joda.time.DateTime; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; @@ -35,15 +49,20 @@ class AnnotationAuditingMetadata { private static final Map, AnnotationAuditingMetadata> METADATA_CACHE = new ConcurrentHashMap, AnnotationAuditingMetadata>(); - static final List> SUPPORTED_DATE_TYPES; + private static final String JDK8_TIME_PACKAGE_PREFIX = "java.time"; + public static final boolean IS_JDK_8 = org.springframework.util.ClassUtils.isPresent("java.time.Clock", + AnnotationAuditingMetadata.class.getClassLoader()); + + static final List SUPPORTED_DATE_TYPES; static { - List> types = new ArrayList>(4); - types.add(DateTime.class); - types.add(Date.class); - types.add(Long.class); - types.add(long.class); + List 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); } @@ -53,6 +72,11 @@ class AnnotationAuditingMetadata { private final Field lastModifiedByField; private final Field lastModifiedDateField; + /** + * 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!"); @@ -73,13 +97,18 @@ class AnnotationAuditingMetadata { */ private void assertValidDateFieldType(Field field) { - if (field == null || SUPPORTED_DATE_TYPES.contains(field.getType())) { + if (field == null || SUPPORTED_DATE_TYPES.contains(field.getType().getName())) { + return; + } + + // Support JDK 8 date types if runtime allows + if (IS_JDK_8 && field.getType().getPackage().getName().startsWith(JDK8_TIME_PACKAGE_PREFIX)) { return; } throw new IllegalStateException(String.format( - "Found created/modified date field with type %s but only %s are supported!", field.getType(), - SUPPORTED_DATE_TYPES)); + "Found created/modified date field with type %s but only %s as well as java.time types are supported!", + field.getType(), SUPPORTED_DATE_TYPES)); } /** diff --git a/src/main/java/org/springframework/data/auditing/AuditableBeanWrapper.java b/src/main/java/org/springframework/data/auditing/AuditableBeanWrapper.java index 3223dcdd5..8003a4e05 100644 --- a/src/main/java/org/springframework/data/auditing/AuditableBeanWrapper.java +++ b/src/main/java/org/springframework/data/auditing/AuditableBeanWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 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. @@ -15,7 +15,7 @@ */ package org.springframework.data.auditing; -import org.joda.time.DateTime; +import java.util.Calendar; /** * Interface to abstract the ways setting the auditing information can be implemented. @@ -37,7 +37,7 @@ public interface AuditableBeanWrapper { * * @param value */ - void setCreatedDate(DateTime value); + void setCreatedDate(Calendar value); /** * Set the last modifier of the object. @@ -51,5 +51,5 @@ public interface AuditableBeanWrapper { * * @param value */ - void setLastModifiedDate(DateTime value); + void setLastModifiedDate(Calendar value); } diff --git a/src/main/java/org/springframework/data/auditing/AuditableBeanWrapperFactory.java b/src/main/java/org/springframework/data/auditing/AuditableBeanWrapperFactory.java index 9cfc9da4f..84e17353d 100644 --- a/src/main/java/org/springframework/data/auditing/AuditableBeanWrapperFactory.java +++ b/src/main/java/org/springframework/data/auditing/AuditableBeanWrapperFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 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. @@ -16,15 +16,18 @@ package org.springframework.data.auditing; import java.lang.reflect.Field; -import java.util.Date; +import java.util.Calendar; 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.DefaultConversionService; +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; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; /** * A factory class to {@link AuditableBeanWrapper} instances. @@ -34,6 +37,9 @@ import org.springframework.util.Assert; */ 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. * @@ -85,8 +91,8 @@ class AuditableBeanWrapperFactory { * (non-Javadoc) * @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedDate(org.joda.time.DateTime) */ - public void setCreatedDate(DateTime value) { - auditable.setCreatedDate(value); + public void setCreatedDate(Calendar value) { + auditable.setCreatedDate(new DateTime(value)); } /* @@ -101,8 +107,8 @@ class AuditableBeanWrapperFactory { * (non-Javadoc) * @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedDate(org.joda.time.DateTime) */ - public void setLastModifiedDate(DateTime value) { - auditable.setLastModifiedDate(value); + public void setLastModifiedDate(Calendar value) { + auditable.setLastModifiedDate(new DateTime(value)); } } @@ -129,9 +135,12 @@ class AuditableBeanWrapperFactory { this.metadata = AnnotationAuditingMetadata.getMetadata(target.getClass()); this.target = target; - DefaultConversionService conversionService = new DefaultConversionService(); - conversionService.addConverter(DateTimeToLongConverter.INSTANCE); - conversionService.addConverter(DateTimeToDateConverter.INSTANCE); + ConfigurableConversionService conversionService = new DefaultFormattingConversionService(); + + if (IS_JODA_TIME_PRESENT) { + conversionService.addConverter(CalendarToDateTimeConverter.INSTANCE); + conversionService.addConverter(CalendarToLocalDateTimeConverter.INSTANCE); + } this.conversionService = conversionService; } @@ -146,9 +155,9 @@ class AuditableBeanWrapperFactory { /* * (non-Javadoc) - * @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedDate(org.joda.time.DateTime) + * @see org.springframework.data.auditing.AuditableBeanWrapper#setCreatedDate(java.util.Calendar) */ - public void setCreatedDate(DateTime value) { + public void setCreatedDate(Calendar value) { setDateField(metadata.getCreatedDateField(), value); } @@ -162,9 +171,9 @@ class AuditableBeanWrapperFactory { /* * (non-Javadoc) - * @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedDate(org.joda.time.DateTime) + * @see org.springframework.data.auditing.AuditableBeanWrapper#setLastModifiedDate(java.util.Calendar) */ - public void setLastModifiedDate(DateTime value) { + public void setLastModifiedDate(Calendar value) { setDateField(metadata.getLastModifiedDateField(), value); } @@ -187,7 +196,7 @@ class AuditableBeanWrapperFactory { * @param field * @param value */ - private void setDateField(Field field, DateTime value) { + private void setDateField(Field field, Calendar value) { if (field == null) { return; @@ -203,7 +212,7 @@ class AuditableBeanWrapperFactory { * @param field must not be {@literal null}. * @return */ - private Object getDateValueToSet(DateTime value, Field field) { + private Object getDateValueToSet(Calendar value, Field field) { if (value == null) { return null; @@ -211,11 +220,11 @@ class AuditableBeanWrapperFactory { Class targetType = field.getType(); - if (DateTime.class.equals(targetType)) { + if (Calendar.class.equals(targetType)) { return value; } - if (conversionService.canConvert(DateTime.class, targetType)) { + if (conversionService.canConvert(Calendar.class, targetType)) { return conversionService.convert(value, targetType); } @@ -224,23 +233,23 @@ class AuditableBeanWrapperFactory { } } - static enum DateTimeToLongConverter implements Converter { + static enum CalendarToDateTimeConverter implements Converter { INSTANCE; @Override - public Long convert(DateTime source) { - return source.getMillis(); + public DateTime convert(Calendar source) { + return new DateTime(source); } } - static enum DateTimeToDateConverter implements Converter { + static enum CalendarToLocalDateTimeConverter implements Converter { INSTANCE; @Override - public Date convert(DateTime source) { - return source.toDate(); + public LocalDateTime convert(Calendar source) { + return new LocalDateTime(source); } } } diff --git a/src/main/java/org/springframework/data/auditing/CurrentDateTimeProvider.java b/src/main/java/org/springframework/data/auditing/CurrentDateTimeProvider.java index c8bbed8d8..4664c2105 100644 --- a/src/main/java/org/springframework/data/auditing/CurrentDateTimeProvider.java +++ b/src/main/java/org/springframework/data/auditing/CurrentDateTimeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 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. @@ -15,6 +15,9 @@ */ package org.springframework.data.auditing; +import java.util.Calendar; +import java.util.GregorianCalendar; + import org.joda.time.DateTime; /** @@ -27,11 +30,12 @@ public enum CurrentDateTimeProvider implements DateTimeProvider { INSTANCE; - /* + /* * (non-Javadoc) - * @see org.springframework.data.jpa.domain.support.DateTimeProvider#getDateTime() + * @see org.springframework.data.auditing.DateTimeProvider#getNow() */ - public DateTime getDateTime() { - return new DateTime(); + @Override + public Calendar getNow() { + return new GregorianCalendar(); } } diff --git a/src/main/java/org/springframework/data/auditing/DateTimeProvider.java b/src/main/java/org/springframework/data/auditing/DateTimeProvider.java index 1b4a7d5a4..f03290ca3 100644 --- a/src/main/java/org/springframework/data/auditing/DateTimeProvider.java +++ b/src/main/java/org/springframework/data/auditing/DateTimeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 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. @@ -15,10 +15,10 @@ */ package org.springframework.data.auditing; -import org.joda.time.DateTime; +import java.util.Calendar; /** - * SPI to calculate the {@link DateTime} instance to be used when auditing. + * SPI to calculate the current time to be used when auditing. * * @author Oliver Gierke * @since 1.5 @@ -26,9 +26,9 @@ import org.joda.time.DateTime; public interface DateTimeProvider { /** - * Returns the {@link DateTime} to be used as modification date. + * Returns the current time to be used as modification or creation date. * * @return */ - DateTime getDateTime(); + Calendar getNow(); }