001/*
002 * Copyright 2002-2015 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.core.convert.converter;
018
019import java.util.Set;
020
021import org.springframework.core.convert.TypeDescriptor;
022import org.springframework.util.Assert;
023
024/**
025 * Generic converter interface for converting between two or more types.
026 *
027 * <p>This is the most flexible of the Converter SPI interfaces, but also the most complex.
028 * It is flexible in that a GenericConverter may support converting between multiple source/target
029 * type pairs (see {@link #getConvertibleTypes()}. In addition, GenericConverter implementations
030 * have access to source/target {@link TypeDescriptor field context} during the type conversion
031 * process. This allows for resolving source and target field metadata such as annotations and
032 * generics information, which can be used to influence the conversion logic.
033 *
034 * <p>This interface should generally not be used when the simpler {@link Converter} or
035 * {@link ConverterFactory} interface is sufficient.
036 *
037 * <p>Implementations may additionally implement {@link ConditionalConverter}.
038 *
039 * @author Keith Donald
040 * @author Juergen Hoeller
041 * @since 3.0
042 * @see TypeDescriptor
043 * @see Converter
044 * @see ConverterFactory
045 * @see ConditionalConverter
046 */
047public interface GenericConverter {
048
049        /**
050         * Return the source and target types that this converter can convert between.
051         * <p>Each entry is a convertible source-to-target type pair.
052         * <p>For {@link ConditionalConverter conditional converters} this method may return
053         * {@code null} to indicate all source-to-target pairs should be considered.
054         */
055        Set<ConvertiblePair> getConvertibleTypes();
056
057        /**
058         * Convert the source object to the targetType described by the {@code TypeDescriptor}.
059         * @param source the source object to convert (may be {@code null})
060         * @param sourceType the type descriptor of the field we are converting from
061         * @param targetType the type descriptor of the field we are converting to
062         * @return the converted object
063         */
064        Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
065
066
067        /**
068         * Holder for a source-to-target class pair.
069         */
070        final class ConvertiblePair {
071
072                private final Class<?> sourceType;
073
074                private final Class<?> targetType;
075
076                /**
077                 * Create a new source-to-target pair.
078                 * @param sourceType the source type
079                 * @param targetType the target type
080                 */
081                public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
082                        Assert.notNull(sourceType, "Source type must not be null");
083                        Assert.notNull(targetType, "Target type must not be null");
084                        this.sourceType = sourceType;
085                        this.targetType = targetType;
086                }
087
088                public Class<?> getSourceType() {
089                        return this.sourceType;
090                }
091
092                public Class<?> getTargetType() {
093                        return this.targetType;
094                }
095
096                @Override
097                public boolean equals(Object other) {
098                        if (this == other) {
099                                return true;
100                        }
101                        if (other == null || other.getClass() != ConvertiblePair.class) {
102                                return false;
103                        }
104                        ConvertiblePair otherPair = (ConvertiblePair) other;
105                        return (this.sourceType == otherPair.sourceType && this.targetType == otherPair.targetType);
106                }
107
108                @Override
109                public int hashCode() {
110                        return (this.sourceType.hashCode() * 31 + this.targetType.hashCode());
111                }
112
113                @Override
114                public String toString() {
115                        return (this.sourceType.getName() + " -> " + this.targetType.getName());
116                }
117        }
118
119}