Skip to content

Commit

Permalink
added Field context variant to TypeConverter interface in beans module;
Browse files Browse the repository at this point in the history
@value injection works in combination with formatting rules such as @DateTimeFormat

Issue: SPR-9637
  • Loading branch information
jhoeller committed Sep 4, 2012
1 parent 780a259 commit e904589
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 121 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,8 +31,7 @@
* @see #getPropertyValue
* @see #setPropertyValue
*/
public abstract class AbstractPropertyAccessor extends PropertyEditorRegistrySupport
implements ConfigurablePropertyAccessor {
public abstract class AbstractPropertyAccessor extends TypeConverterSupport implements ConfigurablePropertyAccessor {

private boolean extractOldValueForEditor = false;

Expand Down Expand Up @@ -103,12 +102,8 @@ public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean
}
}

public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
return convertIfNecessary(value, requiredType, null);
}


// Redefined with public visibility.
// Redefined with public visibility.
@Override
public Class getPropertyType(String propertyPath) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.beans.PropertyChangeEvent;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
Expand Down Expand Up @@ -100,8 +101,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra

private Object rootObject;

private TypeConverterDelegate typeConverterDelegate;

/**
* The security context used for invoking the property methods
*/
Expand Down Expand Up @@ -445,25 +444,6 @@ public boolean isWritableProperty(String propertyName) {
return false;
}

public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
throws TypeMismatchException {
try {
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
}
catch (ConverterNotFoundException ex) {
throw new ConversionNotSupportedException(value, requiredType, ex);
}
catch (ConversionException ex) {
throw new TypeMismatchException(value, requiredType, ex);
}
catch (IllegalStateException ex) {
throw new ConversionNotSupportedException(value, requiredType, ex);
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchException(value, requiredType, ex);
}
}

private Object convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<?> requiredType,
TypeDescriptor td) throws TypeMismatchException {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,18 +16,18 @@

package org.springframework.beans;

import java.beans.PropertyChangeEvent;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import java.beans.PropertyChangeEvent;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
* {@link PropertyAccessor} implementation that directly accesses instance fields.
* Allows for direct binding to fields instead of going through JavaBean setters.
Expand All @@ -51,8 +51,6 @@ public class DirectFieldAccessor extends AbstractPropertyAccessor {

private final Map<String, Field> fieldMap = new HashMap<String, Field>();

private final TypeConverterDelegate typeConverterDelegate;


/**
* Create a new DirectFieldAccessor for the given target object.
Expand All @@ -65,7 +63,8 @@ public DirectFieldAccessor(final Object target) {
public void doWith(Field field) {
if (fieldMap.containsKey(field.getName())) {
// ignore superclass declarations of fields already found in a subclass
} else {
}
else {
fieldMap.put(field.getName(), field);
}
}
Expand Down Expand Up @@ -153,17 +152,4 @@ public void setPropertyValue(String propertyName, Object newValue) throws BeansE
}
}

public <T> T convertIfNecessary(
Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException {
try {
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchException(value, requiredType, ex);
}
catch (IllegalStateException ex) {
throw new ConversionNotSupportedException(value, requiredType, ex);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,50 +16,22 @@

package org.springframework.beans;

import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;

/**
* Simple implementation of the TypeConverter interface that does not operate
* on any specific target object. This is an alternative to using a full-blown
* BeanWrapperImpl instance for arbitrary type conversion needs.
* Simple implementation of the {@link TypeConverter} interface that does not operate on
* a specific target object. This is an alternative to using a full-blown BeanWrapperImpl
* instance for arbitrary type conversion needs, while using the very same conversion
* algorithm (including delegation to {@link java.beans.PropertyEditor} and
* {@link org.springframework.core.convert.ConversionService}) underneath.
*
* @author Juergen Hoeller
* @since 2.0
* @see BeanWrapperImpl
*/
public class SimpleTypeConverter extends PropertyEditorRegistrySupport implements TypeConverter {

private final TypeConverterDelegate typeConverterDelegate = new TypeConverterDelegate(this);

public class SimpleTypeConverter extends TypeConverterSupport {

public SimpleTypeConverter() {
this.typeConverterDelegate = new TypeConverterDelegate(this);
registerDefaultEditors();
}


public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
return convertIfNecessary(value, requiredType, null);
}

public <T> T convertIfNecessary(
Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException {
try {
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
}
catch (ConverterNotFoundException ex) {
throw new ConversionNotSupportedException(value, requiredType, ex);
}
catch (ConversionException ex) {
throw new TypeMismatchException(value, requiredType, ex);
}
catch (IllegalStateException ex) {
throw new ConversionNotSupportedException(value, requiredType, ex);
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchException(value, requiredType, ex);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,15 +16,16 @@

package org.springframework.beans;

import java.lang.reflect.Field;

import org.springframework.core.MethodParameter;

/**
* Interface that defines type conversion methods. Typically (but not necessarily)
* implemented in conjunction with the PropertyEditorRegistry interface.
* implemented in conjunction with the {@link PropertyEditorRegistry} interface.
*
* @author Juergen Hoeller
* @since 2.0
* @see PropertyEditorRegistry
* @see SimpleTypeConverter
* @see BeanWrapperImpl
*/
Expand All @@ -33,25 +34,23 @@ public interface TypeConverter {
/**
* Convert the value to the required type (if necessary from a String).
* <p>Conversions from String to any type will typically use the <code>setAsText</code>
* method of the PropertyEditor class. Note that a PropertyEditor must be registered
* for the given class for this to work; this is a standard JavaBeans API.
* A number of PropertyEditors are automatically registered.
* method of the PropertyEditor class, or a Spring Converter in a ConversionService.
* @param value the value to convert
* @param requiredType the type we must convert to
* (or <code>null</code> if not known, for example in case of a collection element)
* @return the new value, possibly the result of type conversion
* @throws TypeMismatchException if type conversion failed
* @see java.beans.PropertyEditor#setAsText(String)
* @see java.beans.PropertyEditor#getValue()
* @see org.springframework.core.convert.ConversionService
* @see org.springframework.core.convert.converter.Converter
*/
<T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;

/**
* Convert the value to the required type (if necessary from a String).
* <p>Conversions from String to any type will typically use the <code>setAsText</code>
* method of the PropertyEditor class. Note that a PropertyEditor must be registered
* for the given class for this to work; this is a standard JavaBeans API.
* A number of PropertyEditors are automatically registered.
* method of the PropertyEditor class, or a Spring Converter in a ConversionService.
* @param value the value to convert
* @param requiredType the type we must convert to
* (or <code>null</code> if not known, for example in case of a collection element)
Expand All @@ -61,8 +60,29 @@ public interface TypeConverter {
* @throws TypeMismatchException if type conversion failed
* @see java.beans.PropertyEditor#setAsText(String)
* @see java.beans.PropertyEditor#getValue()
* @see org.springframework.core.convert.ConversionService
* @see org.springframework.core.convert.converter.Converter
*/
<T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
throws TypeMismatchException;

/**
* Convert the value to the required type (if necessary from a String).
* <p>Conversions from String to any type will typically use the <code>setAsText</code>
* method of the PropertyEditor class, or a Spring Converter in a ConversionService.
* @param value the value to convert
* @param requiredType the type we must convert to
* (or <code>null</code> if not known, for example in case of a collection element)
* @param field the reflective field that is the target of the conversion
* (for analysis of generic types; may be <code>null</code>)
* @return the new value, possibly the result of type conversion
* @throws TypeMismatchException if type conversion failed
* @see java.beans.PropertyEditor#setAsText(String)
* @see java.beans.PropertyEditor#getValue()
* @see org.springframework.core.convert.ConversionService
* @see org.springframework.core.convert.converter.Converter
*/
<T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
throws TypeMismatchException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,23 @@ public <T> T convertIfNecessary(Object newValue, Class<T> requiredType, MethodPa
(methodParam != null ? new TypeDescriptor(methodParam) : TypeDescriptor.valueOf(requiredType)));
}

/**
* Convert the value to the specified required type.
* @param newValue the proposed new value
* @param requiredType the type we must convert to
* (or <code>null</code> if not known, for example in case of a collection element)
* @param field the reflective field that is the target of the conversion
* (may be <code>null</code>)
* @return the new value, possibly the result of type conversion
* @throws IllegalArgumentException if type conversion failed
*/
public <T> T convertIfNecessary(Object newValue, Class<T> requiredType, Field field)
throws IllegalArgumentException {

return convertIfNecessary(null, null, newValue, requiredType,
(field != null ? new TypeDescriptor(field) : TypeDescriptor.valueOf(requiredType)));
}

/**
* Convert the value to the required type for the specified property.
* @param propertyName name of the property
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.beans;

import java.lang.reflect.Field;

import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;

/**
* Base implementation of the {@link TypeConverter} interface, using a package-private delegate.
* Mainly serves as base class for {@link BeanWrapperImpl}.
*
* @author Juergen Hoeller
* @since 3.2
* @see SimpleTypeConverter
*/
public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter {

TypeConverterDelegate typeConverterDelegate;


public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
return doConvert(value, requiredType, null, null);
}

public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
throws TypeMismatchException {

return doConvert(value, requiredType, methodParam, null);
}

public <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
throws TypeMismatchException {

return doConvert(value, requiredType, null, field);
}

private <T> T doConvert(Object value, Class<T> requiredType, MethodParameter methodParam, Field field)
throws TypeMismatchException {
try {
if (field != null) {
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);
}
else {
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
}
}
catch (ConverterNotFoundException ex) {
throw new ConversionNotSupportedException(value, requiredType, ex);
}
catch (ConversionException ex) {
throw new TypeMismatchException(value, requiredType, ex);
}
catch (IllegalStateException ex) {
throw new ConversionNotSupportedException(value, requiredType, ex);
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchException(value, requiredType, ex);
}
}

}
Loading

0 comments on commit e904589

Please sign in to comment.