Keith Donald
15 years ago
3 changed files with 194 additions and 1 deletions
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
/* |
||||
* 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)]"); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
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)); |
||||
} |
||||
|
||||
} |
||||
} |
Loading…
Reference in new issue