001/*
002 * Copyright 2002-2017 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;
018
019import java.lang.reflect.Field;
020import java.lang.reflect.Method;
021import java.util.Collection;
022import java.util.Map;
023
024/**
025 * Helper class for determining element types of collections and maps.
026 *
027 * <p>Mainly intended for usage within the framework, determining the
028 * target type of values to be added to a collection or map
029 * (to be able to attempt type conversion if appropriate).
030 *
031 * @author Juergen Hoeller
032 * @author Phillip Webb
033 * @since 2.0
034 * @see ResolvableType
035 * @deprecated as of 4.3.6, in favor of direct {@link ResolvableType} usage
036 */
037@Deprecated
038public abstract class GenericCollectionTypeResolver {
039
040        /**
041         * Determine the generic element type of the given Collection class
042         * (if it declares one through a generic superclass or generic interface).
043         * @param collectionClass the collection class to introspect
044         * @return the generic type, or {@code null} if none
045         */
046        @SuppressWarnings("rawtypes")
047        public static Class<?> getCollectionType(Class<? extends Collection> collectionClass) {
048                return ResolvableType.forClass(collectionClass).asCollection().resolveGeneric();
049        }
050
051        /**
052         * Determine the generic key type of the given Map class
053         * (if it declares one through a generic superclass or generic interface).
054         * @param mapClass the map class to introspect
055         * @return the generic type, or {@code null} if none
056         */
057        @SuppressWarnings("rawtypes")
058        public static Class<?> getMapKeyType(Class<? extends Map> mapClass) {
059                return ResolvableType.forClass(mapClass).asMap().resolveGeneric(0);
060        }
061
062        /**
063         * Determine the generic value type of the given Map class
064         * (if it declares one through a generic superclass or generic interface).
065         * @param mapClass the map class to introspect
066         * @return the generic type, or {@code null} if none
067         */
068        @SuppressWarnings("rawtypes")
069        public static Class<?> getMapValueType(Class<? extends Map> mapClass) {
070                return ResolvableType.forClass(mapClass).asMap().resolveGeneric(1);
071        }
072
073        /**
074         * Determine the generic element type of the given Collection field.
075         * @param collectionField the collection field to introspect
076         * @return the generic type, or {@code null} if none
077         */
078        public static Class<?> getCollectionFieldType(Field collectionField) {
079                return ResolvableType.forField(collectionField).asCollection().resolveGeneric();
080        }
081
082        /**
083         * Determine the generic element type of the given Collection field.
084         * @param collectionField the collection field to introspect
085         * @param nestingLevel the nesting level of the target type
086         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
087         * nested List, whereas 2 would indicate the element of the nested List)
088         * @return the generic type, or {@code null} if none
089         */
090        public static Class<?> getCollectionFieldType(Field collectionField, int nestingLevel) {
091                return ResolvableType.forField(collectionField).getNested(nestingLevel).asCollection().resolveGeneric();
092        }
093
094        /**
095         * Determine the generic element type of the given Collection field.
096         * @param collectionField the collection field to introspect
097         * @param nestingLevel the nesting level of the target type
098         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
099         * nested List, whereas 2 would indicate the element of the nested List)
100         * @param typeIndexesPerLevel Map keyed by nesting level, with each value
101         * expressing the type index for traversal at that level
102         * @return the generic type, or {@code null} if none
103         * @deprecated as of 4.0, in favor of using {@link ResolvableType} for arbitrary nesting levels
104         */
105        @Deprecated
106        public static Class<?> getCollectionFieldType(Field collectionField, int nestingLevel, Map<Integer, Integer> typeIndexesPerLevel) {
107                return ResolvableType.forField(collectionField).getNested(nestingLevel, typeIndexesPerLevel).asCollection().resolveGeneric();
108        }
109
110        /**
111         * Determine the generic key type of the given Map field.
112         * @param mapField the map field to introspect
113         * @return the generic type, or {@code null} if none
114         */
115        public static Class<?> getMapKeyFieldType(Field mapField) {
116                return ResolvableType.forField(mapField).asMap().resolveGeneric(0);
117        }
118
119        /**
120         * Determine the generic key type of the given Map field.
121         * @param mapField the map field to introspect
122         * @param nestingLevel the nesting level of the target type
123         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
124         * nested List, whereas 2 would indicate the element of the nested List)
125         * @return the generic type, or {@code null} if none
126         */
127        public static Class<?> getMapKeyFieldType(Field mapField, int nestingLevel) {
128                return ResolvableType.forField(mapField).getNested(nestingLevel).asMap().resolveGeneric(0);
129        }
130
131        /**
132         * Determine the generic key type of the given Map field.
133         * @param mapField the map field to introspect
134         * @param nestingLevel the nesting level of the target type
135         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
136         * nested List, whereas 2 would indicate the element of the nested List)
137         * @param typeIndexesPerLevel Map keyed by nesting level, with each value
138         * expressing the type index for traversal at that level
139         * @return the generic type, or {@code null} if none
140         * @deprecated as of 4.0, in favor of using {@link ResolvableType} for arbitrary nesting levels
141         */
142        @Deprecated
143        public static Class<?> getMapKeyFieldType(Field mapField, int nestingLevel, Map<Integer, Integer> typeIndexesPerLevel) {
144                return ResolvableType.forField(mapField).getNested(nestingLevel, typeIndexesPerLevel).asMap().resolveGeneric(0);
145        }
146
147        /**
148         * Determine the generic value type of the given Map field.
149         * @param mapField the map field to introspect
150         * @return the generic type, or {@code null} if none
151         */
152        public static Class<?> getMapValueFieldType(Field mapField) {
153                return ResolvableType.forField(mapField).asMap().resolveGeneric(1);
154        }
155
156        /**
157         * Determine the generic value type of the given Map field.
158         * @param mapField the map field to introspect
159         * @param nestingLevel the nesting level of the target type
160         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
161         * nested List, whereas 2 would indicate the element of the nested List)
162         * @return the generic type, or {@code null} if none
163         */
164        public static Class<?> getMapValueFieldType(Field mapField, int nestingLevel) {
165                return ResolvableType.forField(mapField).getNested(nestingLevel).asMap().resolveGeneric(1);
166        }
167
168        /**
169         * Determine the generic value type of the given Map field.
170         * @param mapField the map field to introspect
171         * @param nestingLevel the nesting level of the target type
172         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
173         * nested List, whereas 2 would indicate the element of the nested List)
174         * @param typeIndexesPerLevel Map keyed by nesting level, with each value
175         * expressing the type index for traversal at that level
176         * @return the generic type, or {@code null} if none
177         * @deprecated as of 4.0, in favor of using {@link ResolvableType} for arbitrary nesting levels
178         */
179        @Deprecated
180        public static Class<?> getMapValueFieldType(Field mapField, int nestingLevel, Map<Integer, Integer> typeIndexesPerLevel) {
181                return ResolvableType.forField(mapField).getNested(nestingLevel, typeIndexesPerLevel).asMap().resolveGeneric(1);
182        }
183
184        /**
185         * Determine the generic element type of the given Collection parameter.
186         * @param methodParam the method parameter specification
187         * @return the generic type, or {@code null} if none
188         */
189        public static Class<?> getCollectionParameterType(MethodParameter methodParam) {
190                return ResolvableType.forMethodParameter(methodParam).asCollection().resolveGeneric();
191        }
192
193        /**
194         * Determine the generic key type of the given Map parameter.
195         * @param methodParam the method parameter specification
196         * @return the generic type, or {@code null} if none
197         */
198        public static Class<?> getMapKeyParameterType(MethodParameter methodParam) {
199                return ResolvableType.forMethodParameter(methodParam).asMap().resolveGeneric(0);
200        }
201
202        /**
203         * Determine the generic value type of the given Map parameter.
204         * @param methodParam the method parameter specification
205         * @return the generic type, or {@code null} if none
206         */
207        public static Class<?> getMapValueParameterType(MethodParameter methodParam) {
208                return ResolvableType.forMethodParameter(methodParam).asMap().resolveGeneric(1);
209        }
210
211        /**
212         * Determine the generic element type of the given Collection return type.
213         * @param method the method to check the return type for
214         * @return the generic type, or {@code null} if none
215         */
216        public static Class<?> getCollectionReturnType(Method method) {
217                return ResolvableType.forMethodReturnType(method).asCollection().resolveGeneric();
218        }
219
220        /**
221         * Determine the generic element type of the given Collection return type.
222         * <p>If the specified nesting level is higher than 1, the element type of
223         * a nested Collection/Map will be analyzed.
224         * @param method the method to check the return type for
225         * @param nestingLevel the nesting level of the target type
226         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
227         * nested List, whereas 2 would indicate the element of the nested List)
228         * @return the generic type, or {@code null} if none
229         */
230        public static Class<?> getCollectionReturnType(Method method, int nestingLevel) {
231                return ResolvableType.forMethodReturnType(method).getNested(nestingLevel).asCollection().resolveGeneric();
232        }
233
234        /**
235         * Determine the generic key type of the given Map return type.
236         * @param method the method to check the return type for
237         * @return the generic type, or {@code null} if none
238         */
239        public static Class<?> getMapKeyReturnType(Method method) {
240                return ResolvableType.forMethodReturnType(method).asMap().resolveGeneric(0);
241        }
242
243        /**
244         * Determine the generic key type of the given Map return type.
245         * @param method the method to check the return type for
246         * @param nestingLevel the nesting level of the target type
247         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
248         * nested List, whereas 2 would indicate the element of the nested List)
249         * @return the generic type, or {@code null} if none
250         */
251        public static Class<?> getMapKeyReturnType(Method method, int nestingLevel) {
252                return ResolvableType.forMethodReturnType(method).getNested(nestingLevel).asMap().resolveGeneric(0);
253        }
254
255        /**
256         * Determine the generic value type of the given Map return type.
257         * @param method the method to check the return type for
258         * @return the generic type, or {@code null} if none
259         */
260        public static Class<?> getMapValueReturnType(Method method) {
261                return ResolvableType.forMethodReturnType(method).asMap().resolveGeneric(1);
262        }
263
264        /**
265         * Determine the generic value type of the given Map return type.
266         * @param method the method to check the return type for
267         * @param nestingLevel the nesting level of the target type
268         * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
269         * nested List, whereas 2 would indicate the element of the nested List)
270         * @return the generic type, or {@code null} if none
271         */
272        public static Class<?> getMapValueReturnType(Method method, int nestingLevel) {
273                return ResolvableType.forMethodReturnType(method).getNested(nestingLevel).asMap().resolveGeneric(1);
274        }
275
276}