提交 6c66406f 编写于 作者: K Keith Donald

removed converter matcher since its not used directly

上级 08f9f8b8
......@@ -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);
}
\ No newline at end of file
/*
* 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);
} 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));
if (converter instanceof ConditionalGenericConverter) {
if (this.conditionalConverters == null) {
this.conditionalConverters = new LinkedList<ConditionalGenericConverter>();
}
this.conditionalConverters.add((ConditionalGenericConverter) 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;
}
}
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册