Browse Source
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@2233 50f2f4bb-b051-0410-bef5-90022cba6387pull/1/head
56 changed files with 1724 additions and 1602 deletions
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.mapping.support; |
||||
|
||||
import org.springframework.core.style.StylerUtils; |
||||
import org.springframework.expression.Expression; |
||||
import org.springframework.mapping.Mapper; |
||||
|
||||
/** |
||||
* A mapping between several source fields and one or more target fields. |
||||
* @author Keith Donald |
||||
*/ |
||||
final class FlexibleFieldMapping implements SpelMapping { |
||||
|
||||
private String[] fields; |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private final Mapper flexibleFieldMapper; |
||||
|
||||
private Expression condition; |
||||
|
||||
public FlexibleFieldMapping(String[] fields, Mapper<?, ?> flexibleFieldMapper, Expression condition) { |
||||
this.fields = fields; |
||||
this.flexibleFieldMapper = flexibleFieldMapper; |
||||
this.condition = condition; |
||||
} |
||||
|
||||
public String[] getSourceFields() { |
||||
return fields; |
||||
} |
||||
|
||||
public boolean mapsField(String field) { |
||||
for (String f : this.fields) { |
||||
if (f.equals(field)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public void map(SpelMappingContext context) { |
||||
if (!context.conditionHolds(this.condition)) { |
||||
return; |
||||
} |
||||
try { |
||||
this.flexibleFieldMapper.map(context.getSource(), context.getTarget()); |
||||
} catch (Exception e) { |
||||
context.addMappingFailure(e); |
||||
} |
||||
} |
||||
|
||||
public int hashCode() { |
||||
return this.flexibleFieldMapper.hashCode(); |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
if (!(o instanceof FlexibleFieldMapping)) { |
||||
return false; |
||||
} |
||||
FlexibleFieldMapping m = (FlexibleFieldMapping) o; |
||||
return this.flexibleFieldMapper.equals(m.flexibleFieldMapper); |
||||
} |
||||
|
||||
public String toString() { |
||||
return "[FlexibleFieldMapping<" + StylerUtils.style(this.fields) + " -> " + this.flexibleFieldMapper + ">]"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format; |
||||
|
||||
import java.text.ParseException; |
||||
import java.util.Locale; |
||||
|
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
|
||||
/** |
||||
* A service interface for formatting localized field values. |
||||
* This is the entry point into the <code>ui.format</code> system. |
||||
* |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public interface FormattingService { |
||||
|
||||
/** |
||||
* Print the field value for display in the locale. |
||||
* @param fieldValue the field value |
||||
* @param fieldType the field type |
||||
* @param locale the user's locale |
||||
* @return the printed string |
||||
*/ |
||||
String print(Object fieldValue, TypeDescriptor fieldType, Locale locale); |
||||
|
||||
/** |
||||
* Parse the the value submitted by the user. |
||||
* @param submittedValue the submitted field value |
||||
* @param fieldType the field type |
||||
* @param locale the user's locale |
||||
* @return the parsed field value |
||||
*/ |
||||
Object parse(String submittedValue, TypeDescriptor fieldType, Locale locale) throws ParseException; |
||||
|
||||
} |
||||
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.lang.annotation.Annotation; |
||||
import java.util.Calendar; |
||||
import java.util.Collections; |
||||
import java.util.Date; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
import org.joda.time.DateTime; |
||||
import org.joda.time.ReadableInstant; |
||||
import org.joda.time.ReadablePartial; |
||||
import org.joda.time.format.DateTimeFormatter; |
||||
import org.springframework.ui.format.AnnotationFormatterFactory; |
||||
import org.springframework.ui.format.Parser; |
||||
import org.springframework.ui.format.Printer; |
||||
|
||||
/** |
||||
* Base class for annotation-based Joda DateTime formatters. |
||||
* Can format any Joda {@link ReadableInstant} or {@link ReadablePartial} property, as well as standard {@link Date}, {@link Calendar}, and Long properties. |
||||
* @author Keith Donald |
||||
* @param <A> the format annotation parameter type to be declared by subclasses |
||||
*/ |
||||
abstract class AbstractDateTimeAnnotationFormatterFactory<A extends Annotation> implements AnnotationFormatterFactory<A> { |
||||
|
||||
private final Set<Class<?>> propertyTypes; |
||||
|
||||
public AbstractDateTimeAnnotationFormatterFactory() { |
||||
this.propertyTypes = Collections.unmodifiableSet(createPropertyTypes()); |
||||
} |
||||
|
||||
public Set<Class<?>> getFieldTypes() { |
||||
return propertyTypes; |
||||
} |
||||
|
||||
public Printer<?> getPrinter(A annotation, Class<?> propertyType) { |
||||
DateTimeFormatter formatter = configureDateTimeFormatterFrom(annotation); |
||||
if (ReadableInstant.class.isAssignableFrom(propertyType)) { |
||||
return new ReadableInstantPrinter(formatter); |
||||
} else if (ReadablePartial.class.equals(propertyType)) { |
||||
return new ReadablePartialPrinter(formatter); |
||||
} else if (Calendar.class.isAssignableFrom(propertyType)) { |
||||
// assumes Calendar->ReadableInstant converter is registered
|
||||
return new ReadableInstantPrinter(formatter); |
||||
} else { |
||||
// assumes Date->Long converter is registered
|
||||
return new MillisecondInstantPrinter(formatter); |
||||
} |
||||
} |
||||
|
||||
public Parser<DateTime> getParser(A annotation, Class<?> propertyType) { |
||||
return new DateTimeParser(configureDateTimeFormatterFrom(annotation)); |
||||
} |
||||
|
||||
/** |
||||
* Hook method subclasses should override to configure the Joda {@link DateTimeFormatter} from the <code>annotation</code> values. |
||||
* @param annotation the annotation containing formatter configuration rules |
||||
* @return the configured date time formatter |
||||
*/ |
||||
protected abstract DateTimeFormatter configureDateTimeFormatterFrom(A annotation); |
||||
|
||||
// internal helpers
|
||||
|
||||
private Set<Class<?>> createPropertyTypes() { |
||||
Set<Class<?>> propertyTypes = new HashSet<Class<?>>(); |
||||
propertyTypes.add(ReadableInstant.class); |
||||
propertyTypes.add(ReadablePartial.class); |
||||
propertyTypes.add(Date.class); |
||||
propertyTypes.add(Calendar.class); |
||||
propertyTypes.add(Long.class); |
||||
return propertyTypes; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* Indicates a property should be formatted as a date time. |
||||
* @author Keith Donald |
||||
*/ |
||||
@Target( { ElementType.METHOD, ElementType.FIELD }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public @interface DateTimeFormat { |
||||
|
||||
/** |
||||
* The style to use for formatting the date portion of the property. |
||||
* Defaults to {@link FormatStyle#NONE}. |
||||
*/ |
||||
FormatStyle dateStyle() default FormatStyle.NONE; |
||||
|
||||
/** |
||||
* The style to use for formatting the time portion of the property. |
||||
* Defaults to {@link FormatStyle#NONE}. |
||||
*/ |
||||
FormatStyle timeStyle() default FormatStyle.NONE; |
||||
|
||||
/** |
||||
* A pattern String that defines a custom format for the property. |
||||
* Use this method or the <code>*Style</code> methods, not both. |
||||
*/ |
||||
String pattern() default ""; |
||||
|
||||
/** |
||||
* Supported DateTimeFormat styles. |
||||
*/ |
||||
public enum FormatStyle { |
||||
SHORT { |
||||
public String toString() { |
||||
return "S"; |
||||
} |
||||
}, |
||||
MEDIUM { |
||||
public String toString() { |
||||
return "M"; |
||||
} |
||||
}, |
||||
LONG { |
||||
public String toString() { |
||||
return "L"; |
||||
} |
||||
}, |
||||
FULL { |
||||
public String toString() { |
||||
return "F"; |
||||
} |
||||
}, |
||||
NONE { |
||||
public String toString() { |
||||
return "-"; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import org.joda.time.format.DateTimeFormatter; |
||||
import org.springframework.ui.format.jodatime.DateTimeFormat.FormatStyle; |
||||
|
||||
/** |
||||
* Formats properties annotated with the {@link DateTimeFormat} annotation. |
||||
* |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see DateTimeFormat |
||||
*/ |
||||
public final class DateTimeFormatAnnotationFormatterFactory extends AbstractDateTimeAnnotationFormatterFactory<DateTimeFormat> { |
||||
|
||||
protected DateTimeFormatter configureDateTimeFormatterFrom(DateTimeFormat annotation) { |
||||
String pattern = annotation.pattern(); |
||||
if (!pattern.isEmpty()) { |
||||
return forPattern(pattern); |
||||
} else { |
||||
FormatStyle dateStyle = annotation.dateStyle(); |
||||
FormatStyle timeStyle = annotation.timeStyle(); |
||||
return forDateTimeStyle(dateStyle, timeStyle); |
||||
} |
||||
} |
||||
|
||||
private DateTimeFormatter forDateTimeStyle(FormatStyle dateStyle, FormatStyle timeStyle) { |
||||
return org.joda.time.format.DateTimeFormat.forStyle(dateStyle.toString() + timeStyle.toString()); |
||||
} |
||||
|
||||
private DateTimeFormatter forPattern(String pattern) { |
||||
return org.joda.time.format.DateTimeFormat.forPattern(pattern); |
||||
} |
||||
|
||||
} |
||||
@ -1,57 +0,0 @@
@@ -1,57 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.text.ParseException; |
||||
import java.util.Locale; |
||||
|
||||
import org.joda.time.DateTime; |
||||
import org.joda.time.format.DateTimeFormat; |
||||
import org.springframework.ui.format.Formatter; |
||||
|
||||
/** |
||||
* {@link Formatter} implementation to handle JodaTime {@link DateTime} instances. |
||||
* @author Oliver Gierke |
||||
*/ |
||||
public class DateTimeFormatter implements Formatter<DateTime> { |
||||
|
||||
private org.joda.time.format.DateTimeFormatter formatter; |
||||
|
||||
/** |
||||
* Creates a new {@link DateTimeFormatter} for the given JodaTime formatting pattern. |
||||
* @param pattern |
||||
* @see DateTimeFormat#forPattern(String) |
||||
*/ |
||||
public DateTimeFormatter(String pattern) { |
||||
this.formatter = DateTimeFormat.forPattern(pattern); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new {@link DateTimeFormatter} for the given JodaTime formatter. |
||||
* @param formatter the Date Formatter instance |
||||
*/ |
||||
public DateTimeFormatter(org.joda.time.format.DateTimeFormatter formatter) { |
||||
this.formatter = formatter; |
||||
} |
||||
|
||||
public String format(DateTime object, Locale locale) { |
||||
return null == object ? "" : object.toString(formatter); |
||||
} |
||||
|
||||
public DateTime parse(String formatted, Locale locale) throws ParseException { |
||||
return formatter.withLocale(locale).parseDateTime(formatted); |
||||
} |
||||
} |
||||
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import org.joda.time.format.DateTimeFormatter; |
||||
import org.springframework.ui.format.jodatime.ISODateTimeFormat.FormatStyle; |
||||
|
||||
/** |
||||
* Formats properties annotated with the {@link ISODateTimeFormat} annotation. |
||||
* |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see ISODateTimeFormat |
||||
*/ |
||||
public final class ISODateTimeFormatAnnotationFormatterFactory extends AbstractDateTimeAnnotationFormatterFactory<ISODateTimeFormat> { |
||||
|
||||
protected DateTimeFormatter configureDateTimeFormatterFrom(ISODateTimeFormat annotation) { |
||||
FormatStyle style = annotation.value(); |
||||
if (style == FormatStyle.DATE) { |
||||
return org.joda.time.format.ISODateTimeFormat.date(); |
||||
} else if (style == FormatStyle.TIME) { |
||||
return org.joda.time.format.ISODateTimeFormat.time(); |
||||
} else { |
||||
return org.joda.time.format.ISODateTimeFormat.dateTime(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import org.joda.time.Chronology; |
||||
import org.joda.time.DateTimeZone; |
||||
import org.joda.time.format.DateTimeFormatter; |
||||
|
||||
/** |
||||
* A context that holds user-specific Joda Time settings such as the user's Chronology (calendar system) and time zone. |
||||
* A <code>null</code> property value indicate the user has not specified a setting. |
||||
* @author Keith Donald |
||||
* @see JodaTimeContextHolder |
||||
*/ |
||||
public class JodaTimeContext { |
||||
|
||||
private Chronology chronology; |
||||
|
||||
private DateTimeZone timeZone; |
||||
|
||||
/** |
||||
* The user's chronology (calendar system). |
||||
* Null if not specified. |
||||
*/ |
||||
public Chronology getChronology() { |
||||
return chronology; |
||||
} |
||||
|
||||
/** |
||||
* Sets the user's chronology. |
||||
*/ |
||||
public void setChronology(Chronology chronology) { |
||||
this.chronology = chronology; |
||||
} |
||||
|
||||
/** |
||||
* The user's timezone. |
||||
* Null if not specified. |
||||
*/ |
||||
public DateTimeZone getTimeZone() { |
||||
return timeZone; |
||||
} |
||||
|
||||
/** |
||||
* Sets the user's timezone. |
||||
*/ |
||||
public void setTimeZone(DateTimeZone timeZone) { |
||||
this.timeZone = timeZone; |
||||
} |
||||
|
||||
/** |
||||
* Gets the Formatter with the this context's settings applied to the base <code>formatter</code>. |
||||
* @param formatter the base formatter that establishes default formatting rules, generally context independent |
||||
* @return the context DateTimeFormatter |
||||
*/ |
||||
public DateTimeFormatter getFormatter(DateTimeFormatter formatter) { |
||||
if (this.chronology != null) { |
||||
formatter = formatter.withChronology(this.chronology); |
||||
} |
||||
if (this.timeZone != null) { |
||||
formatter = formatter.withZone(this.timeZone); |
||||
} |
||||
return formatter; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.joda.time.format.DateTimeFormatter; |
||||
import org.springframework.core.NamedInheritableThreadLocal; |
||||
|
||||
/** |
||||
* A holder for a thread-local user {@link JodaTimeContext}. |
||||
* @author Keith Donald |
||||
*/ |
||||
public final class JodaTimeContextHolder { |
||||
|
||||
private static final ThreadLocal<JodaTimeContext> jodaTimeContextHolder = new NamedInheritableThreadLocal<JodaTimeContext>( |
||||
"Joda Time Context"); |
||||
|
||||
/** |
||||
* Return the JodaTimeContext associated with the current thread, if any. |
||||
* @return the current JodaTimeContext, or <code>null</code> if none |
||||
*/ |
||||
public static JodaTimeContext getJodaTimeContext() { |
||||
return jodaTimeContextHolder.get(); |
||||
} |
||||
|
||||
/** |
||||
* Associate the given JodaTimeContext with the current thread. |
||||
* @param context the current JodaTimeContext, or <code>null</code> to clear |
||||
* the thread-bound context |
||||
*/ |
||||
public static void setLocaleContext(JodaTimeContext context) { |
||||
jodaTimeContextHolder.set(context); |
||||
} |
||||
|
||||
/** |
||||
* Gets the Formatter with the user-specific settings applied to thefrom the base <code>formatter</code>. |
||||
* @param formatter the base formatter that establishes default formatting rules, generally user independent |
||||
* @param locale the current user locale (may be null if not known) |
||||
* @return the user's DateTimeFormatter |
||||
*/ |
||||
public static DateTimeFormatter getFormatter(DateTimeFormatter formatter, Locale locale) { |
||||
if (locale != null) { |
||||
formatter = formatter.withLocale(locale); |
||||
} |
||||
JodaTimeContext context = getJodaTimeContext(); |
||||
return context != null ? context.getFormatter(formatter) : formatter; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,113 @@
@@ -0,0 +1,113 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
|
||||
import org.joda.time.DateMidnight; |
||||
import org.joda.time.DateTime; |
||||
import org.joda.time.LocalDate; |
||||
import org.joda.time.LocalDateTime; |
||||
import org.joda.time.LocalTime; |
||||
import org.joda.time.ReadableInstant; |
||||
import org.springframework.core.convert.converter.Converter; |
||||
import org.springframework.core.convert.converter.ConverterRegistry; |
||||
|
||||
/** |
||||
* Installs lower-level type converters required to integrate Joda Time support into Spring's formatting and property binding systems. |
||||
* @author Keith Donald |
||||
*/ |
||||
final class JodaTimeConverters { |
||||
|
||||
private JodaTimeConverters() { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Installs the converters into the converter registry. |
||||
* @param registry the converter registry |
||||
*/ |
||||
public static void registerConverters(ConverterRegistry registry) { |
||||
registry.addConverter(new DateTimeToLocalDateConverter()); |
||||
registry.addConverter(new DateTimeToLocalTimeConverter()); |
||||
registry.addConverter(new DateTimeToLocalDateTimeConverter()); |
||||
registry.addConverter(new DateTimeToDateMidnightConverter()); |
||||
registry.addConverter(new DateTimeToDateConverter()); |
||||
registry.addConverter(new DateTimeToCalendarConverter()); |
||||
registry.addConverter(new DateToLongConverter()); |
||||
registry.addConverter(new CalendarToDateTimeConverter()); |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
// used when binding a parsed DateTime to a LocalDate property
|
||||
private static class DateTimeToLocalDateConverter implements Converter<DateTime, LocalDate> { |
||||
public LocalDate convert(DateTime source) { |
||||
return source.toLocalDate(); |
||||
} |
||||
} |
||||
|
||||
// used when binding a parsed DateTime to a LocalTime property
|
||||
private static class DateTimeToLocalTimeConverter implements Converter<DateTime, LocalTime> { |
||||
public LocalTime convert(DateTime source) { |
||||
return source.toLocalTime(); |
||||
} |
||||
} |
||||
|
||||
// used when binding a parsed DateTime to a LocalDateTime property
|
||||
private static class DateTimeToLocalDateTimeConverter implements Converter<DateTime, LocalDateTime> { |
||||
public LocalDateTime convert(DateTime source) { |
||||
return source.toLocalDateTime(); |
||||
} |
||||
} |
||||
|
||||
// used when binding a parsed DateTime to a DateMidnight property
|
||||
private static class DateTimeToDateMidnightConverter implements Converter<DateTime, DateMidnight> { |
||||
public DateMidnight convert(DateTime source) { |
||||
return source.toDateMidnight(); |
||||
} |
||||
} |
||||
|
||||
// used when binding a parsed DateTime to a java.util.Date property
|
||||
private static class DateTimeToDateConverter implements Converter<DateTime, Date> { |
||||
public Date convert(DateTime source) { |
||||
return source.toDate(); |
||||
} |
||||
} |
||||
|
||||
// used when binding a parsed DateTime to a java.util.Calendar property
|
||||
private static class DateTimeToCalendarConverter implements Converter<DateTime, Calendar> { |
||||
public Calendar convert(DateTime source) { |
||||
return source.toGregorianCalendar(); |
||||
} |
||||
} |
||||
|
||||
// used when formatting a java.util.Date property with a MillisecondInstantPrinter
|
||||
private static class DateToLongConverter implements Converter<Date, Long> { |
||||
public Long convert(Date source) { |
||||
return source.getTime(); |
||||
} |
||||
} |
||||
|
||||
// used when formatting a java.util.Calendar property with a ReadableInstantPrinter
|
||||
private static class CalendarToDateTimeConverter implements Converter<Calendar, ReadableInstant> { |
||||
public ReadableInstant convert(Calendar source) { |
||||
return new DateTime(source); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,154 @@
@@ -0,0 +1,154 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
|
||||
import org.joda.time.DateTime; |
||||
import org.joda.time.LocalDate; |
||||
import org.joda.time.LocalDateTime; |
||||
import org.joda.time.LocalTime; |
||||
import org.joda.time.ReadableInstant; |
||||
import org.joda.time.format.DateTimeFormat; |
||||
import org.joda.time.format.DateTimeFormatter; |
||||
import org.joda.time.format.ISODateTimeFormat; |
||||
import org.springframework.ui.format.FormatterRegistry; |
||||
import org.springframework.ui.format.Parser; |
||||
import org.springframework.ui.format.Printer; |
||||
|
||||
/** |
||||
* Configures Joda Time's Formatting system for use with Spring. |
||||
* @author Keith Donald |
||||
*/ |
||||
public class JodaTimeFormattingConfigurer { |
||||
|
||||
private FormatterRegistry formatterRegistry; |
||||
|
||||
private String dateStyle; |
||||
|
||||
private String timeStyle; |
||||
|
||||
private String dateTimeStyle; |
||||
|
||||
private boolean useISOFormat; |
||||
|
||||
/** |
||||
* Creates a new JodaTimeFormattingConfigurer that installs into the provided FormatterRegistry. |
||||
* Call {@link #registerJodaTimeFormatting()} to install. |
||||
* @param formatterRegistry the registry to register Joda Time formatters with |
||||
*/ |
||||
public JodaTimeFormattingConfigurer(FormatterRegistry formatterRegistry) { |
||||
this.formatterRegistry = formatterRegistry; |
||||
} |
||||
|
||||
/** |
||||
* Set the default format style of Joda {@link LocalDate} objects. |
||||
* Default is {@link DateTimeFormat#shortDate()}. |
||||
* @param dateStyle the date format style |
||||
*/ |
||||
public void setDateStyle(String dateStyle) { |
||||
this.dateStyle = dateStyle; |
||||
} |
||||
|
||||
/** |
||||
* Set the default format style of Joda {@link LocalTime} objects. |
||||
* Default is {@link DateTimeFormat#shortTime()}. |
||||
* @param timeStyle the time format style |
||||
*/ |
||||
public void setTimeStyle(String timeStyle) { |
||||
this.timeStyle = timeStyle; |
||||
} |
||||
|
||||
/** |
||||
* Set the default format style of Joda {@link LocalDateTime} and {@link DateTime} objects, as well as JDK {@link Date} and {@link Calendar} objects. |
||||
* Default is {@link DateTimeFormat#shortDateTime()}. |
||||
* @param dateTimeStyle the date time format style |
||||
*/ |
||||
public void setDateTimeStyle(String dateTimeStyle) { |
||||
this.dateTimeStyle = dateTimeStyle; |
||||
} |
||||
|
||||
/** |
||||
* Set whether standard ISO formatting should be applied to all Date/Time types. |
||||
* Default is false (no). |
||||
* If set to true, the dateStyle, timeStyle, and dateTimeStyle properties are ignored. |
||||
* @param useISOFormat true to enable ISO formatting |
||||
*/ |
||||
public void setUseISOFormat(boolean useISOFormat) { |
||||
this.useISOFormat = useISOFormat; |
||||
} |
||||
|
||||
/** |
||||
* Install Joda Time formatters given the current configuration of this {@link JodaTimeFormattingConfigurer}. |
||||
*/ |
||||
public void registerJodaTimeFormatting() { |
||||
JodaTimeConverters.registerConverters(this.formatterRegistry.getConverterRegistry()); |
||||
|
||||
DateTimeFormatter jodaDateFormatter = getJodaDateFormatter(); |
||||
this.formatterRegistry.addFormatterForFieldType(LocalDate.class, new ReadablePartialPrinter(jodaDateFormatter), new DateTimeParser(jodaDateFormatter)); |
||||
|
||||
DateTimeFormatter jodaTimeFormatter = getJodaTimeFormatter(); |
||||
this.formatterRegistry.addFormatterForFieldType(LocalTime.class, new ReadablePartialPrinter(jodaTimeFormatter), new DateTimeParser(jodaTimeFormatter)); |
||||
|
||||
DateTimeFormatter jodaDateTimeFormatter = getJodaDateTimeFormatter(); |
||||
Parser<DateTime> dateTimeParser = new DateTimeParser(jodaDateTimeFormatter); |
||||
this.formatterRegistry.addFormatterForFieldType(LocalDateTime.class, new ReadablePartialPrinter(jodaDateTimeFormatter), dateTimeParser); |
||||
|
||||
Printer<ReadableInstant> readableInstantPrinter = new ReadableInstantPrinter(jodaDateTimeFormatter); |
||||
this.formatterRegistry.addFormatterForFieldType(ReadableInstant.class, readableInstantPrinter, dateTimeParser); |
||||
this.formatterRegistry.addFormatterForFieldType(Calendar.class, readableInstantPrinter, dateTimeParser); |
||||
this.formatterRegistry.addFormatterForFieldType(Calendar.class, new MillisecondInstantPrinter(jodaDateTimeFormatter), dateTimeParser); |
||||
|
||||
this.formatterRegistry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory()); |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private DateTimeFormatter getJodaDateFormatter() { |
||||
if (this.useISOFormat) { |
||||
return ISODateTimeFormat.date(); |
||||
} |
||||
if (this.dateStyle != null) { |
||||
return DateTimeFormat.forStyle(this.dateStyle + "-"); |
||||
} else { |
||||
return DateTimeFormat.shortDate(); |
||||
} |
||||
} |
||||
|
||||
private DateTimeFormatter getJodaTimeFormatter() { |
||||
if (this.useISOFormat) { |
||||
return ISODateTimeFormat.time(); |
||||
} |
||||
if (this.timeStyle != null) { |
||||
return DateTimeFormat.forStyle("-" + this.timeStyle); |
||||
} else { |
||||
return DateTimeFormat.shortTime(); |
||||
} |
||||
} |
||||
|
||||
private DateTimeFormatter getJodaDateTimeFormatter() { |
||||
if (this.useISOFormat) { |
||||
return ISODateTimeFormat.dateTime(); |
||||
} |
||||
if (this.dateTimeStyle != null) { |
||||
return DateTimeFormat.forStyle(this.dateTimeStyle); |
||||
} else { |
||||
return DateTimeFormat.shortDateTime(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.joda.time.format.DateTimeFormatter; |
||||
import org.springframework.ui.format.Printer; |
||||
|
||||
/** |
||||
* Prints Long instances using a {@link DateTimeFormatter}. |
||||
* @author Keith Donald |
||||
*/ |
||||
public final class MillisecondInstantPrinter implements Printer<Long> { |
||||
|
||||
private final DateTimeFormatter formatter; |
||||
|
||||
/** |
||||
* Creates a new ReadableInstantPrinter. |
||||
* @param formatter the Joda DateTimeFormatter instance |
||||
*/ |
||||
public MillisecondInstantPrinter(DateTimeFormatter formatter) { |
||||
this.formatter = formatter; |
||||
} |
||||
|
||||
public String print(Long instant, Locale locale) { |
||||
return JodaTimeContextHolder.getFormatter(this.formatter, locale).print(instant); |
||||
} |
||||
} |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.joda.time.ReadableInstant; |
||||
import org.joda.time.format.DateTimeFormatter; |
||||
import org.springframework.ui.format.Printer; |
||||
|
||||
/** |
||||
* Prints Joda Time {@link ReadableInstant} instances using a {@link DateTimeFormatter}. |
||||
* @author Keith Donald |
||||
*/ |
||||
public final class ReadableInstantPrinter implements Printer<ReadableInstant> { |
||||
|
||||
private final DateTimeFormatter formatter; |
||||
|
||||
/** |
||||
* Creates a new ReadableInstantPrinter. |
||||
* @param formatter the Joda DateTimeFormatter instance |
||||
*/ |
||||
public ReadableInstantPrinter(DateTimeFormatter formatter) { |
||||
this.formatter = formatter; |
||||
} |
||||
|
||||
public String print(ReadableInstant instant, Locale locale) { |
||||
return JodaTimeContextHolder.getFormatter(this.formatter, locale).print(instant); |
||||
} |
||||
} |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.jodatime; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.joda.time.ReadablePartial; |
||||
import org.joda.time.format.DateTimeFormatter; |
||||
import org.springframework.ui.format.Printer; |
||||
|
||||
/** |
||||
* Prints Joda Time {@link ReadablePartial} instances using a {@link DateTimeFormatter}. |
||||
* @author Keith Donald |
||||
*/ |
||||
public final class ReadablePartialPrinter implements Printer<ReadablePartial> { |
||||
|
||||
private final DateTimeFormatter formatter; |
||||
|
||||
/** |
||||
* Creates a new ReadableInstantPrinter. |
||||
* @param formatter the Joda DateTimeFormatter instance |
||||
*/ |
||||
public ReadablePartialPrinter(DateTimeFormatter formatter) { |
||||
this.formatter = formatter; |
||||
} |
||||
|
||||
public String print(ReadablePartial partial, Locale locale) { |
||||
return JodaTimeContextHolder.getFormatter(this.formatter, locale).print(partial); |
||||
} |
||||
} |
||||
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
/** |
||||
* Integration with the Joda Time for formatting Joda types as well as standard JDK Date types. |
||||
*/ |
||||
package org.springframework.ui.format.jodatime; |
||||
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
/** |
||||
* A SPI for defining Formatters to format field model values for display in a UI. |
||||
* An API for defining Formatters to format field model values for display in a UI. |
||||
*/ |
||||
package org.springframework.ui.format; |
||||
|
||||
@ -1,406 +0,0 @@
@@ -1,406 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.support; |
||||
|
||||
import java.lang.annotation.Annotation; |
||||
import java.text.ParseException; |
||||
import java.util.LinkedList; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import org.springframework.beans.BeanUtils; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.ApplicationContextAware; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.core.GenericTypeResolver; |
||||
import org.springframework.core.annotation.AnnotationUtils; |
||||
import org.springframework.core.convert.ConversionService; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.core.convert.support.DefaultConversionService; |
||||
import org.springframework.ui.format.AnnotationFormatterFactory; |
||||
import org.springframework.ui.format.Formatted; |
||||
import org.springframework.ui.format.Formatter; |
||||
import org.springframework.ui.format.FormatterRegistry; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* A generic implementation of {@link org.springframework.ui.format.FormatterRegistry} |
||||
* suitable for use in most environments. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
* @see #setFormatters(Set) |
||||
* @see #setFormatterMap(Map) |
||||
* @see #setAnnotationFormatterMap(Map) |
||||
* @see #setAnnotationFormatterFactories(Set) |
||||
* @see #setConversionService(ConversionService) |
||||
* @see #addFormatterByType(Formatter) |
||||
* @see #addFormatterByType(Class, Formatter) |
||||
* @see #addFormatterByAnnotation(Class, Formatter) |
||||
* @see #addFormatterByAnnotation(AnnotationFormatterFactory) |
||||
*/ |
||||
public class GenericFormatterRegistry implements FormatterRegistry, ApplicationContextAware, Cloneable { |
||||
|
||||
private final Map<Class<?>, FormatterHolder> typeFormatters = new ConcurrentHashMap<Class<?>, FormatterHolder>(); |
||||
|
||||
private final Map<Class<?>, AnnotationFormatterFactoryHolder> annotationFormatters = new ConcurrentHashMap<Class<?>, AnnotationFormatterFactoryHolder>(); |
||||
|
||||
private ConversionService conversionService; |
||||
|
||||
private ApplicationContext applicationContext; |
||||
|
||||
private boolean shared = true; |
||||
|
||||
/** |
||||
* Registers the formatters in the set provided. |
||||
* JavaBean-friendly alternative to calling {@link #addFormatterByType(Formatter)}. |
||||
* @see #add(Formatter) |
||||
*/ |
||||
public void setFormatters(Set<Formatter<?>> formatters) { |
||||
for (Formatter<?> formatter : formatters) { |
||||
addFormatterByType(formatter); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Registers the formatters in the map provided by type. |
||||
* JavaBean-friendly alternative to calling {@link #addFormatterByType(Class, Formatter)}. |
||||
* @see #add(Class, Formatter) |
||||
*/ |
||||
public void setFormatterMap(Map<Class<?>, Formatter<?>> formatters) { |
||||
for (Map.Entry<Class<?>, Formatter<?>> entry : formatters.entrySet()) { |
||||
addFormatterByType(entry.getKey(), entry.getValue()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Registers the formatters in the map provided by annotation type. |
||||
* JavaBean-friendly alternative to calling {@link #addFormatterByAnnotation(Class, Formatter)}. |
||||
* @see #add(Class, Formatter) |
||||
*/ |
||||
public void setAnnotationFormatterMap(Map<Class<? extends Annotation>, Formatter<?>> formatters) { |
||||
for (Map.Entry<Class<? extends Annotation>, Formatter<?>> entry : formatters.entrySet()) { |
||||
addFormatterByAnnotation(entry.getKey(), entry.getValue()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Registers the annotation formatter factories in the set provided. |
||||
* JavaBean-friendly alternative to calling {@link #addFormatterByAnnotation(AnnotationFormatterFactory)}. |
||||
* @see #add(AnnotationFormatterFactory) |
||||
*/ |
||||
public void setAnnotationFormatterFactories(Set<AnnotationFormatterFactory<?, ?>> factories) { |
||||
for (AnnotationFormatterFactory<?, ?> factory : factories) { |
||||
addFormatterByAnnotation(factory); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Specify the type conversion service that will be used to coerce objects to the |
||||
* types required for formatting. Defaults to a {@link DefaultConversionService}. |
||||
* @see #addFormatterByType(Class, Formatter) |
||||
*/ |
||||
public void setConversionService(ConversionService conversionService) { |
||||
Assert.notNull(conversionService, "ConversionService must not be null"); |
||||
this.conversionService = conversionService; |
||||
} |
||||
|
||||
/** |
||||
* Return the type conversion service which this FormatterRegistry delegates to. |
||||
*/ |
||||
public ConversionService getConversionService() { |
||||
return this.conversionService; |
||||
} |
||||
|
||||
/** |
||||
* Take the context's default ConversionService if none specified locally. |
||||
*/ |
||||
public void setApplicationContext(ApplicationContext context) { |
||||
if (this.conversionService == null |
||||
&& context.containsBean(ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME)) { |
||||
this.conversionService = context.getBean(ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME, |
||||
ConversionService.class); |
||||
} |
||||
this.applicationContext = context; |
||||
} |
||||
|
||||
// cloning support
|
||||
|
||||
/** |
||||
* Specify whether this FormatterRegistry is shared, in which case newly |
||||
* registered Formatters will be visible to other callers as well. |
||||
* <p>A new GenericFormatterRegistry is considered as shared by default, |
||||
* whereas a cloned GenericFormatterRegistry will be non-shared by default. |
||||
* @see #clone() |
||||
*/ |
||||
public void setShared(boolean shared) { |
||||
this.shared = shared; |
||||
} |
||||
|
||||
/** |
||||
* Return whether this FormatterRegistry is shared, in which case newly |
||||
* registered Formatters will be visible to other callers as well. |
||||
*/ |
||||
public boolean isShared() { |
||||
return this.shared; |
||||
} |
||||
|
||||
/** |
||||
* Create an independent clone of this FormatterRegistry. |
||||
* @see #setShared |
||||
*/ |
||||
@Override |
||||
public GenericFormatterRegistry clone() { |
||||
GenericFormatterRegistry clone = new GenericFormatterRegistry(); |
||||
clone.typeFormatters.putAll(this.typeFormatters); |
||||
clone.annotationFormatters.putAll(this.annotationFormatters); |
||||
clone.conversionService = this.conversionService; |
||||
clone.applicationContext = applicationContext; |
||||
clone.shared = false; |
||||
return clone; |
||||
} |
||||
|
||||
// implementing FormatterRegistry
|
||||
|
||||
public void addFormatterByType(Formatter<?> formatter) { |
||||
Class<?> formatterObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
||||
if (formatterObjectType == null) { |
||||
throw new IllegalArgumentException("Unable to register Formatter " + formatter |
||||
+ "; cannot determine parameterized object type <T>"); |
||||
} |
||||
this.typeFormatters.put(formatterObjectType, new FormatterHolder(formatterObjectType, formatter)); |
||||
} |
||||
|
||||
public void addFormatterByType(Class<?> type, Formatter<?> formatter) { |
||||
Class<?> formatterObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
||||
if (formatterObjectType != null && !type.isAssignableFrom(formatterObjectType)) { |
||||
if (this.conversionService == null) { |
||||
throw new IllegalStateException("Unable to index Formatter " + formatter + " under type [" |
||||
+ type.getName() + "]; not able to convert from a [" + formatterObjectType.getName() |
||||
+ "] parsed by the Formatter to [" + type.getName() |
||||
+ "] because this.conversionService is null"); |
||||
} |
||||
if (!this.conversionService.canConvert(formatterObjectType, type)) { |
||||
throw new IllegalArgumentException("Unable to index Formatter " + formatter + " under type [" |
||||
+ type.getName() + "]; not able to convert from a [" + formatterObjectType.getName() |
||||
+ "] parsed by the Formatter to [" + type.getName() + "]"); |
||||
} |
||||
if (!this.conversionService.canConvert(type, formatterObjectType)) { |
||||
throw new IllegalArgumentException("Unable to index Formatter " + formatter + " under type [" |
||||
+ type.getName() + "]; not able to convert to [" + formatterObjectType.getName() |
||||
+ "] to format a [" + type.getName() + "]"); |
||||
} |
||||
} |
||||
this.typeFormatters.put(type, new FormatterHolder(formatterObjectType, formatter)); |
||||
} |
||||
|
||||
public void addFormatterByAnnotation(Class<? extends Annotation> annotationType, Formatter<?> formatter) { |
||||
Class<?> formatterObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
||||
SimpleAnnotationFormatterFactory factory = new SimpleAnnotationFormatterFactory(formatter); |
||||
this.annotationFormatters.put(annotationType, |
||||
new AnnotationFormatterFactoryHolder(formatterObjectType, factory)); |
||||
} |
||||
|
||||
public void addFormatterByAnnotation(AnnotationFormatterFactory<?, ?> factory) { |
||||
Class<?>[] typeArgs = GenericTypeResolver.resolveTypeArguments(factory.getClass(), |
||||
AnnotationFormatterFactory.class); |
||||
if (typeArgs == null || typeArgs.length != 2) { |
||||
throw new IllegalArgumentException( |
||||
"Unable to extract parameterized type arguments from AnnotationFormatterFactory [" |
||||
+ factory.getClass().getName() |
||||
+ "]; does the factory parameterize the <A> and <T> generic types?"); |
||||
} |
||||
this.annotationFormatters.put(typeArgs[0], new AnnotationFormatterFactoryHolder(typeArgs[1], factory)); |
||||
} |
||||
|
||||
public Formatter<Object> getFormatter(TypeDescriptor type) { |
||||
Assert.notNull(type, "TypeDescriptor is required"); |
||||
FormatterHolder holder = findFormatterHolderForAnnotatedProperty(type.getAnnotations()); |
||||
Class<?> objectType = type.getObjectType(); |
||||
if (holder == null) { |
||||
holder = findFormatterHolderForType(objectType); |
||||
} |
||||
if (holder == null) { |
||||
holder = getDefaultFormatterHolder(objectType); |
||||
} |
||||
if (holder == null) { |
||||
return null; |
||||
} |
||||
Class<?> formatterObjectType = holder.getFormatterObjectType(); |
||||
if (formatterObjectType != null && !objectType.isAssignableFrom(formatterObjectType)) { |
||||
if (this.conversionService != null) { |
||||
return new ConvertingFormatter(type, holder); |
||||
} else { |
||||
return null; |
||||
} |
||||
} else { |
||||
return holder.getFormatter(); |
||||
} |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private FormatterHolder findFormatterHolderForAnnotatedProperty(Annotation[] annotations) { |
||||
for (Annotation annotation : annotations) { |
||||
FormatterHolder holder = findFormatterHolderForAnnotation(annotation); |
||||
if (holder != null) { |
||||
return holder; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private FormatterHolder findFormatterHolderForAnnotation(Annotation annotation) { |
||||
Class<? extends Annotation> annotationType = annotation.annotationType(); |
||||
AnnotationFormatterFactoryHolder factory = this.annotationFormatters.get(annotationType); |
||||
if (factory != null) { |
||||
return factory.getFormatterHolder(annotation); |
||||
} else { |
||||
Formatted formatted = annotationType.getAnnotation(Formatted.class); |
||||
if (formatted != null) { |
||||
// property annotation has @Formatted meta-annotation
|
||||
Formatter<?> formatter = createFormatter(formatted.value()); |
||||
addFormatterByAnnotation(annotationType, formatter); |
||||
return findFormatterHolderForAnnotation(annotation); |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private FormatterHolder findFormatterHolderForType(Class<?> type) { |
||||
LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>(); |
||||
classQueue.addFirst(type); |
||||
while (!classQueue.isEmpty()) { |
||||
Class<?> currentClass = classQueue.removeLast(); |
||||
FormatterHolder holder = this.typeFormatters.get(currentClass); |
||||
if (holder != null) { |
||||
return holder; |
||||
} |
||||
if (currentClass.getSuperclass() != null) { |
||||
classQueue.addFirst(currentClass.getSuperclass()); |
||||
} |
||||
Class<?>[] interfaces = currentClass.getInterfaces(); |
||||
for (Class<?> ifc : interfaces) { |
||||
classQueue.addFirst(ifc); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private FormatterHolder getDefaultFormatterHolder(Class<?> type) { |
||||
Formatted formatted = AnnotationUtils.findAnnotation(type, Formatted.class); |
||||
if (formatted != null) { |
||||
Formatter<?> formatter = createFormatter(formatted.value()); |
||||
addFormatterByType(type, formatter); |
||||
return findFormatterHolderForType(type); |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
private Formatter<?> createFormatter(Class<? extends Formatter> formatterClass) { |
||||
return (this.applicationContext != null ? this.applicationContext.getAutowireCapableBeanFactory().createBean( |
||||
formatterClass) : BeanUtils.instantiate(formatterClass)); |
||||
} |
||||
|
||||
private abstract static class AbstractFormatterHolder { |
||||
|
||||
private Class<?> formatterObjectType; |
||||
|
||||
public AbstractFormatterHolder(Class<?> formatterObjectType) { |
||||
this.formatterObjectType = formatterObjectType; |
||||
} |
||||
|
||||
public Class<?> getFormatterObjectType() { |
||||
return formatterObjectType; |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class FormatterHolder extends AbstractFormatterHolder { |
||||
|
||||
private Formatter formatter; |
||||
|
||||
public FormatterHolder(Class<?> formatterObjectType, Formatter<?> formatter) { |
||||
super(formatterObjectType); |
||||
this.formatter = formatter; |
||||
} |
||||
|
||||
public Formatter getFormatter() { |
||||
return this.formatter; |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class AnnotationFormatterFactoryHolder extends AbstractFormatterHolder { |
||||
|
||||
private AnnotationFormatterFactory factory; |
||||
|
||||
public AnnotationFormatterFactoryHolder(Class<?> formatterObjectType, AnnotationFormatterFactory<?, ?> factory) { |
||||
super(formatterObjectType); |
||||
this.factory = factory; |
||||
} |
||||
|
||||
public FormatterHolder getFormatterHolder(Annotation annotation) { |
||||
return new FormatterHolder(getFormatterObjectType(), this.factory.getFormatter(annotation)); |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class SimpleAnnotationFormatterFactory implements AnnotationFormatterFactory { |
||||
|
||||
private final Formatter instance; |
||||
|
||||
public SimpleAnnotationFormatterFactory(Formatter<?> instance) { |
||||
this.instance = instance; |
||||
} |
||||
|
||||
public Formatter getFormatter(Annotation annotation) { |
||||
return this.instance; |
||||
} |
||||
} |
||||
|
||||
private class ConvertingFormatter implements Formatter { |
||||
|
||||
private final TypeDescriptor type; |
||||
|
||||
private final FormatterHolder formatterHolder; |
||||
|
||||
public ConvertingFormatter(TypeDescriptor type, FormatterHolder formatterHolder) { |
||||
this.type = type; |
||||
this.formatterHolder = formatterHolder; |
||||
} |
||||
|
||||
public String format(Object object, Locale locale) { |
||||
object = GenericFormatterRegistry.this.conversionService.convert(object, this.formatterHolder |
||||
.getFormatterObjectType()); |
||||
return this.formatterHolder.getFormatter().format(object, locale); |
||||
} |
||||
|
||||
public Object parse(String formatted, Locale locale) throws ParseException { |
||||
Object parsed = this.formatterHolder.getFormatter().parse(formatted, locale); |
||||
parsed = GenericFormatterRegistry.this.conversionService.convert(parsed, TypeDescriptor |
||||
.valueOf(this.formatterHolder.getFormatterObjectType()), this.type); |
||||
return parsed; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,234 @@
@@ -0,0 +1,234 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.support; |
||||
|
||||
import java.lang.annotation.Annotation; |
||||
import java.text.ParseException; |
||||
import java.util.LinkedList; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import org.springframework.core.GenericTypeResolver; |
||||
import org.springframework.core.convert.ConversionService; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.core.convert.converter.ConverterRegistry; |
||||
import org.springframework.core.convert.support.GenericConversionService; |
||||
import org.springframework.ui.format.AnnotationFormatterFactory; |
||||
import org.springframework.ui.format.Formatter; |
||||
import org.springframework.ui.format.FormatterRegistry; |
||||
import org.springframework.ui.format.FormattingService; |
||||
import org.springframework.ui.format.Parser; |
||||
import org.springframework.ui.format.Printer; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* A generic implementation of {@link FormattingService} suitable for use in most environments. |
||||
* Is a {@link FormatterRegistry} to allow for registration of field formatting logic. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Juergen Hoeller |
||||
* @since 3.0 |
||||
*/ |
||||
public class GenericFormattingService implements FormattingService, FormatterRegistry { |
||||
|
||||
private final Map<Class<?>, GenericFormatter> typeFormatters = new ConcurrentHashMap<Class<?>, GenericFormatter>(); |
||||
|
||||
private final Map<Class<? extends Annotation>, GenericAnnotationFormatterFactory> annotationFormatters = new ConcurrentHashMap<Class<? extends Annotation>, GenericAnnotationFormatterFactory>(); |
||||
|
||||
private GenericConversionService conversionService = new GenericConversionService(); |
||||
|
||||
/** |
||||
* Configure a parent of the type conversion service that will be used to coerce objects to types required for formatting. |
||||
*/ |
||||
public void setParentConversionService(ConversionService parentConversionService) { |
||||
this.conversionService.setParent(parentConversionService); |
||||
} |
||||
|
||||
// implementing FormattingService
|
||||
|
||||
public String print(Object fieldValue, TypeDescriptor fieldType, Locale locale) { |
||||
return getFormatter(fieldType).print(fieldValue, fieldType, locale); |
||||
} |
||||
|
||||
public Object parse(String submittedValue, TypeDescriptor fieldType, Locale locale) throws ParseException { |
||||
return getFormatter(fieldType).parse(submittedValue, fieldType, locale); |
||||
} |
||||
|
||||
// implementing FormatterRegistry
|
||||
|
||||
public void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser) { |
||||
Class<?> printerObjectType = resolvePrinterObjectType(printer); |
||||
Class<?> parserObjectType = resolveParserObjectType(parser); |
||||
this.typeFormatters.put(fieldType, new GenericFormatter(printerObjectType, printer, parserObjectType, parser)); |
||||
} |
||||
|
||||
public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) { |
||||
Class<?> formatterObjectType = resolveFormatterObjectType(formatter); |
||||
this.typeFormatters.put(fieldType, new GenericFormatter(formatterObjectType, formatter, formatterObjectType, formatter)); |
||||
} |
||||
|
||||
public void addFormatterForFieldAnnotation(AnnotationFormatterFactory<?> annotationFormatterFactory) { |
||||
Class<? extends Annotation> annotationType = resolveAnnotationType(annotationFormatterFactory); |
||||
if (annotationType == null) { |
||||
throw new IllegalArgumentException( |
||||
"Unable to extract parameterized Annotation type argument from AnnotationFormatterFactory [" |
||||
+ annotationFormatterFactory.getClass().getName() |
||||
+ "]; does the factory parameterize the <A extends Annotation> generic type?"); |
||||
} |
||||
this.annotationFormatters.put(annotationType, new GenericAnnotationFormatterFactory(annotationFormatterFactory)); |
||||
} |
||||
|
||||
public ConverterRegistry getConverterRegistry() { |
||||
return this.conversionService; |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private Class<?> resolveParserObjectType(Parser<?> parser) { |
||||
return GenericTypeResolver.resolveTypeArgument(parser.getClass(), Parser.class); |
||||
} |
||||
|
||||
private Class<?> resolvePrinterObjectType(Printer<?> printer) { |
||||
return GenericTypeResolver.resolveTypeArgument(printer.getClass(), Printer.class); |
||||
} |
||||
|
||||
private Class<?> resolveFormatterObjectType(Formatter<?> formatter) { |
||||
return GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private Class<? extends Annotation> resolveAnnotationType(AnnotationFormatterFactory<?> annotationFormatterFactory) { |
||||
return (Class<? extends Annotation>) GenericTypeResolver.resolveTypeArgument(annotationFormatterFactory.getClass(), AnnotationFormatterFactory.class); |
||||
} |
||||
|
||||
private GenericFormatter getFormatter(TypeDescriptor fieldType) { |
||||
Assert.notNull(fieldType, "Field TypeDescriptor is required"); |
||||
GenericFormatter formatter = findFormatterForAnnotatedField(fieldType); |
||||
Class<?> fieldObjectType = fieldType.getObjectType(); |
||||
if (formatter == null) { |
||||
formatter = findFormatterForFieldType(fieldObjectType); |
||||
} |
||||
return formatter; |
||||
} |
||||
|
||||
private GenericFormatter findFormatterForAnnotatedField(TypeDescriptor fieldType) { |
||||
for (Annotation annotation : fieldType.getAnnotations()) { |
||||
GenericFormatter formatter = findFormatterForAnnotation(annotation, fieldType.getObjectType()); |
||||
if (formatter != null) { |
||||
return formatter; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private GenericFormatter findFormatterForAnnotation(Annotation annotation, Class<?> fieldType) { |
||||
Class<? extends Annotation> annotationType = annotation.annotationType(); |
||||
GenericAnnotationFormatterFactory factory = this.annotationFormatters.get(annotationType); |
||||
if (factory != null) { |
||||
return factory.getFormatter(annotation, fieldType); |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
private GenericFormatter findFormatterForFieldType(Class<?> fieldType) { |
||||
LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>(); |
||||
classQueue.addFirst(fieldType); |
||||
while (!classQueue.isEmpty()) { |
||||
Class<?> currentClass = classQueue.removeLast(); |
||||
GenericFormatter formatter = this.typeFormatters.get(currentClass); |
||||
if (formatter != null) { |
||||
return formatter; |
||||
} |
||||
if (currentClass.getSuperclass() != null) { |
||||
classQueue.addFirst(currentClass.getSuperclass()); |
||||
} |
||||
Class<?>[] interfaces = currentClass.getInterfaces(); |
||||
for (Class<?> ifc : interfaces) { |
||||
classQueue.addFirst(ifc); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private class GenericFormatter { |
||||
|
||||
private TypeDescriptor printerObjectType; |
||||
|
||||
private Printer printer; |
||||
|
||||
private Parser parser; |
||||
|
||||
public GenericFormatter(Class<?> printerObjectType, Printer<?> printer, Class<?> parserObjectType, Parser<?> parser) { |
||||
this.printerObjectType = TypeDescriptor.valueOf(printerObjectType); |
||||
this.printer = printer; |
||||
this.parser = parser; |
||||
} |
||||
|
||||
public String print(Object fieldValue, TypeDescriptor fieldType, Locale locale) { |
||||
if (!fieldType.isAssignableTo(this.printerObjectType)) { |
||||
fieldValue = GenericFormattingService.this.conversionService.convert(fieldValue, fieldType, this.printerObjectType); |
||||
} |
||||
return fieldType != null ? this.printer.print(fieldValue, locale) : ""; |
||||
} |
||||
|
||||
public Object parse(String submittedValue, TypeDescriptor fieldType, Locale locale) throws ParseException { |
||||
if (submittedValue.isEmpty()) { |
||||
return null; |
||||
} |
||||
Object parsedValue = this.parser.parse(submittedValue, locale); |
||||
TypeDescriptor parsedObjectType = TypeDescriptor.valueOf(parsedValue.getClass()); |
||||
if (!parsedObjectType.isAssignableTo(fieldType)) { |
||||
parsedValue = GenericFormattingService.this.conversionService.convert(parsedValue, parsedObjectType, fieldType); |
||||
} |
||||
return parsedValue; |
||||
} |
||||
|
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private class GenericAnnotationFormatterFactory { |
||||
|
||||
private AnnotationFormatterFactory annotationFormatterFactory; |
||||
|
||||
public GenericAnnotationFormatterFactory(AnnotationFormatterFactory<?> annotationFormatterFactory) { |
||||
this.annotationFormatterFactory = annotationFormatterFactory; |
||||
} |
||||
|
||||
public GenericFormatter getFormatter(Annotation annotation, Class<?> fieldType) { |
||||
Printer<?> printer = this.annotationFormatterFactory.getPrinter(annotation, fieldType); |
||||
Parser<?> parser = this.annotationFormatterFactory.getParser(annotation, fieldType); |
||||
return new GenericFormatter(getPrinterObjectType(printer, fieldType), printer, getParserObjectType(parser, fieldType), parser); |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private Class<?> getPrinterObjectType(Printer<?> printer, Class<?> fieldType) { |
||||
// TODO cache
|
||||
return resolvePrinterObjectType(printer); |
||||
} |
||||
|
||||
private Class<?> getParserObjectType(Parser<?> parser, Class<?> fieldType) { |
||||
// TODO cache
|
||||
return resolveParserObjectType(parser); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,115 +0,0 @@
@@ -1,115 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.support; |
||||
|
||||
import java.lang.reflect.Method; |
||||
import java.lang.reflect.Modifier; |
||||
import java.util.Locale; |
||||
|
||||
import org.springframework.ui.format.Formatter; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
/** |
||||
* A generic Formatter that reflectively invokes methods on a class to carry out format and parse operations. |
||||
* The format method should be a public member method that returns a String and either accepts no arguments or a single Locale argument. |
||||
* The parse method should be a declared public static method that returns the formattedObjectType and either accepts a single String argument or String and Locale arguments. |
||||
* Throws an {@link IllegalArgumentException} if either the format method or parse method could not be resolved. |
||||
* Useful for invoking existing Formatter logic on a formattable type without needing a dedicated Formatter class. |
||||
* |
||||
* @author Keith Donald |
||||
*/ |
||||
public class MethodInvokingFormatter implements Formatter { |
||||
|
||||
private Class<?> formattedObjectType; |
||||
|
||||
private Method formatMethod; |
||||
|
||||
private boolean formatMethodLocaleArgumentPresent; |
||||
|
||||
private Method parseMethod; |
||||
|
||||
private boolean parseMethodLocaleArgumentPresent; |
||||
|
||||
/** |
||||
* Creates a new reflective method invoking formatter. |
||||
* @param formattedObjectType the object type that contains format and parse methods |
||||
* @param formatMethodName the format method name e.g. "toString" |
||||
* @param parseMethodName the parse method name e.g. "valueOf" |
||||
*/ |
||||
public MethodInvokingFormatter(Class<?> formattedObjectType, String formatMethodName, String parseMethodName) { |
||||
this.formattedObjectType = formattedObjectType; |
||||
resolveFormatMethod(formatMethodName); |
||||
resolveParseMethod(parseMethodName); |
||||
} |
||||
|
||||
public String format(Object object, Locale locale) { |
||||
if (this.formatMethodLocaleArgumentPresent) { |
||||
return (String) ReflectionUtils.invokeMethod(this.formatMethod, object, locale); |
||||
} else { |
||||
return (String) ReflectionUtils.invokeMethod(this.formatMethod, object); |
||||
} |
||||
} |
||||
|
||||
public Object parse(String formatted, Locale locale) { |
||||
if (this.parseMethodLocaleArgumentPresent) { |
||||
return ReflectionUtils.invokeMethod(this.parseMethod, null, formatted, locale); |
||||
} else { |
||||
return ReflectionUtils.invokeMethod(this.parseMethod, null, formatted); |
||||
} |
||||
} |
||||
|
||||
private void resolveFormatMethod(String methodName) { |
||||
Method[] methods = this.formattedObjectType.getMethods(); |
||||
for (Method method : methods) { |
||||
if (method.getName().equals(methodName) && method.getReturnType().equals(String.class)) { |
||||
if (method.getParameterTypes().length == 0) { |
||||
this.formatMethod = method; |
||||
} else if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(Locale.class)) { |
||||
this.formatMethod = method; |
||||
this.formatMethodLocaleArgumentPresent = true; |
||||
} |
||||
} |
||||
} |
||||
if (this.formatMethod == null) { |
||||
throw new IllegalArgumentException("Unable to resolve format method '" + methodName + "' on class [" |
||||
+ this.formattedObjectType.getName() |
||||
+ "] method should have signature [public String <methodName>()] " |
||||
+ "or [public String <methodName>(Locale)]"); |
||||
} |
||||
} |
||||
|
||||
private void resolveParseMethod(String methodName) { |
||||
Method[] methods = this.formattedObjectType.getDeclaredMethods(); |
||||
for (Method method : methods) { |
||||
if (method.getName().equals(methodName) && method.getReturnType().equals(this.formattedObjectType) |
||||
&& Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers())) { |
||||
if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(String.class)) { |
||||
this.parseMethod = method; |
||||
} else if (method.getParameterTypes().length == 2 && method.getParameterTypes()[0].equals(String.class) |
||||
&& method.getParameterTypes()[1].equals(Locale.class)) { |
||||
this.parseMethod = method; |
||||
this.parseMethodLocaleArgumentPresent = true; |
||||
} |
||||
} |
||||
} |
||||
if (this.parseMethod == null) { |
||||
throw new IllegalArgumentException("Unable to resolve parse method '" + methodName + "' on class [" |
||||
+ this.formattedObjectType.getName() |
||||
+ "]; method should have signature [public static T <methodName>(String)] " |
||||
+ "or [public static T <methodName>(String, Locale)]"); |
||||
} |
||||
} |
||||
} |
||||
@ -1,228 +0,0 @@
@@ -1,228 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.support; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertNull; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
import java.math.BigDecimal; |
||||
import java.math.BigInteger; |
||||
import java.text.ParseException; |
||||
import java.util.Locale; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.core.convert.support.DefaultConversionService; |
||||
import org.springframework.core.style.ToStringCreator; |
||||
import org.springframework.ui.format.AnnotationFormatterFactory; |
||||
import org.springframework.ui.format.Formatted; |
||||
import org.springframework.ui.format.Formatter; |
||||
import org.springframework.ui.format.number.CurrencyFormatter; |
||||
import org.springframework.ui.format.number.IntegerFormatter; |
||||
import org.springframework.ui.format.support.GenericFormatterRegistry; |
||||
|
||||
/** |
||||
* @author Keith Donald |
||||
* @author Juergen Hoeller |
||||
*/ |
||||
public class GenericFormatterRegistryTests { |
||||
|
||||
private GenericFormatterRegistry registry; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
registry = new GenericFormatterRegistry(); |
||||
registry.setConversionService(new DefaultConversionService()); |
||||
} |
||||
|
||||
@Test |
||||
public void testAdd() throws ParseException { |
||||
registry.addFormatterByType(new IntegerFormatter()); |
||||
Formatter formatter = registry.getFormatter(TypeDescriptor.valueOf(Integer.class)); |
||||
String formatted = formatter.format(new Integer(3), Locale.US); |
||||
assertEquals("3", formatted); |
||||
Integer i = (Integer) formatter.parse("3", Locale.US); |
||||
assertEquals(new Integer(3), i); |
||||
} |
||||
|
||||
@Test |
||||
public void testAddLookupByPrimitive() throws ParseException { |
||||
registry.addFormatterByType(new IntegerFormatter()); |
||||
Formatter formatter = registry.getFormatter(TypeDescriptor.valueOf(int.class)); |
||||
String formatted = formatter.format(3, Locale.US); |
||||
assertEquals("3", formatted); |
||||
int integer = (Integer) formatter.parse("3", Locale.US); |
||||
assertEquals(3, integer); |
||||
} |
||||
|
||||
@Test |
||||
public void testAddByObjectType() { |
||||
registry.addFormatterByType(BigInteger.class, new IntegerFormatter()); |
||||
Formatter formatter = registry.getFormatter(TypeDescriptor.valueOf(BigInteger.class)); |
||||
String formatted = formatter.format(new BigInteger("3"), Locale.US); |
||||
assertEquals("3", formatted); |
||||
} |
||||
|
||||
@Test |
||||
public void testAddByAnnotation() throws Exception { |
||||
registry.addFormatterByAnnotation(Currency.class, new CurrencyFormatter()); |
||||
Formatter formatter = registry.getFormatter(new TypeDescriptor(getClass().getField("currencyField"))); |
||||
String formatted = formatter.format(new BigDecimal("5.00"), Locale.US); |
||||
assertEquals("$5.00", formatted); |
||||
} |
||||
|
||||
@Test |
||||
public void testAddAnnotationFormatterFactory() throws Exception { |
||||
registry.addFormatterByAnnotation(new CurrencyAnnotationFormatterFactory()); |
||||
Formatter formatter = registry.getFormatter(new TypeDescriptor(getClass().getField("currencyField"))); |
||||
String formatted = formatter.format(new BigDecimal("5.00"), Locale.US); |
||||
assertEquals("$5.00", formatted); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetDefaultFormatterFromMetaAnnotation() throws Exception { |
||||
Formatter formatter = registry.getFormatter(new TypeDescriptor(getClass().getField("smartCurrencyField"))); |
||||
String formatted = formatter.format(new BigDecimal("5.00"), Locale.US); |
||||
assertEquals("$5.00", formatted); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetDefaultFormatterForType() { |
||||
Formatter formatter = registry.getFormatter(TypeDescriptor.valueOf(Address.class)); |
||||
Address address = new Address(); |
||||
address.street = "12345 Bel Aire Estates"; |
||||
address.city = "Palm Bay"; |
||||
address.state = "FL"; |
||||
address.zip = "12345"; |
||||
String formatted = formatter.format(address, Locale.US); |
||||
assertEquals("12345 Bel Aire Estates:Palm Bay:FL:12345", formatted); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetDefaultFormatterNull() throws ParseException { |
||||
assertNull(registry.getFormatter(TypeDescriptor.valueOf(Integer.class))); |
||||
} |
||||
|
||||
@Test(expected = IllegalArgumentException.class) |
||||
public void testGetFormatterCannotConvert() { |
||||
registry.addFormatterByType(Integer.class, new AddressFormatter()); |
||||
} |
||||
|
||||
@Currency |
||||
public BigDecimal currencyField; |
||||
|
||||
@SmartCurrency |
||||
public BigDecimal smartCurrencyField; |
||||
|
||||
@Target( { ElementType.METHOD, ElementType.FIELD }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public @interface Currency { |
||||
} |
||||
|
||||
@Target( { ElementType.METHOD, ElementType.FIELD }) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Formatted(CurrencyFormatter.class) |
||||
public @interface SmartCurrency { |
||||
} |
||||
|
||||
public static class CurrencyAnnotationFormatterFactory implements AnnotationFormatterFactory<Currency, Number> { |
||||
|
||||
private final CurrencyFormatter currencyFormatter = new CurrencyFormatter(); |
||||
|
||||
public Formatter<Number> getFormatter(Currency annotation) { |
||||
return this.currencyFormatter; |
||||
} |
||||
} |
||||
|
||||
@Formatted(AddressFormatter.class) |
||||
public static class Address { |
||||
|
||||
private String street; |
||||
private String city; |
||||
private String state; |
||||
private String zip; |
||||
private String country; |
||||
|
||||
public String getStreet() { |
||||
return street; |
||||
} |
||||
|
||||
public void setStreet(String street) { |
||||
this.street = street; |
||||
} |
||||
|
||||
public String getCity() { |
||||
return city; |
||||
} |
||||
|
||||
public void setCity(String city) { |
||||
this.city = city; |
||||
} |
||||
|
||||
public String getState() { |
||||
return state; |
||||
} |
||||
|
||||
public void setState(String state) { |
||||
this.state = state; |
||||
} |
||||
|
||||
public String getZip() { |
||||
return zip; |
||||
} |
||||
|
||||
public void setZip(String zip) { |
||||
this.zip = zip; |
||||
} |
||||
|
||||
public String getCountry() { |
||||
return country; |
||||
} |
||||
|
||||
public void setCountry(String country) { |
||||
this.country = country; |
||||
} |
||||
|
||||
public String toString() { |
||||
return new ToStringCreator(this).append("street", street).append("city", city).append("state", state) |
||||
.append("zip", zip).toString(); |
||||
} |
||||
} |
||||
|
||||
public static class AddressFormatter implements Formatter<Address> { |
||||
|
||||
public String format(Address address, Locale locale) { |
||||
return address.getStreet() + ":" + address.getCity() + ":" + address.getState() + ":" + address.getZip(); |
||||
} |
||||
|
||||
public Address parse(String formatted, Locale locale) throws ParseException { |
||||
Address address = new Address(); |
||||
String[] fields = formatted.split(":"); |
||||
address.setStreet(fields[0]); |
||||
address.setCity(fields[1]); |
||||
address.setState(fields[2]); |
||||
address.setZip(fields[3]); |
||||
return address; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.ui.format.support; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
import java.text.ParseException; |
||||
import java.util.Date; |
||||
import java.util.Locale; |
||||
|
||||
import org.joda.time.DateTime; |
||||
import org.joda.time.LocalDate; |
||||
import org.joda.time.format.DateTimeFormat; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.core.convert.converter.Converter; |
||||
import org.springframework.core.convert.support.DefaultConversionService; |
||||
import org.springframework.ui.format.jodatime.DateTimeFormatAnnotationFormatterFactory; |
||||
import org.springframework.ui.format.jodatime.DateTimeParser; |
||||
import org.springframework.ui.format.jodatime.ReadablePartialPrinter; |
||||
import org.springframework.ui.format.jodatime.DateTimeFormat.FormatStyle; |
||||
import org.springframework.ui.format.number.IntegerFormatter; |
||||
|
||||
/** |
||||
* @author Keith Donald |
||||
* @author Juergen Hoeller |
||||
*/ |
||||
public class GenericFormattingServiceTests { |
||||
|
||||
private GenericFormattingService formattingService; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
formattingService = new GenericFormattingService(); |
||||
formattingService.setParentConversionService(new DefaultConversionService()); |
||||
} |
||||
|
||||
@Test |
||||
public void testFormatFieldForTypeWithFormatter() throws ParseException { |
||||
formattingService.addFormatterForFieldType(Number.class, new IntegerFormatter()); |
||||
String formatted = formattingService.print(new Integer(3), TypeDescriptor.valueOf(Integer.class), Locale.US); |
||||
assertEquals("3", formatted); |
||||
Integer i = (Integer) formattingService.parse("3", TypeDescriptor.valueOf(Integer.class), Locale.US); |
||||
assertEquals(new Integer(3), i); |
||||
} |
||||
|
||||
@Test |
||||
public void testFormatFieldForTypeWithPrinterParserWithCoersion() throws ParseException { |
||||
formattingService.getConverterRegistry().addConverter(new Converter<DateTime, LocalDate>() { |
||||
public LocalDate convert(DateTime source) { |
||||
return source.toLocalDate(); |
||||
} |
||||
}); |
||||
formattingService.addFormatterForFieldType(LocalDate.class, new ReadablePartialPrinter(DateTimeFormat |
||||
.shortDate()), new DateTimeParser(DateTimeFormat.shortDate())); |
||||
String formatted = formattingService.print(new LocalDate(2009, 10, 31), TypeDescriptor.valueOf(LocalDate.class), Locale.US); |
||||
assertEquals("10/31/09", formatted); |
||||
LocalDate date = (LocalDate) formattingService.parse("10/31/09", TypeDescriptor.valueOf(LocalDate.class), Locale.US); |
||||
assertEquals(new LocalDate(2009, 10, 31), date); |
||||
} |
||||
|
||||
@Test |
||||
public void testFormatFieldForAnnotation() throws Exception { |
||||
formattingService.getConverterRegistry().addConverter(new Converter<Date, Long>() { |
||||
public Long convert(Date source) { |
||||
return source.getTime(); |
||||
} |
||||
}); |
||||
formattingService.getConverterRegistry().addConverter(new Converter<DateTime, Date>() { |
||||
public Date convert(DateTime source) { |
||||
return source.toDate(); |
||||
} |
||||
}); |
||||
formattingService.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory()); |
||||
String formatted = formattingService.print(new LocalDate(2009, 10, 31).toDateTimeAtCurrentTime().toDate(), new TypeDescriptor(Model.class.getField("date")), Locale.US); |
||||
assertEquals("10/31/09", formatted); |
||||
LocalDate date = new LocalDate(formattingService.parse("10/31/09", new TypeDescriptor(Model.class.getField("date")), Locale.US)); |
||||
assertEquals(new LocalDate(2009, 10, 31), date); |
||||
} |
||||
|
||||
private static class Model { |
||||
|
||||
@SuppressWarnings("unused") |
||||
@org.springframework.ui.format.jodatime.DateTimeFormat(dateStyle=FormatStyle.SHORT) |
||||
public Date date; |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
@ -1,75 +0,0 @@
@@ -1,75 +0,0 @@
|
||||
package org.springframework.ui.format.support; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.ui.format.support.MethodInvokingFormatter; |
||||
|
||||
public class MethodInvokingFormatterTests { |
||||
|
||||
private MethodInvokingFormatter formatter = new MethodInvokingFormatter(AccountNumber.class, "getFormatted", |
||||
"valueOf"); |
||||
|
||||
private MethodInvokingFormatter formatter2 = new MethodInvokingFormatter(I8nAccountNumber.class, "getFormatted", |
||||
"valueOf"); |
||||
|
||||
@Test |
||||
public void testFormat() { |
||||
assertEquals("123456789", formatter.format(new AccountNumber(123456789L), null)); |
||||
} |
||||
|
||||
@Test |
||||
public void testParse() { |
||||
assertEquals(new Long(123456789), ((AccountNumber) formatter.parse("123456789", null)).number); |
||||
} |
||||
|
||||
@Test |
||||
public void testFormatI18n() { |
||||
assertEquals("123456789", formatter2.format(new I8nAccountNumber(123456789L), Locale.GERMAN)); |
||||
} |
||||
|
||||
@Test |
||||
public void testParseI18n() { |
||||
assertEquals(new Long(123456789), ((I8nAccountNumber) formatter2.parse("123456789", Locale.GERMAN)).number); |
||||
} |
||||
|
||||
public static class AccountNumber { |
||||
|
||||
private Long number; |
||||
|
||||
public AccountNumber(Long number) { |
||||
this.number = number; |
||||
} |
||||
|
||||
public String getFormatted() { |
||||
return number.toString(); |
||||
} |
||||
|
||||
public static AccountNumber valueOf(String str) { |
||||
return new AccountNumber(Long.valueOf(str)); |
||||
} |
||||
|
||||
} |
||||
|
||||
public static class I8nAccountNumber { |
||||
|
||||
private Long number; |
||||
|
||||
public I8nAccountNumber(Long number) { |
||||
this.number = number; |
||||
} |
||||
|
||||
public String getFormatted(Locale locale) { |
||||
assertEquals(Locale.GERMAN, locale); |
||||
return number.toString(); |
||||
} |
||||
|
||||
public static I8nAccountNumber valueOf(String str, Locale locale) { |
||||
assertEquals(Locale.GERMAN, locale); |
||||
return new I8nAccountNumber(Long.valueOf(str)); |
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -1,130 +0,0 @@
@@ -1,130 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2009 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.core.convert.support; |
||||
|
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
|
||||
import org.joda.time.DateMidnight; |
||||
import org.joda.time.DateTime; |
||||
import org.joda.time.LocalDate; |
||||
import org.joda.time.LocalDateTime; |
||||
import org.joda.time.LocalTime; |
||||
import org.springframework.core.convert.converter.Converter; |
||||
import org.springframework.util.ClassUtils; |
||||
|
||||
class JodaTimeConverters { |
||||
|
||||
public static void addConverters(GenericConversionService registry) { |
||||
if (!isJodaTimePresent()) { |
||||
return; |
||||
} |
||||
registry.addConverter(DateTime.class, LocalDate.class, new DateTimeToLocalDateConverter()); |
||||
registry.addConverter(LocalDate.class, DateTime.class, new LocalDateToDateTimeConverter()); |
||||
|
||||
registry.addConverter(DateTime.class, LocalTime.class, new DateTimeToLocalTimeConverter()); |
||||
registry.addConverter(LocalTime.class, DateTime.class, new LocalTimeToDateTimeConverter()); |
||||
|
||||
registry.addConverter(DateTime.class, LocalDateTime.class, new DateTimeToLocalDateTimeConverter()); |
||||
registry.addConverter(LocalDateTime.class, DateTime.class, new LocalDateTimeToDateTimeConverter()); |
||||
|
||||
registry.addConverter(DateTime.class, DateMidnight.class, new DateTimeToDateMidnightConverter()); |
||||
registry.addConverter(DateMidnight.class, Date.class, new DateMidnightToDateTimeConverter()); |
||||
|
||||
registry.addConverter(DateTime.class, Date.class, new DateTimeToDateConverter()); |
||||
registry.addConverter(Date.class, DateTime.class, new DateToDateTimeConverter()); |
||||
|
||||
registry.addConverter(DateTime.class, Calendar.class, new DateTimeToCalendarConverter()); |
||||
registry.addConverter(Calendar.class, DateTime.class, new CalendarToDateTimeConverter()); |
||||
} |
||||
|
||||
private static boolean isJodaTimePresent() { |
||||
return ClassUtils.isPresent("org.joda.time.DateTime", JodaTimeConverters.class.getClassLoader()); |
||||
} |
||||
|
||||
private static class DateTimeToLocalDateConverter implements Converter<DateTime, LocalDate> { |
||||
public LocalDate convert(DateTime source) { |
||||
return source.toLocalDate(); |
||||
} |
||||
} |
||||
|
||||
private static class LocalDateToDateTimeConverter implements Converter<LocalDate, DateTime> { |
||||
public DateTime convert(LocalDate source) { |
||||
return source.toDateTimeAtStartOfDay(); |
||||
} |
||||
} |
||||
|
||||
private static class DateTimeToLocalTimeConverter implements Converter<DateTime, LocalTime> { |
||||
public LocalTime convert(DateTime source) { |
||||
return source.toLocalTime(); |
||||
} |
||||
} |
||||
|
||||
private static class LocalTimeToDateTimeConverter implements Converter<LocalTime, DateTime> { |
||||
public DateTime convert(LocalTime source) { |
||||
return source.toDateTimeToday(); |
||||
} |
||||
} |
||||
|
||||
private static class DateTimeToLocalDateTimeConverter implements Converter<DateTime, LocalDateTime> { |
||||
public LocalDateTime convert(DateTime source) { |
||||
return source.toLocalDateTime(); |
||||
} |
||||
} |
||||
|
||||
private static class LocalDateTimeToDateTimeConverter implements Converter<LocalDateTime, DateTime> { |
||||
public DateTime convert(LocalDateTime source) { |
||||
return source.toDateTime(); |
||||
} |
||||
} |
||||
|
||||
private static class DateTimeToDateMidnightConverter implements Converter<DateTime, DateMidnight> { |
||||
public DateMidnight convert(DateTime source) { |
||||
return source.toDateMidnight(); |
||||
} |
||||
} |
||||
|
||||
private static class DateMidnightToDateTimeConverter implements Converter<DateMidnight, DateTime> { |
||||
public DateTime convert(DateMidnight source) { |
||||
return source.toDateTime(); |
||||
} |
||||
} |
||||
|
||||
private static class DateTimeToDateConverter implements Converter<DateTime, Date> { |
||||
public Date convert(DateTime source) { |
||||
return source.toDate(); |
||||
} |
||||
} |
||||
|
||||
private static class DateToDateTimeConverter implements Converter<Date, DateTime> { |
||||
public DateTime convert(Date source) { |
||||
return new DateTime(source); |
||||
} |
||||
} |
||||
|
||||
private static class DateTimeToCalendarConverter implements Converter<DateTime, Calendar> { |
||||
public Calendar convert(DateTime source) { |
||||
return source.toGregorianCalendar(); |
||||
} |
||||
} |
||||
|
||||
private static class CalendarToDateTimeConverter implements Converter<Calendar, DateTime> { |
||||
public DateTime convert(Calendar source) { |
||||
return new DateTime(source); |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue