DateTimeFormat annotation supports use as a meta-annotation as well
This commit is contained in:
parent
ee50d849a1
commit
5b93b14392
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
@ -41,10 +41,11 @@ import java.lang.annotation.Target;
|
|||
* When no annotation attributes are specified, the default format applied is style-based with a style code of 'SS' (short date, short time).
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see org.joda.time.format.DateTimeFormat
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
|
||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DateTimeFormat {
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.format.support;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
@ -106,6 +108,23 @@ public class FormattingConversionServiceTests {
|
|||
assertEquals(new LocalDate(2009, 10, 31), new LocalDate(valueBean.date));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatFieldForValueInjectionUsingMetaAnnotations() {
|
||||
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
|
||||
ac.registerBeanDefinition("valueBean", new RootBeanDefinition(MetaValueBean.class, false));
|
||||
ac.registerBeanDefinition("conversionService", new RootBeanDefinition(FormattingConversionServiceFactoryBean.class));
|
||||
ac.registerBeanDefinition("ppc", new RootBeanDefinition(PropertyPlaceholderConfigurer.class));
|
||||
ac.refresh();
|
||||
System.setProperty("myDate", "10-31-09");
|
||||
try {
|
||||
MetaValueBean valueBean = ac.getBean(MetaValueBean.class);
|
||||
assertEquals(new LocalDate(2009, 10, 31), new LocalDate(valueBean.date));
|
||||
}
|
||||
finally {
|
||||
System.clearProperty("myDate");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatFieldForAnnotation() throws Exception {
|
||||
formattingService.addFormatterForFieldAnnotation(new JodaDateTimeFormatAnnotationFormatterFactory());
|
||||
|
@ -287,6 +306,20 @@ public class FormattingConversionServiceTests {
|
|||
}
|
||||
|
||||
|
||||
public static class MetaValueBean {
|
||||
|
||||
@MyDateAnn
|
||||
public Date date;
|
||||
}
|
||||
|
||||
|
||||
@Value("${myDate}")
|
||||
@org.springframework.format.annotation.DateTimeFormat(pattern="MM-d-yy")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public static @interface MyDateAnn {
|
||||
}
|
||||
|
||||
|
||||
public static class Model {
|
||||
|
||||
@org.springframework.format.annotation.DateTimeFormat(style="S-")
|
||||
|
@ -310,7 +343,7 @@ public class FormattingConversionServiceTests {
|
|||
@org.springframework.format.annotation.DateTimeFormat(style="${dateStyle}")
|
||||
public Date date;
|
||||
|
||||
@org.springframework.format.annotation.DateTimeFormat(pattern="${datePattern}")
|
||||
@MyDatePattern
|
||||
public List<Date> dates;
|
||||
|
||||
public List<Date> getDates() {
|
||||
|
@ -321,7 +354,14 @@ public class FormattingConversionServiceTests {
|
|||
this.dates = dates;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@org.springframework.format.annotation.DateTimeFormat(pattern="${datePattern}")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public static @interface MyDatePattern {
|
||||
}
|
||||
|
||||
|
||||
public static class NullReturningFormatter implements Formatter<Integer> {
|
||||
|
||||
public String print(Integer object, Locale locale) {
|
||||
|
|
|
@ -215,8 +215,9 @@ public class TypeDescriptor {
|
|||
/**
|
||||
* The type of the backing class, method parameter, field, or property described by this TypeDescriptor.
|
||||
* Returns primitive types as-is.
|
||||
* See {@link #getObjectType()} for a variation of this operation that resolves primitive types to their corresponding Object types if necessary.
|
||||
* @return the type, or <code>null</code> if this is {@link TypeDescriptor#NULL}
|
||||
* <p>See {@link #getObjectType()} for a variation of this operation that resolves primitive types
|
||||
* to their corresponding Object types if necessary.
|
||||
* @return the type, or <code>null</code>
|
||||
* @see #getObjectType()
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
|
@ -225,7 +226,8 @@ public class TypeDescriptor {
|
|||
|
||||
/**
|
||||
* Variation of {@link #getType()} that accounts for a primitive type by returning its object wrapper type.
|
||||
* This is useful for conversion service implementations that wish to normalize to object-based types and not work with primitive types directly.
|
||||
* <p>This is useful for conversion service implementations that wish to normalize to object-based types
|
||||
* and not work with primitive types directly.
|
||||
*/
|
||||
public Class<?> getObjectType() {
|
||||
return ClassUtils.resolvePrimitiveIfNecessary(getType());
|
||||
|
@ -233,12 +235,12 @@ public class TypeDescriptor {
|
|||
|
||||
/**
|
||||
* Narrows this {@link TypeDescriptor} by setting its type to the class of the provided value.
|
||||
* If the value is null, no narrowing is performed and this TypeDescriptor is returned unchanged.
|
||||
* Designed to be called by binding frameworks when they read property, field, or method return values.
|
||||
* If the value is <code>null</code>, no narrowing is performed and this TypeDescriptor is returned unchanged.
|
||||
* <p>Designed to be called by binding frameworks when they read property, field, or method return values.
|
||||
* Allows such frameworks to narrow a TypeDescriptor built from a declared property, field, or method return value type.
|
||||
* For example, a field declared as java.lang.Object would be narrowed to java.util.HashMap if it was set to a java.util.HashMap value.
|
||||
* The narrowed TypeDescriptor can then be used to convert the HashMap to some other type.
|
||||
* Annotation and nested type context is preserved by the narrowed copy.
|
||||
* For example, a field declared as <code>java.lang.Object</code> would be narrowed to <code>java.util.HashMap</code>
|
||||
* if it was set to a <code>java.util.HashMap</code> value. The narrowed TypeDescriptor can then be used to convert
|
||||
* the HashMap to some other type. Annotation and nested type context is preserved by the narrowed copy.
|
||||
* @param value the value to use for narrowing this type descriptor
|
||||
* @return this TypeDescriptor narrowed (returns a copy with its type updated to the class of the provided value)
|
||||
*/
|
||||
|
@ -302,15 +304,21 @@ public class TypeDescriptor {
|
|||
/**
|
||||
* Obtain the annotation associated with this type descriptor of the specified type.
|
||||
* @param annotationType the annotation type
|
||||
* @return the annotation, or null if no such annotation exists on this type descriptor
|
||||
* @return the annotation, or <code>null</code> if no such annotation exists on this type descriptor
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
for (Annotation annotation : getAnnotations()) {
|
||||
for (Annotation annotation : this.annotations) {
|
||||
if (annotation.annotationType().equals(annotationType)) {
|
||||
return (T) annotation;
|
||||
}
|
||||
}
|
||||
for (Annotation metaAnn : this.annotations) {
|
||||
T ann = metaAnn.annotationType().getAnnotation(annotationType);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -573,24 +581,23 @@ public class TypeDescriptor {
|
|||
return false;
|
||||
}
|
||||
TypeDescriptor other = (TypeDescriptor) obj;
|
||||
if (!ObjectUtils.nullSafeEquals(getType(), other.getType())) {
|
||||
if (!ObjectUtils.nullSafeEquals(this.type, other.type)) {
|
||||
return false;
|
||||
}
|
||||
Annotation[] annotations = getAnnotations();
|
||||
if (annotations.length != other.getAnnotations().length) {
|
||||
if (this.annotations.length != other.annotations.length) {
|
||||
return false;
|
||||
}
|
||||
for (Annotation ann : annotations) {
|
||||
for (Annotation ann : this.annotations) {
|
||||
if (other.getAnnotation(ann.annotationType()) == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isCollection() || isArray()) {
|
||||
return ObjectUtils.nullSafeEquals(getElementTypeDescriptor(), other.getElementTypeDescriptor());
|
||||
return ObjectUtils.nullSafeEquals(this.elementTypeDescriptor, other.elementTypeDescriptor);
|
||||
}
|
||||
else if (isMap()) {
|
||||
return ObjectUtils.nullSafeEquals(getMapKeyTypeDescriptor(), other.getMapKeyTypeDescriptor()) &&
|
||||
ObjectUtils.nullSafeEquals(getMapValueTypeDescriptor(), other.getMapValueTypeDescriptor());
|
||||
return ObjectUtils.nullSafeEquals(this.mapKeyTypeDescriptor, other.mapKeyTypeDescriptor) &&
|
||||
ObjectUtils.nullSafeEquals(this.mapValueTypeDescriptor, other.mapValueTypeDescriptor);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
|
@ -603,17 +610,16 @@ public class TypeDescriptor {
|
|||
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Annotation[] anns = getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
for (Annotation ann : this.annotations) {
|
||||
builder.append("@").append(ann.annotationType().getName()).append(' ');
|
||||
}
|
||||
builder.append(ClassUtils.getQualifiedName(getType()));
|
||||
if (isMap()) {
|
||||
builder.append("<").append(wildcard(getMapKeyTypeDescriptor()));
|
||||
builder.append(", ").append(wildcard(getMapValueTypeDescriptor())).append(">");
|
||||
builder.append("<").append(wildcard(this.mapKeyTypeDescriptor));
|
||||
builder.append(", ").append(wildcard(this.mapValueTypeDescriptor)).append(">");
|
||||
}
|
||||
else if (isCollection()) {
|
||||
builder.append("<").append(wildcard(getElementTypeDescriptor())).append(">");
|
||||
builder.append("<").append(wildcard(this.elementTypeDescriptor)).append(">");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue