removed converter matcher since its not used directly
This commit is contained in:
@@ -15,14 +15,25 @@
|
||||
*/
|
||||
package org.springframework.core.convert.converter;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* A generic converter that, as a ConverterMatcher, conditionally executes.
|
||||
* Often used when selectively matching custom conversion logic based on the presence of a field or class-level annotation.
|
||||
* For example, when converting from a String to a Date field, an implementation might return true if the target field has also been annotated with <code>@DateTimeFormat</code>.
|
||||
* A generic converter that conditionally executes.
|
||||
* Applies a rule that determines if a converter between a set of {@link #getConvertibleTypes() convertible types} matches given a client request to convert between a source field of convertible type S and a target field of convertible type T.
|
||||
* Often used to selectively match custom conversion logic based on the presence of a field or class-level characteristic, such as an annotation or method.
|
||||
* For example, when converting from a String field to a Date field, an implementation might return true if the target field has also been annotated with <code>@DateTimeFormat</code>.
|
||||
* As another example, when converting from a String field to an Account field, an implementation might return true if the target Account class defines a public static findAccount(String) method.
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface ConditionalGenericConverter extends GenericConverter, ConverterMatcher {
|
||||
public interface ConditionalGenericConverter extends GenericConverter {
|
||||
|
||||
/**
|
||||
* Should the Converter from <code>sourceType</code> to <code>targetType</code> currently under consideration be selected?
|
||||
* @param sourceType the type descriptor of the field we are converting from
|
||||
* @param targetType the type descriptor of the field we are converting to
|
||||
* @return true if conversion should be performed, false otherwise
|
||||
*/
|
||||
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||
|
||||
}
|
||||
@@ -1,37 +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.converter;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* A rule that determines if a particular Converter of S to T matches given a request to convert between a field of type S and a field of type T.
|
||||
* Often used to selectively apply custom type conversion logic based on the presence of a field annotation.
|
||||
* For example, when converting from a String to a Date field, an implementation might return true only if the target Date field has also been annotated with <code>@DateTimeFormat</code>.
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
* TODO - consider collapsing into ConditionalGenericConverter
|
||||
*/
|
||||
public interface ConverterMatcher {
|
||||
|
||||
/**
|
||||
* Should the Converter from <code>sourceType</code> to <code>targetType</code> currently under consideration be selected?
|
||||
* @param sourceType the type descriptor of the field we are converting from
|
||||
* @param targetType the type descriptor of the field we are converting to
|
||||
* @return true if conversion should be performed, false otherwise
|
||||
*/
|
||||
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||
}
|
||||
@@ -17,35 +17,37 @@
|
||||
package org.springframework.core.convert.converter;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
|
||||
/**
|
||||
* Uniform converter interface as returned from {@link GenericConversionService#getConverter}.
|
||||
*
|
||||
* <p>This interface is primarily an internal detail of the {@link GenericConversionService}
|
||||
* implementation. It should generally not be implemented by application code directly.
|
||||
* See {@link Converter} and {@link ConverterFactory} interfaces for simpler public converter SPIs.
|
||||
* Generic converter interface for converting between two or more types.
|
||||
* <p>
|
||||
* This is the most flexible of the Converter SPI interfaces, but also the most complex.
|
||||
* It is flexible in that a GenericConverter may support converting between multiple source/target type pairs (see {@link #getConvertibleTypes()}.
|
||||
* In addition, GenericConverter implementations have access to source/target {@link TypeDescriptor field context} during the type conversion process.
|
||||
* This allows for resolving source and target field metadata such as annotations and generics information, which can be used influence the conversion logic.
|
||||
* <p>
|
||||
* This interface should generally not be used when the simpler {@link Converter} or {@link ConverterFactory} interfaces are sufficient.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
* @see TypeDescriptor
|
||||
* @see Converter
|
||||
* @see ConverterFactory
|
||||
* @see GenericConversionService
|
||||
*/
|
||||
public interface GenericConverter {
|
||||
|
||||
/**
|
||||
* The source and target types this converter can convert between.
|
||||
* Each entry in the returned array is a two-element array where the first element is a sourceType that can be converted from,
|
||||
* and the second element is a targetType that can be converted to.
|
||||
* Each entry in the returned array is a convertible source-to-target type pair, also expressed as an array.
|
||||
* For each pair, the first array element is a sourceType that can be converted from, and the second array element is a targetType that can be converted to.
|
||||
*/
|
||||
public Class<?>[][] getConvertibleTypes();
|
||||
|
||||
/**
|
||||
* Convert the source to the targetType described by the TypeDescriptor.
|
||||
* @param source the source object to convert (may be null)
|
||||
* @param sourceType context about the source type to convert from
|
||||
* @param targetType context about the target type to convert to
|
||||
* @param sourceType the type descriptor of the field we are converting from
|
||||
* @param targetType the type descriptor of the field we are converting to
|
||||
* @return the converted object
|
||||
*/
|
||||
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||
|
||||
@@ -31,9 +31,9 @@ import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConverterFactory;
|
||||
import org.springframework.core.convert.converter.ConverterMatcher;
|
||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -48,18 +48,19 @@ import org.springframework.util.ClassUtils;
|
||||
public class GenericConversionService implements ConversionService, ConverterRegistry {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(GenericConversionService.class);
|
||||
|
||||
|
||||
private static final GenericConverter NO_OP_CONVERTER = new GenericConverter() {
|
||||
public Class<?>[][] getConvertibleTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return source;
|
||||
}
|
||||
};
|
||||
|
||||
private final Map<Class<?>, Map<Class<?>, MatchableConverters>> converters = new HashMap<Class<?>, Map<Class<?>, MatchableConverters>>(36);
|
||||
private final Map<Class<?>, Map<Class<?>, MatchableConverters>> converters = new HashMap<Class<?>, Map<Class<?>, MatchableConverters>>(
|
||||
36);
|
||||
|
||||
// implementing ConverterRegistry
|
||||
|
||||
@@ -84,10 +85,10 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||
public void addGenericConverter(GenericConverter converter) {
|
||||
Class<?>[][] convertibleTypes = converter.getConvertibleTypes();
|
||||
for (Class<?>[] convertibleType : convertibleTypes) {
|
||||
getMatchableConvertersList(convertibleType[0], convertibleType[1]).add(converter);
|
||||
getMatchableConvertersList(convertibleType[0], convertibleType[1]).add(converter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
|
||||
getSourceConverterMap(sourceType).remove(targetType);
|
||||
}
|
||||
@@ -284,7 +285,8 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||
return converters;
|
||||
}
|
||||
|
||||
private GenericConverter getMatchingConverterForTarget(TypeDescriptor sourceType, TypeDescriptor targetType, Map<Class<?>, MatchableConverters> converters) {
|
||||
private GenericConverter getMatchingConverterForTarget(TypeDescriptor sourceType, TypeDescriptor targetType,
|
||||
Map<Class<?>, MatchableConverters> converters) {
|
||||
Class<?> targetObjectType = targetType.getObjectType();
|
||||
if (targetObjectType.isInterface()) {
|
||||
LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();
|
||||
@@ -340,14 +342,14 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||
private final class ConverterAdapter implements GenericConverter {
|
||||
|
||||
private final Class<?>[] typeInfo;
|
||||
|
||||
|
||||
private final Converter converter;
|
||||
|
||||
public ConverterAdapter(Class<?>[] typeInfo, Converter<?, ?> converter) {
|
||||
this.converter = converter;
|
||||
this.typeInfo = typeInfo;
|
||||
}
|
||||
|
||||
|
||||
public Class<?>[][] getConvertibleTypes() {
|
||||
return new Class[][] { this.typeInfo };
|
||||
}
|
||||
@@ -360,7 +362,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.converter.toString();
|
||||
return this.typeInfo[0].getName() + " -> " + this.typeInfo[1].getName() + " : " + this.converter.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,13 +375,13 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||
|
||||
public ConverterFactoryAdapter(Class<?>[] typeInfo, ConverterFactory<?, ?> converterFactory) {
|
||||
this.converterFactory = converterFactory;
|
||||
this.typeInfo = typeInfo;
|
||||
this.typeInfo = typeInfo;
|
||||
}
|
||||
|
||||
public Class<?>[][] getConvertibleTypes() {
|
||||
return new Class[][] { this.typeInfo };
|
||||
}
|
||||
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
return convertNullSource(sourceType, targetType);
|
||||
@@ -388,102 +390,57 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.converterFactory.toString();
|
||||
return this.typeInfo[0].getName() + " -> " + this.typeInfo[1].getName() + " : " + this.converterFactory.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MatchableConverters {
|
||||
|
||||
private static final ConverterMatcher ALWAYS_MATCHES = new ConverterMatcher() {
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
private LinkedList<ConditionalGenericConverter> conditionalConverters;
|
||||
|
||||
private LinkedList<MatchableConverter> matchableConverters = new LinkedList<MatchableConverter>();
|
||||
private GenericConverter defaultConverter;
|
||||
|
||||
public void add(GenericConverter converter) {
|
||||
if (converter instanceof ConverterMatcher) {
|
||||
add((ConverterMatcher) converter, converter);
|
||||
if (converter instanceof ConditionalGenericConverter) {
|
||||
if (this.conditionalConverters == null) {
|
||||
this.conditionalConverters = new LinkedList<ConditionalGenericConverter>();
|
||||
}
|
||||
this.conditionalConverters.add((ConditionalGenericConverter) converter);
|
||||
} else {
|
||||
add(ALWAYS_MATCHES, converter);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(ConverterMatcher matcher, GenericConverter converter) {
|
||||
MatchableConverter matchable = new MatchableConverter(matcher, converter);
|
||||
int index = this.matchableConverters.indexOf(matchable);
|
||||
if (index == -1) {
|
||||
this.matchableConverters.addFirst(new MatchableConverter(matcher, converter));
|
||||
} else {
|
||||
this.matchableConverters.set(index, matchable);
|
||||
this.defaultConverter = converter;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericConverter matchConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
for (MatchableConverter matchable : this.matchableConverters) {
|
||||
if (matchable.matches(sourceType, targetType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converter Lookup [MATCHED] " + matchable);
|
||||
if (this.conditionalConverters != null) {
|
||||
for (ConditionalGenericConverter conditional : this.conditionalConverters) {
|
||||
if (conditional.matches(sourceType, targetType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converter Lookup [MATCHED] " + conditional);
|
||||
}
|
||||
return conditional;
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converter Lookup [DID NOT MATCH] " + conditional);
|
||||
}
|
||||
}
|
||||
return matchable.getConverter();
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converter Lookup [DID NOT MATCH] " + matchable);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converter Lookup [MATCHED] " + this.defaultConverter);
|
||||
}
|
||||
return this.defaultConverter;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (this.matchableConverters.size() == 1) {
|
||||
return this.matchableConverters.get(0).toString();
|
||||
if (this.conditionalConverters != null) {
|
||||
return "[" + this.conditionalConverters + "; default = " + this.defaultConverter + "]";
|
||||
} else {
|
||||
return "[MatchableConverters = " + this.matchableConverters + "]";
|
||||
return this.defaultConverter.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MatchableConverter {
|
||||
|
||||
private ConverterMatcher matcher;
|
||||
|
||||
private GenericConverter converter;
|
||||
|
||||
public MatchableConverter(ConverterMatcher matcher, GenericConverter converter) {
|
||||
this.matcher = matcher;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public GenericConverter getConverter() {
|
||||
return this.converter;
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.matcher.matches(sourceType, targetType);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.matcher.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof MatchableConverter)) {
|
||||
return false;
|
||||
}
|
||||
MatchableConverter matchable = (MatchableConverter) o;
|
||||
return this.matcher.equals(matchable.matcher);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (matcher == ALWAYS_MATCHES || matcher == converter) {
|
||||
return this.converter.toString();
|
||||
} else {
|
||||
return "if (" + this.matcher + ") " + this.converter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user