• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.apache.velocity.util.introspection;
2 
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21 
22 import org.apache.commons.lang3.LocaleUtils;
23 import org.apache.commons.lang3.reflect.TypeUtils;
24 import org.apache.commons.lang3.tuple.Pair;
25 
26 import java.lang.reflect.Type;
27 import java.math.BigDecimal;
28 import java.math.BigInteger;
29 import java.util.HashMap;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.Optional;
33 import java.util.concurrent.ConcurrentHashMap;
34 
35 /**
36  * A conversion handler adds admissible conversions between Java types whenever Velocity introspection has to map
37  * VTL methods and property accessors to Java methods. This implementation is the default Conversion Handler
38  * for Velocity.
39  *
40  * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
41  * @version $Id: TypeConversionHandlerImpl.java $
42  * @since 2.0
43  */
44 
45 public class TypeConversionHandlerImpl implements TypeConversionHandler
46 {
47     /**
48      * standard narrowing and string parsing conversions.
49      */
50     static Map<Pair<String, String>, Converter<?>> standardConverterMap;
51 
52     /**
53      * basic toString converter
54      */
55     static Converter<?> toString;
56 
57     /**
58      * cache miss converter
59      */
60     static Converter<?> cacheMiss;
61 
62     /**
63      * a converters cache map, initialized with the standard narrowing and string parsing conversions.
64      */
65     Map<Pair<String, String>, Converter<?>> converterCacheMap;
66 
67     static final String BOOLEAN_TYPE = "boolean";
68     static final String BYTE_TYPE = "byte";
69     static final String SHORT_TYPE = "short";
70     static final String INTEGER_TYPE = "int";
71     static final String LONG_TYPE = "long";
72     static final String FLOAT_TYPE = "float";
73     static final String DOUBLE_TYPE = "double";
74     static final String CHARACTER_TYPE = "char";
75     static final String BOOLEAN_CLASS = "java.lang.Boolean";
76     static final String BYTE_CLASS = "java.lang.Byte";
77     static final String SHORT_CLASS = "java.lang.Short";
78     static final String INTEGER_CLASS = "java.lang.Integer";
79     static final String LONG_CLASS = "java.lang.Long";
80     static final String BIG_INTEGER_CLASS = "java.math.BigInteger";
81     static final String FLOAT_CLASS = "java.lang.Float";
82     static final String DOUBLE_CLASS = "java.lang.Double";
83     static final String BIG_DECIMAL_CLASS = "java.math.BigDecimal";
84     static final String NUMBER_CLASS = "java.lang.Number";
85     static final String CHARACTER_CLASS = "java.lang.Character";
86     static final String STRING_CLASS = "java.lang.String";
87     static final String LOCALE_CLASS = "java.util.Locale";
88 
89     /*
90      * Bounds checking helper
91      */
92 
checkBounds(Number n, double min, double max)93     static boolean checkBounds(Number n, double min, double max)
94     {
95         double d = n.doubleValue();
96         if (d < min || d > max)
97         {
98             throw new NumberFormatException("value out of range: " + n);
99         }
100         return true;
101     }
102 
103     static
104     {
105         standardConverterMap = new HashMap<>();
106 
107         cacheMiss = o -> o;
108 
109         /*
110          * Conversions towards boolean
111          */
112 
113         /* number -> boolean */
114 
115         Converter<Boolean> numberToBool = o -> Optional.ofNullable((Number)o).map(n -> Double.compare(n.doubleValue(), 0.0) != 0).orElse(null);
116         Converter<Boolean> bigIntegerToBool = o -> Optional.ofNullable((BigInteger)o).map(bi -> bi.signum() != 0).orElse(null);
117         Converter<Boolean> bigDecimalToBool = o -> Optional.ofNullable((BigDecimal)o).map(bi -> bi.signum() != 0).orElse(null);
118 
Pair.of(BOOLEAN_CLASS, BYTE_CLASS)119         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, BYTE_CLASS), numberToBool);
Pair.of(BOOLEAN_CLASS, SHORT_CLASS)120         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, SHORT_CLASS), numberToBool);
Pair.of(BOOLEAN_CLASS, INTEGER_CLASS)121         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, INTEGER_CLASS), numberToBool);
Pair.of(BOOLEAN_CLASS, LONG_CLASS)122         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, LONG_CLASS), numberToBool);
Pair.of(BOOLEAN_CLASS, BIG_INTEGER_CLASS)123         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, BIG_INTEGER_CLASS), bigIntegerToBool);
Pair.of(BOOLEAN_CLASS, FLOAT_CLASS)124         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, FLOAT_CLASS), numberToBool);
Pair.of(BOOLEAN_CLASS, DOUBLE_CLASS)125         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, DOUBLE_CLASS), numberToBool);
Pair.of(BOOLEAN_CLASS, BIG_DECIMAL_CLASS)126         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, BIG_DECIMAL_CLASS), bigDecimalToBool);
Pair.of(BOOLEAN_CLASS, NUMBER_CLASS)127         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, NUMBER_CLASS), numberToBool);
Pair.of(BOOLEAN_CLASS, BYTE_TYPE)128         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, BYTE_TYPE), numberToBool);
Pair.of(BOOLEAN_CLASS, SHORT_TYPE)129         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, SHORT_TYPE), numberToBool);
Pair.of(BOOLEAN_CLASS, INTEGER_TYPE)130         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, INTEGER_TYPE), numberToBool);
Pair.of(BOOLEAN_CLASS, LONG_TYPE)131         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, LONG_TYPE), numberToBool);
Pair.of(BOOLEAN_CLASS, FLOAT_TYPE)132         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, FLOAT_TYPE), numberToBool);
Pair.of(BOOLEAN_CLASS, DOUBLE_TYPE)133         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, DOUBLE_TYPE), numberToBool);
Pair.of(BOOLEAN_TYPE, BYTE_CLASS)134         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, BYTE_CLASS), numberToBool);
Pair.of(BOOLEAN_TYPE, SHORT_CLASS)135         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, SHORT_CLASS), numberToBool);
Pair.of(BOOLEAN_TYPE, INTEGER_CLASS)136         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, INTEGER_CLASS), numberToBool);
Pair.of(BOOLEAN_TYPE, BIG_INTEGER_CLASS)137         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, BIG_INTEGER_CLASS), bigIntegerToBool);
Pair.of(BOOLEAN_TYPE, LONG_CLASS)138         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, LONG_CLASS), numberToBool);
Pair.of(BOOLEAN_TYPE, FLOAT_CLASS)139         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, FLOAT_CLASS), numberToBool);
Pair.of(BOOLEAN_TYPE, DOUBLE_CLASS)140         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, DOUBLE_CLASS), numberToBool);
Pair.of(BOOLEAN_TYPE, BIG_DECIMAL_CLASS)141         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, BIG_DECIMAL_CLASS), bigDecimalToBool);
Pair.of(BOOLEAN_TYPE, NUMBER_CLASS)142         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, NUMBER_CLASS), numberToBool);
Pair.of(BOOLEAN_TYPE, BYTE_TYPE)143         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, BYTE_TYPE), numberToBool);
Pair.of(BOOLEAN_TYPE, SHORT_TYPE)144         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, SHORT_TYPE), numberToBool);
Pair.of(BOOLEAN_TYPE, INTEGER_TYPE)145         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, INTEGER_TYPE), numberToBool);
Pair.of(BOOLEAN_TYPE, LONG_TYPE)146         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, LONG_TYPE), numberToBool);
Pair.of(BOOLEAN_TYPE, FLOAT_TYPE)147         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, FLOAT_TYPE), numberToBool);
Pair.of(BOOLEAN_TYPE, DOUBLE_TYPE)148         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, DOUBLE_TYPE), numberToBool);
149 
150         /* character -> boolean */
151 
152         Converter<Boolean> charToBoolean = o -> Optional.ofNullable((Character)o).map(c -> c != 0).orElse(null);
153 
Pair.of(BOOLEAN_CLASS, CHARACTER_CLASS)154         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, CHARACTER_CLASS), charToBoolean);
Pair.of(BOOLEAN_CLASS, CHARACTER_TYPE)155         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, CHARACTER_TYPE), charToBoolean);
Pair.of(BOOLEAN_TYPE, CHARACTER_CLASS)156         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, CHARACTER_CLASS), charToBoolean);
Pair.of(BOOLEAN_TYPE, CHARACTER_TYPE)157         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, CHARACTER_TYPE), charToBoolean);
158 
159         /* string -> boolean */
160 
161         Converter<Boolean> stringToBoolean = o -> Boolean.valueOf(String.valueOf(o));
162 
Pair.of(BOOLEAN_CLASS, STRING_CLASS)163         standardConverterMap.put(Pair.of(BOOLEAN_CLASS, STRING_CLASS), stringToBoolean);
Pair.of(BOOLEAN_TYPE, STRING_CLASS)164         standardConverterMap.put(Pair.of(BOOLEAN_TYPE, STRING_CLASS), stringToBoolean);
165 
166         /*
167          * Conversions towards byte
168          */
169 
170         /* narrowing towards byte */
171 
172         Converter<Byte> narrowingToByte = o -> Optional.ofNullable((Number)o)
173             .filter(n -> checkBounds(n, Byte.MIN_VALUE, Byte.MAX_VALUE))
174             .map(Number::byteValue)
175             .orElse(null);
176 
177         Converter<Byte> narrowingBigIntegerToByte = o -> Optional.ofNullable((BigInteger)o)
178             .map(BigInteger::byteValueExact)
179             .orElse(null);
180 
181         Converter<Byte> narrowingBigDecimalToByte = o -> Optional.ofNullable((BigDecimal)o)
182             .map(BigDecimal::byteValueExact)
183             .orElse(null);
184 
Pair.of(BYTE_CLASS, SHORT_CLASS)185         standardConverterMap.put(Pair.of(BYTE_CLASS, SHORT_CLASS), narrowingToByte);
Pair.of(BYTE_CLASS, INTEGER_CLASS)186         standardConverterMap.put(Pair.of(BYTE_CLASS, INTEGER_CLASS), narrowingToByte);
Pair.of(BYTE_CLASS, LONG_CLASS)187         standardConverterMap.put(Pair.of(BYTE_CLASS, LONG_CLASS), narrowingToByte);
Pair.of(BYTE_CLASS, BIG_INTEGER_CLASS)188         standardConverterMap.put(Pair.of(BYTE_CLASS, BIG_INTEGER_CLASS), narrowingBigIntegerToByte);
Pair.of(BYTE_CLASS, FLOAT_CLASS)189         standardConverterMap.put(Pair.of(BYTE_CLASS, FLOAT_CLASS), narrowingToByte);
Pair.of(BYTE_CLASS, DOUBLE_CLASS)190         standardConverterMap.put(Pair.of(BYTE_CLASS, DOUBLE_CLASS), narrowingToByte);
Pair.of(BYTE_CLASS, BIG_DECIMAL_CLASS)191         standardConverterMap.put(Pair.of(BYTE_CLASS, BIG_DECIMAL_CLASS), narrowingBigDecimalToByte);
Pair.of(BYTE_CLASS, NUMBER_CLASS)192         standardConverterMap.put(Pair.of(BYTE_CLASS, NUMBER_CLASS), narrowingToByte);
Pair.of(BYTE_CLASS, SHORT_TYPE)193         standardConverterMap.put(Pair.of(BYTE_CLASS, SHORT_TYPE), narrowingToByte);
Pair.of(BYTE_CLASS, INTEGER_TYPE)194         standardConverterMap.put(Pair.of(BYTE_CLASS, INTEGER_TYPE), narrowingToByte);
Pair.of(BYTE_CLASS, LONG_TYPE)195         standardConverterMap.put(Pair.of(BYTE_CLASS, LONG_TYPE), narrowingToByte);
Pair.of(BYTE_CLASS, FLOAT_TYPE)196         standardConverterMap.put(Pair.of(BYTE_CLASS, FLOAT_TYPE), narrowingToByte);
Pair.of(BYTE_CLASS, DOUBLE_TYPE)197         standardConverterMap.put(Pair.of(BYTE_CLASS, DOUBLE_TYPE), narrowingToByte);
Pair.of(BYTE_TYPE, SHORT_CLASS)198         standardConverterMap.put(Pair.of(BYTE_TYPE, SHORT_CLASS), narrowingToByte);
Pair.of(BYTE_TYPE, INTEGER_CLASS)199         standardConverterMap.put(Pair.of(BYTE_TYPE, INTEGER_CLASS), narrowingToByte);
Pair.of(BYTE_TYPE, LONG_CLASS)200         standardConverterMap.put(Pair.of(BYTE_TYPE, LONG_CLASS), narrowingToByte);
Pair.of(BYTE_TYPE, BIG_INTEGER_CLASS)201         standardConverterMap.put(Pair.of(BYTE_TYPE, BIG_INTEGER_CLASS), narrowingBigIntegerToByte);
Pair.of(BYTE_TYPE, FLOAT_CLASS)202         standardConverterMap.put(Pair.of(BYTE_TYPE, FLOAT_CLASS), narrowingToByte);
Pair.of(BYTE_TYPE, DOUBLE_CLASS)203         standardConverterMap.put(Pair.of(BYTE_TYPE, DOUBLE_CLASS), narrowingToByte);
Pair.of(BYTE_TYPE, BIG_DECIMAL_CLASS)204         standardConverterMap.put(Pair.of(BYTE_TYPE, BIG_DECIMAL_CLASS), narrowingBigDecimalToByte);
Pair.of(BYTE_TYPE, NUMBER_CLASS)205         standardConverterMap.put(Pair.of(BYTE_TYPE, NUMBER_CLASS), narrowingToByte);
Pair.of(BYTE_TYPE, SHORT_TYPE)206         standardConverterMap.put(Pair.of(BYTE_TYPE, SHORT_TYPE), narrowingToByte);
Pair.of(BYTE_TYPE, INTEGER_TYPE)207         standardConverterMap.put(Pair.of(BYTE_TYPE, INTEGER_TYPE), narrowingToByte);
Pair.of(BYTE_TYPE, LONG_TYPE)208         standardConverterMap.put(Pair.of(BYTE_TYPE, LONG_TYPE), narrowingToByte);
Pair.of(BYTE_TYPE, FLOAT_TYPE)209         standardConverterMap.put(Pair.of(BYTE_TYPE, FLOAT_TYPE), narrowingToByte);
Pair.of(BYTE_TYPE, DOUBLE_TYPE)210         standardConverterMap.put(Pair.of(BYTE_TYPE, DOUBLE_TYPE), narrowingToByte);
211 
212         /* string to byte */
213 
214         Converter<Byte> stringToByte = o -> Byte.valueOf(String.valueOf(o));
215 
Pair.of(BYTE_CLASS, STRING_CLASS)216         standardConverterMap.put(Pair.of(BYTE_CLASS, STRING_CLASS), stringToByte);
Pair.of(BYTE_TYPE, STRING_CLASS)217         standardConverterMap.put(Pair.of(BYTE_TYPE, STRING_CLASS), stringToByte);
218 
219         /*
220          * Conversions towards short
221          */
222 
223         /* narrowing towards short */
224 
225         Converter<Short> narrowingToShort = o -> Optional.ofNullable((Number)o)
226             .filter(n -> checkBounds(n, Short.MIN_VALUE, Short.MAX_VALUE))
227             .map(Number::shortValue)
228             .orElse(null);
229 
230         Converter<Short> narrowingBigIntegerToShort = o -> Optional.ofNullable((BigInteger)o)
231             .map(BigInteger::shortValueExact)
232             .orElse(null);
233 
234         Converter<Short> narrowingBigDecimalToShort = o -> Optional.ofNullable((BigDecimal)o)
235             .map(BigDecimal::shortValueExact)
236             .orElse(null);
237 
Pair.of(SHORT_CLASS, INTEGER_CLASS)238         standardConverterMap.put(Pair.of(SHORT_CLASS, INTEGER_CLASS), narrowingToShort);
Pair.of(SHORT_CLASS, LONG_CLASS)239         standardConverterMap.put(Pair.of(SHORT_CLASS, LONG_CLASS), narrowingToShort);
Pair.of(SHORT_CLASS, BIG_INTEGER_CLASS)240         standardConverterMap.put(Pair.of(SHORT_CLASS, BIG_INTEGER_CLASS), narrowingBigIntegerToShort);
Pair.of(SHORT_CLASS, FLOAT_CLASS)241         standardConverterMap.put(Pair.of(SHORT_CLASS, FLOAT_CLASS), narrowingToShort);
Pair.of(SHORT_CLASS, DOUBLE_CLASS)242         standardConverterMap.put(Pair.of(SHORT_CLASS, DOUBLE_CLASS), narrowingToShort);
Pair.of(SHORT_CLASS, BIG_DECIMAL_CLASS)243         standardConverterMap.put(Pair.of(SHORT_CLASS, BIG_DECIMAL_CLASS), narrowingBigDecimalToShort);
Pair.of(SHORT_CLASS, NUMBER_CLASS)244         standardConverterMap.put(Pair.of(SHORT_CLASS, NUMBER_CLASS), narrowingToShort);
Pair.of(SHORT_CLASS, INTEGER_TYPE)245         standardConverterMap.put(Pair.of(SHORT_CLASS, INTEGER_TYPE), narrowingToShort);
Pair.of(SHORT_CLASS, LONG_TYPE)246         standardConverterMap.put(Pair.of(SHORT_CLASS, LONG_TYPE), narrowingToShort);
Pair.of(SHORT_CLASS, FLOAT_TYPE)247         standardConverterMap.put(Pair.of(SHORT_CLASS, FLOAT_TYPE), narrowingToShort);
Pair.of(SHORT_CLASS, DOUBLE_TYPE)248         standardConverterMap.put(Pair.of(SHORT_CLASS, DOUBLE_TYPE), narrowingToShort);
Pair.of(SHORT_TYPE, INTEGER_CLASS)249         standardConverterMap.put(Pair.of(SHORT_TYPE, INTEGER_CLASS), narrowingToShort);
Pair.of(SHORT_TYPE, LONG_CLASS)250         standardConverterMap.put(Pair.of(SHORT_TYPE, LONG_CLASS), narrowingToShort);
Pair.of(SHORT_TYPE, BIG_INTEGER_CLASS)251         standardConverterMap.put(Pair.of(SHORT_TYPE, BIG_INTEGER_CLASS), narrowingBigIntegerToShort);
Pair.of(SHORT_TYPE, FLOAT_CLASS)252         standardConverterMap.put(Pair.of(SHORT_TYPE, FLOAT_CLASS), narrowingToShort);
Pair.of(SHORT_TYPE, DOUBLE_CLASS)253         standardConverterMap.put(Pair.of(SHORT_TYPE, DOUBLE_CLASS), narrowingToShort);
Pair.of(SHORT_TYPE, BIG_DECIMAL_CLASS)254         standardConverterMap.put(Pair.of(SHORT_TYPE, BIG_DECIMAL_CLASS), narrowingBigDecimalToShort);
Pair.of(SHORT_TYPE, NUMBER_CLASS)255         standardConverterMap.put(Pair.of(SHORT_TYPE, NUMBER_CLASS), narrowingToShort);
Pair.of(SHORT_TYPE, INTEGER_TYPE)256         standardConverterMap.put(Pair.of(SHORT_TYPE, INTEGER_TYPE), narrowingToShort);
Pair.of(SHORT_TYPE, LONG_TYPE)257         standardConverterMap.put(Pair.of(SHORT_TYPE, LONG_TYPE), narrowingToShort);
Pair.of(SHORT_TYPE, FLOAT_TYPE)258         standardConverterMap.put(Pair.of(SHORT_TYPE, FLOAT_TYPE), narrowingToShort);
Pair.of(SHORT_TYPE, DOUBLE_TYPE)259         standardConverterMap.put(Pair.of(SHORT_TYPE, DOUBLE_TYPE), narrowingToShort);
260 
261         /* widening towards short */
262 
263         Converter<Short> wideningToShort = o -> Optional.ofNullable((Number)o)
264             .map(Number::shortValue)
265             .orElse(null);
266 
Pair.of(SHORT_CLASS, BYTE_CLASS)267         standardConverterMap.put(Pair.of(SHORT_CLASS, BYTE_CLASS), wideningToShort);
Pair.of(SHORT_CLASS, BYTE_TYPE)268         standardConverterMap.put(Pair.of(SHORT_CLASS, BYTE_TYPE), wideningToShort);
269 
270         /* string to short */
271 
272         Converter<Short> stringToShort = o -> Short.valueOf(String.valueOf(o));
273 
Pair.of(SHORT_CLASS, STRING_CLASS)274         standardConverterMap.put(Pair.of(SHORT_CLASS, STRING_CLASS), stringToShort);
Pair.of(SHORT_TYPE, STRING_CLASS)275         standardConverterMap.put(Pair.of(SHORT_TYPE, STRING_CLASS), stringToShort);
276 
277         /*
278          * Conversions towards int
279          */
280 
281         /* narrowing towards int */
282 
283         Converter<Integer> narrowingToInteger = o -> Optional.ofNullable((Number)o)
284             .filter(n -> checkBounds(n, Integer.MIN_VALUE, Integer.MAX_VALUE))
285             .map(Number::intValue)
286             .orElse(null);
287 
288         Converter<Integer> narrowingBigIntegerToInteger = o -> Optional.ofNullable((BigInteger)o)
289             .map(BigInteger::intValueExact)
290             .orElse(null);
291 
292         Converter<Integer> narrowingBigDecimalToInteger = o -> Optional.ofNullable((BigDecimal)o)
293             .map(BigDecimal::intValueExact)
294             .orElse(null);
295 
Pair.of(INTEGER_CLASS, LONG_CLASS)296         standardConverterMap.put(Pair.of(INTEGER_CLASS, LONG_CLASS), narrowingToInteger);
Pair.of(INTEGER_CLASS, BIG_INTEGER_CLASS)297         standardConverterMap.put(Pair.of(INTEGER_CLASS, BIG_INTEGER_CLASS), narrowingBigIntegerToInteger);
Pair.of(INTEGER_CLASS, FLOAT_CLASS)298         standardConverterMap.put(Pair.of(INTEGER_CLASS, FLOAT_CLASS), narrowingToInteger);
Pair.of(INTEGER_CLASS, DOUBLE_CLASS)299         standardConverterMap.put(Pair.of(INTEGER_CLASS, DOUBLE_CLASS), narrowingToInteger);
Pair.of(INTEGER_CLASS, BIG_DECIMAL_CLASS)300         standardConverterMap.put(Pair.of(INTEGER_CLASS, BIG_DECIMAL_CLASS), narrowingBigDecimalToInteger);
Pair.of(INTEGER_CLASS, NUMBER_CLASS)301         standardConverterMap.put(Pair.of(INTEGER_CLASS, NUMBER_CLASS), narrowingToInteger);
Pair.of(INTEGER_CLASS, LONG_TYPE)302         standardConverterMap.put(Pair.of(INTEGER_CLASS, LONG_TYPE), narrowingToInteger);
Pair.of(INTEGER_CLASS, FLOAT_TYPE)303         standardConverterMap.put(Pair.of(INTEGER_CLASS, FLOAT_TYPE), narrowingToInteger);
Pair.of(INTEGER_CLASS, DOUBLE_TYPE)304         standardConverterMap.put(Pair.of(INTEGER_CLASS, DOUBLE_TYPE), narrowingToInteger);
Pair.of(INTEGER_TYPE, LONG_CLASS)305         standardConverterMap.put(Pair.of(INTEGER_TYPE, LONG_CLASS), narrowingToInteger);
Pair.of(INTEGER_TYPE, BIG_INTEGER_CLASS)306         standardConverterMap.put(Pair.of(INTEGER_TYPE, BIG_INTEGER_CLASS), narrowingBigIntegerToInteger);
Pair.of(INTEGER_TYPE, FLOAT_CLASS)307         standardConverterMap.put(Pair.of(INTEGER_TYPE, FLOAT_CLASS), narrowingToInteger);
Pair.of(INTEGER_TYPE, DOUBLE_CLASS)308         standardConverterMap.put(Pair.of(INTEGER_TYPE, DOUBLE_CLASS), narrowingToInteger);
Pair.of(INTEGER_TYPE, BIG_DECIMAL_CLASS)309         standardConverterMap.put(Pair.of(INTEGER_TYPE, BIG_DECIMAL_CLASS), narrowingBigDecimalToInteger);
Pair.of(INTEGER_TYPE, NUMBER_CLASS)310         standardConverterMap.put(Pair.of(INTEGER_TYPE, NUMBER_CLASS), narrowingToInteger);
Pair.of(INTEGER_TYPE, LONG_TYPE)311         standardConverterMap.put(Pair.of(INTEGER_TYPE, LONG_TYPE), narrowingToInteger);
Pair.of(INTEGER_TYPE, FLOAT_TYPE)312         standardConverterMap.put(Pair.of(INTEGER_TYPE, FLOAT_TYPE), narrowingToInteger);
Pair.of(INTEGER_TYPE, DOUBLE_TYPE)313         standardConverterMap.put(Pair.of(INTEGER_TYPE, DOUBLE_TYPE), narrowingToInteger);
314 
315         /* widening towards int */
316 
317         Converter<Integer> wideningToInteger = o -> Optional.ofNullable((Number)o)
318             .map(Number::intValue)
319             .orElse(null);
320 
Pair.of(INTEGER_CLASS, BYTE_CLASS)321         standardConverterMap.put(Pair.of(INTEGER_CLASS, BYTE_CLASS), wideningToInteger);
Pair.of(INTEGER_CLASS, SHORT_CLASS)322         standardConverterMap.put(Pair.of(INTEGER_CLASS, SHORT_CLASS), wideningToInteger);
Pair.of(INTEGER_CLASS, BYTE_TYPE)323         standardConverterMap.put(Pair.of(INTEGER_CLASS, BYTE_TYPE), wideningToInteger);
Pair.of(INTEGER_CLASS, SHORT_TYPE)324         standardConverterMap.put(Pair.of(INTEGER_CLASS, SHORT_TYPE), wideningToInteger);
325 
326         /* string to int */
327 
328         Converter<Integer> stringToInteger = o -> Integer.valueOf(String.valueOf(o));
329 
Pair.of(INTEGER_CLASS, STRING_CLASS)330         standardConverterMap.put(Pair.of(INTEGER_CLASS, STRING_CLASS), stringToInteger);
Pair.of(INTEGER_TYPE, STRING_CLASS)331         standardConverterMap.put(Pair.of(INTEGER_TYPE, STRING_CLASS), stringToInteger);
332 
333         /*
334          * Conversions towards long
335          */
336 
337         /* narrowing towards long */
338 
339         Converter<Long> narrowingToLong = o -> Optional.ofNullable((Number)o)
340             .filter(n -> checkBounds(n, Long.MIN_VALUE, Long.MAX_VALUE))
341             .map(Number::longValue)
342             .orElse(null);
343 
344         Converter<Long> narrowingBigIntegerToLong = o -> Optional.ofNullable((BigInteger)o)
345             .map(BigInteger::longValueExact)
346             .orElse(null);
347 
348         Converter<Long> narrowingBigDecimalToLong = o -> Optional.ofNullable((BigDecimal)o)
349             .map(BigDecimal::longValueExact)
350             .orElse(null);
351 
Pair.of(LONG_CLASS, BIG_INTEGER_CLASS)352         standardConverterMap.put(Pair.of(LONG_CLASS, BIG_INTEGER_CLASS), narrowingBigIntegerToLong);
Pair.of(LONG_CLASS, FLOAT_CLASS)353         standardConverterMap.put(Pair.of(LONG_CLASS, FLOAT_CLASS), narrowingToLong);
Pair.of(LONG_CLASS, DOUBLE_CLASS)354         standardConverterMap.put(Pair.of(LONG_CLASS, DOUBLE_CLASS), narrowingToLong);
Pair.of(LONG_CLASS, BIG_DECIMAL_CLASS)355         standardConverterMap.put(Pair.of(LONG_CLASS, BIG_DECIMAL_CLASS), narrowingBigDecimalToLong);
Pair.of(LONG_CLASS, NUMBER_CLASS)356         standardConverterMap.put(Pair.of(LONG_CLASS, NUMBER_CLASS), narrowingToLong);
Pair.of(LONG_CLASS, FLOAT_TYPE)357         standardConverterMap.put(Pair.of(LONG_CLASS, FLOAT_TYPE), narrowingToLong);
Pair.of(LONG_CLASS, DOUBLE_TYPE)358         standardConverterMap.put(Pair.of(LONG_CLASS, DOUBLE_TYPE), narrowingToLong);
Pair.of(LONG_TYPE, BIG_INTEGER_CLASS)359         standardConverterMap.put(Pair.of(LONG_TYPE, BIG_INTEGER_CLASS), narrowingBigIntegerToLong);
Pair.of(LONG_TYPE, FLOAT_CLASS)360         standardConverterMap.put(Pair.of(LONG_TYPE, FLOAT_CLASS), narrowingToLong);
Pair.of(LONG_TYPE, DOUBLE_CLASS)361         standardConverterMap.put(Pair.of(LONG_TYPE, DOUBLE_CLASS), narrowingToLong);
Pair.of(LONG_TYPE, BIG_DECIMAL_CLASS)362         standardConverterMap.put(Pair.of(LONG_TYPE, BIG_DECIMAL_CLASS), narrowingBigDecimalToLong);
Pair.of(LONG_TYPE, NUMBER_CLASS)363         standardConverterMap.put(Pair.of(LONG_TYPE, NUMBER_CLASS), narrowingToLong);
Pair.of(LONG_TYPE, FLOAT_TYPE)364         standardConverterMap.put(Pair.of(LONG_TYPE, FLOAT_TYPE), narrowingToLong);
Pair.of(LONG_TYPE, DOUBLE_TYPE)365         standardConverterMap.put(Pair.of(LONG_TYPE, DOUBLE_TYPE), narrowingToLong);
366 
367         /* widening towards long */
368 
369         Converter<Long> wideningToLong = o -> Optional.ofNullable((Number)o)
370             .map(Number::longValue)
371             .orElse(null);
372 
Pair.of(LONG_CLASS, BYTE_CLASS)373         standardConverterMap.put(Pair.of(LONG_CLASS, BYTE_CLASS), wideningToLong);
Pair.of(LONG_CLASS, SHORT_CLASS)374         standardConverterMap.put(Pair.of(LONG_CLASS, SHORT_CLASS), wideningToLong);
Pair.of(LONG_CLASS, INTEGER_CLASS)375         standardConverterMap.put(Pair.of(LONG_CLASS, INTEGER_CLASS), wideningToLong);
Pair.of(LONG_CLASS, BYTE_TYPE)376         standardConverterMap.put(Pair.of(LONG_CLASS, BYTE_TYPE), wideningToLong);
Pair.of(LONG_CLASS, SHORT_TYPE)377         standardConverterMap.put(Pair.of(LONG_CLASS, SHORT_TYPE), wideningToLong);
Pair.of(LONG_CLASS, INTEGER_TYPE)378         standardConverterMap.put(Pair.of(LONG_CLASS, INTEGER_TYPE), wideningToLong);
379 
380         /* string to long */
381 
382         Converter<Long> stringToLong = o -> Long.valueOf(String.valueOf(o));
383 
Pair.of(LONG_CLASS, STRING_CLASS)384         standardConverterMap.put(Pair.of(LONG_CLASS, STRING_CLASS), stringToLong);
Pair.of(LONG_TYPE, STRING_CLASS)385         standardConverterMap.put(Pair.of(LONG_TYPE, STRING_CLASS), stringToLong);
386 
387         /*
388          * Conversions towards BigInteger
389          */
390 
391         /* exact types towards BigInteger */
392 
393         Converter<BigInteger> toBigInteger = o -> Optional.ofNullable((Number)o)
394             .map(n -> BigInteger.valueOf(n.longValue()))
395             .orElse(null);
396 
Pair.of(BIG_INTEGER_CLASS, BYTE_CLASS)397         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, BYTE_CLASS), toBigInteger);
Pair.of(BIG_INTEGER_CLASS, SHORT_CLASS)398         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, SHORT_CLASS), toBigInteger);
Pair.of(BIG_INTEGER_CLASS, INTEGER_CLASS)399         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, INTEGER_CLASS), toBigInteger);
Pair.of(BIG_INTEGER_CLASS, LONG_CLASS)400         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, LONG_CLASS), toBigInteger);
Pair.of(BIG_INTEGER_CLASS, BYTE_TYPE)401         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, BYTE_TYPE), toBigInteger);
Pair.of(BIG_INTEGER_CLASS, SHORT_TYPE)402         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, SHORT_TYPE), toBigInteger);
Pair.of(BIG_INTEGER_CLASS, INTEGER_TYPE)403         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, INTEGER_TYPE), toBigInteger);
Pair.of(BIG_INTEGER_CLASS, LONG_TYPE)404         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, LONG_TYPE), toBigInteger);
405 
406         /* approximate types towards BigInteger */
407 
408         /* It makes no sense trying to convert from float or double towards BigInteger
409            if we do care about precision loss..
410          */
411 
412         Converter<BigInteger> bigDecimalToBigInteger = o -> Optional.ofNullable((BigDecimal)o)
413             .map(BigDecimal::toBigIntegerExact)
414             .orElse(null);
415 
Pair.of(BIG_INTEGER_CLASS, BIG_DECIMAL_CLASS)416         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, BIG_DECIMAL_CLASS), bigDecimalToBigInteger);
417 
418         /* string to BigInteger */
419 
420         Converter<BigInteger> stringToBigInteger = o -> Optional.ofNullable(o)
421             .map(s -> new BigInteger(String.valueOf(s)))
422             .orElse(null);
423 
Pair.of(BIG_INTEGER_CLASS, STRING_CLASS)424         standardConverterMap.put(Pair.of(BIG_INTEGER_CLASS, STRING_CLASS), stringToBigInteger);
425 
426         /*
427          * Conversions towards float
428          */
429 
430         Converter<Float> toFloat = o -> Optional.ofNullable((Number)o)
431             .map(Number::floatValue)
432             .orElse(null);
433 
434         /* narrowing towards float */
435 
Pair.of(FLOAT_CLASS, BIG_INTEGER_CLASS)436         standardConverterMap.put(Pair.of(FLOAT_CLASS, BIG_INTEGER_CLASS), toFloat);
Pair.of(FLOAT_CLASS, DOUBLE_CLASS)437         standardConverterMap.put(Pair.of(FLOAT_CLASS, DOUBLE_CLASS), toFloat);
Pair.of(FLOAT_CLASS, BIG_DECIMAL_CLASS)438         standardConverterMap.put(Pair.of(FLOAT_CLASS, BIG_DECIMAL_CLASS), toFloat);
Pair.of(FLOAT_CLASS, NUMBER_CLASS)439         standardConverterMap.put(Pair.of(FLOAT_CLASS, NUMBER_CLASS), toFloat);
Pair.of(FLOAT_CLASS, DOUBLE_TYPE)440         standardConverterMap.put(Pair.of(FLOAT_CLASS, DOUBLE_TYPE), toFloat);
Pair.of(FLOAT_TYPE, BIG_INTEGER_CLASS)441         standardConverterMap.put(Pair.of(FLOAT_TYPE, BIG_INTEGER_CLASS), toFloat);
Pair.of(FLOAT_TYPE, DOUBLE_CLASS)442         standardConverterMap.put(Pair.of(FLOAT_TYPE, DOUBLE_CLASS), toFloat);
Pair.of(FLOAT_TYPE, BIG_DECIMAL_CLASS)443         standardConverterMap.put(Pair.of(FLOAT_TYPE, BIG_DECIMAL_CLASS), toFloat);
Pair.of(FLOAT_TYPE, NUMBER_CLASS)444         standardConverterMap.put(Pair.of(FLOAT_TYPE, NUMBER_CLASS), toFloat);
Pair.of(FLOAT_TYPE, DOUBLE_TYPE)445         standardConverterMap.put(Pair.of(FLOAT_TYPE, DOUBLE_TYPE), toFloat);
446 
447         /* exact types towards float */
448 
Pair.of(FLOAT_CLASS, BYTE_CLASS)449         standardConverterMap.put(Pair.of(FLOAT_CLASS, BYTE_CLASS), toFloat);
Pair.of(FLOAT_CLASS, SHORT_CLASS)450         standardConverterMap.put(Pair.of(FLOAT_CLASS, SHORT_CLASS), toFloat);
Pair.of(FLOAT_CLASS, INTEGER_CLASS)451         standardConverterMap.put(Pair.of(FLOAT_CLASS, INTEGER_CLASS), toFloat);
Pair.of(FLOAT_CLASS, LONG_CLASS)452         standardConverterMap.put(Pair.of(FLOAT_CLASS, LONG_CLASS), toFloat);
Pair.of(FLOAT_CLASS, BYTE_TYPE)453         standardConverterMap.put(Pair.of(FLOAT_CLASS, BYTE_TYPE), toFloat);
Pair.of(FLOAT_CLASS, SHORT_TYPE)454         standardConverterMap.put(Pair.of(FLOAT_CLASS, SHORT_TYPE), toFloat);
Pair.of(FLOAT_CLASS, INTEGER_TYPE)455         standardConverterMap.put(Pair.of(FLOAT_CLASS, INTEGER_TYPE), toFloat);
Pair.of(FLOAT_CLASS, LONG_TYPE)456         standardConverterMap.put(Pair.of(FLOAT_CLASS, LONG_TYPE), toFloat);
457 
458         /* string to float */
459 
460         Converter<Float> stringToFloat = o -> Float.valueOf(String.valueOf(o));
461 
Pair.of(FLOAT_CLASS, STRING_CLASS)462         standardConverterMap.put(Pair.of(FLOAT_CLASS, STRING_CLASS), stringToFloat);
Pair.of(FLOAT_TYPE, STRING_CLASS)463         standardConverterMap.put(Pair.of(FLOAT_TYPE, STRING_CLASS), stringToFloat);
464 
465         /*
466          * Conversions towards double
467          */
468 
469         Converter<Double> toDouble = o -> Optional.ofNullable((Number)o)
470             .map(Number::doubleValue)
471             .orElse(null);
472 
473         /* narrowing towards double */
474 
Pair.of(DOUBLE_CLASS, BIG_INTEGER_CLASS)475         standardConverterMap.put(Pair.of(DOUBLE_CLASS, BIG_INTEGER_CLASS), toDouble);
Pair.of(DOUBLE_CLASS, BIG_DECIMAL_CLASS)476         standardConverterMap.put(Pair.of(DOUBLE_CLASS, BIG_DECIMAL_CLASS), toDouble);
Pair.of(DOUBLE_TYPE, BIG_INTEGER_CLASS)477         standardConverterMap.put(Pair.of(DOUBLE_TYPE, BIG_INTEGER_CLASS), toDouble);
Pair.of(DOUBLE_TYPE, BIG_DECIMAL_CLASS)478         standardConverterMap.put(Pair.of(DOUBLE_TYPE, BIG_DECIMAL_CLASS), toDouble);
479 
480         /* exact types or widening towards double */
481 
Pair.of(DOUBLE_CLASS, BYTE_CLASS)482         standardConverterMap.put(Pair.of(DOUBLE_CLASS, BYTE_CLASS), toDouble);
Pair.of(DOUBLE_CLASS, SHORT_CLASS)483         standardConverterMap.put(Pair.of(DOUBLE_CLASS, SHORT_CLASS), toDouble);
Pair.of(DOUBLE_CLASS, INTEGER_CLASS)484         standardConverterMap.put(Pair.of(DOUBLE_CLASS, INTEGER_CLASS), toDouble);
Pair.of(DOUBLE_CLASS, LONG_CLASS)485         standardConverterMap.put(Pair.of(DOUBLE_CLASS, LONG_CLASS), toDouble);
Pair.of(DOUBLE_CLASS, FLOAT_CLASS)486         standardConverterMap.put(Pair.of(DOUBLE_CLASS, FLOAT_CLASS), toDouble);
Pair.of(DOUBLE_CLASS, NUMBER_CLASS)487         standardConverterMap.put(Pair.of(DOUBLE_CLASS, NUMBER_CLASS), toDouble);
Pair.of(DOUBLE_CLASS, BYTE_TYPE)488         standardConverterMap.put(Pair.of(DOUBLE_CLASS, BYTE_TYPE), toDouble);
Pair.of(DOUBLE_CLASS, SHORT_TYPE)489         standardConverterMap.put(Pair.of(DOUBLE_CLASS, SHORT_TYPE), toDouble);
Pair.of(DOUBLE_CLASS, INTEGER_TYPE)490         standardConverterMap.put(Pair.of(DOUBLE_CLASS, INTEGER_TYPE), toDouble);
Pair.of(DOUBLE_CLASS, LONG_TYPE)491         standardConverterMap.put(Pair.of(DOUBLE_CLASS, LONG_TYPE), toDouble);
Pair.of(DOUBLE_CLASS, FLOAT_TYPE)492         standardConverterMap.put(Pair.of(DOUBLE_CLASS, FLOAT_TYPE), toDouble);
Pair.of(DOUBLE_TYPE, NUMBER_CLASS)493         standardConverterMap.put(Pair.of(DOUBLE_TYPE, NUMBER_CLASS), toDouble);
494 
495         /* string to double */
496 
497         Converter<Double> stringToDouble = o -> Double.valueOf(String.valueOf(o));
498 
Pair.of(DOUBLE_CLASS, STRING_CLASS)499         standardConverterMap.put(Pair.of(DOUBLE_CLASS, STRING_CLASS), stringToDouble);
Pair.of(DOUBLE_TYPE, STRING_CLASS)500         standardConverterMap.put(Pair.of(DOUBLE_TYPE, STRING_CLASS), stringToDouble);
501 
502         /*
503          * Conversions towards BigDecimal
504          */
505 
506         /* exact types towards BigDecimal */
507 
508         Converter<BigDecimal> exactToBigDecimal = o -> Optional.ofNullable((Number)o)
509             .map(n -> BigDecimal.valueOf(n.longValue()))
510             .orElse(null);
511 
512         Converter<BigDecimal> bigIntegerToBigDecimal = o -> Optional.ofNullable((BigInteger)o)
513             .map(bi -> new BigDecimal(bi))
514             .orElse(null);
515 
Pair.of(BIG_DECIMAL_CLASS, BYTE_CLASS)516         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, BYTE_CLASS), exactToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, SHORT_CLASS)517         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, SHORT_CLASS), exactToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, INTEGER_CLASS)518         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, INTEGER_CLASS), exactToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, LONG_CLASS)519         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, LONG_CLASS), exactToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, BIG_INTEGER_CLASS)520         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, BIG_INTEGER_CLASS), bigIntegerToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, BYTE_TYPE)521         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, BYTE_TYPE), exactToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, SHORT_TYPE)522         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, SHORT_TYPE), exactToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, INTEGER_TYPE)523         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, INTEGER_TYPE), exactToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, LONG_TYPE)524         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, LONG_TYPE), exactToBigDecimal);
525 
526         /* approximate types towards BigDecimal */
527 
528         Converter<BigDecimal> approxToBigDecimal = o -> Optional.ofNullable((Number)o)
529             .map(n -> BigDecimal.valueOf(n.doubleValue()))
530             .orElse(null);
531 
Pair.of(BIG_DECIMAL_CLASS, FLOAT_CLASS)532         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, FLOAT_CLASS), approxToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, DOUBLE_CLASS)533         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, DOUBLE_CLASS), approxToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, FLOAT_TYPE)534         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, FLOAT_TYPE), approxToBigDecimal);
Pair.of(BIG_DECIMAL_CLASS, DOUBLE_TYPE)535         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, DOUBLE_TYPE), approxToBigDecimal);
536 
537         /* string to BigDecimal */
538 
539         Converter<BigDecimal> stringToBigDecimal = o -> Optional.ofNullable(o)
540             .map(s -> new BigDecimal(String.valueOf(s)))
541             .orElse(null);
542 
Pair.of(BIG_DECIMAL_CLASS, STRING_CLASS)543         standardConverterMap.put(Pair.of(BIG_DECIMAL_CLASS, STRING_CLASS), stringToBigDecimal);
544 
545         /*
546          * Conversions from boolean to numeric type
547          */
548 
549         /* boolean to byte */
550 
551         Converter<Byte> booleanToByte = o -> Optional.ofNullable((Boolean)o)
552             .map(b -> b ? (byte)1 : (byte)0)
553             .orElse(null);
554 
Pair.of(BYTE_CLASS, BOOLEAN_CLASS)555         standardConverterMap.put(Pair.of(BYTE_CLASS, BOOLEAN_CLASS), booleanToByte);
Pair.of(BYTE_CLASS, BOOLEAN_TYPE)556         standardConverterMap.put(Pair.of(BYTE_CLASS, BOOLEAN_TYPE), booleanToByte);
Pair.of(BYTE_TYPE, BOOLEAN_CLASS)557         standardConverterMap.put(Pair.of(BYTE_TYPE, BOOLEAN_CLASS), booleanToByte);
Pair.of(BYTE_TYPE, BOOLEAN_TYPE)558         standardConverterMap.put(Pair.of(BYTE_TYPE, BOOLEAN_TYPE), booleanToByte);
559 
560         /* boolean to short */
561 
562         Converter<Short> booleanToShort = o -> Optional.ofNullable((Boolean)o)
563             .map(b -> b ? (short)1 : (short)0)
564             .orElse(null);
565 
Pair.of(SHORT_CLASS, BOOLEAN_CLASS)566         standardConverterMap.put(Pair.of(SHORT_CLASS, BOOLEAN_CLASS), booleanToShort);
Pair.of(SHORT_CLASS, BOOLEAN_TYPE)567         standardConverterMap.put(Pair.of(SHORT_CLASS, BOOLEAN_TYPE), booleanToShort);
Pair.of(SHORT_TYPE, BOOLEAN_CLASS)568         standardConverterMap.put(Pair.of(SHORT_TYPE, BOOLEAN_CLASS), booleanToShort);
Pair.of(SHORT_TYPE, BOOLEAN_TYPE)569         standardConverterMap.put(Pair.of(SHORT_TYPE, BOOLEAN_TYPE), booleanToShort);
570 
571         /* boolean to integer */
572 
573         Converter<Integer> booleanToInteger = o -> Optional.ofNullable((Boolean)o)
574             .map(b -> b ? (int)1 : (int)0)
575             .orElse(null);
576 
Pair.of(INTEGER_CLASS, BOOLEAN_CLASS)577         standardConverterMap.put(Pair.of(INTEGER_CLASS, BOOLEAN_CLASS), booleanToInteger);
Pair.of(INTEGER_CLASS, BOOLEAN_TYPE)578         standardConverterMap.put(Pair.of(INTEGER_CLASS, BOOLEAN_TYPE), booleanToInteger);
Pair.of(INTEGER_TYPE, BOOLEAN_CLASS)579         standardConverterMap.put(Pair.of(INTEGER_TYPE, BOOLEAN_CLASS), booleanToInteger);
Pair.of(INTEGER_TYPE, BOOLEAN_TYPE)580         standardConverterMap.put(Pair.of(INTEGER_TYPE, BOOLEAN_TYPE), booleanToInteger);
581 
582         /* boolean to long */
583 
584         Converter<Long> booleanToLong = o -> Optional.ofNullable((Boolean)o)
585             .map(b -> b ? 1l : 0l)
586             .orElse(null);
587 
Pair.of(LONG_CLASS, BOOLEAN_CLASS)588         standardConverterMap.put(Pair.of(LONG_CLASS, BOOLEAN_CLASS), booleanToLong);
Pair.of(LONG_CLASS, BOOLEAN_TYPE)589         standardConverterMap.put(Pair.of(LONG_CLASS, BOOLEAN_TYPE), booleanToLong);
Pair.of(LONG_TYPE, BOOLEAN_CLASS)590         standardConverterMap.put(Pair.of(LONG_TYPE, BOOLEAN_CLASS), booleanToLong);
Pair.of(LONG_TYPE, BOOLEAN_TYPE)591         standardConverterMap.put(Pair.of(LONG_TYPE, BOOLEAN_TYPE), booleanToLong);
592 
593         /* to string */
594 
595         toString = o -> String.valueOf(o);
596 
597         /* string to locale */
598         Converter<Locale> stringToLocale = o -> Optional.ofNullable(o)
599             .map(l -> LocaleUtils.toLocale(String.valueOf(l)))
600             .orElse(null);
601 
Pair.of(LOCALE_CLASS, STRING_CLASS)602         standardConverterMap.put(Pair.of(LOCALE_CLASS, STRING_CLASS), stringToLocale);
603     }
604 
605     /**
606      * Constructor
607      */
TypeConversionHandlerImpl()608     public TypeConversionHandlerImpl()
609     {
610         converterCacheMap = new ConcurrentHashMap<>();
611     }
612 
613     /**
614      * Check to see if the conversion can be done using an explicit conversion
615      * @param actual found argument type
616      * @param formal expected formal type
617      * @return true if actual class can be explicitely converted to expected formal type
618      * @since 2.1
619      */
620     @Override
isExplicitlyConvertible(Type formal, Class<?> actual, boolean possibleVarArg)621     public boolean isExplicitlyConvertible(Type formal, Class<?> actual, boolean possibleVarArg)
622     {
623         /*
624          * for consistency, we also have to check standard implicit convertibility
625          * since it may not have been checked before by the calling code
626          */
627         Class<?> formalClass = IntrospectionUtils.getTypeClass(formal);
628         if (formalClass != null && formalClass == actual ||
629             IntrospectionUtils.isMethodInvocationConvertible(formal, actual, possibleVarArg) ||
630             getNeededConverter(formal, actual) != null)
631         {
632             return true;
633         }
634 
635         /* Check var arg */
636         if (possibleVarArg && TypeUtils.isArrayType(formal))
637         {
638             if (actual.isArray())
639             {
640                 actual = actual.getComponentType();
641             }
642             return isExplicitlyConvertible(TypeUtils.getArrayComponentType(formal), actual, false);
643         }
644         return false;
645     }
646 
647 
648     /**
649      * Returns the appropriate Converter object needed for an explicit conversion
650      * Returns null if no conversion is needed.
651      *
652      * @param actual found argument type
653      * @param formal expected formal type
654      * @return null if no conversion is needed, or the appropriate Converter object
655      * @since 2.1
656      */
657     @Override
getNeededConverter(Type formal, Class<?> actual)658     public Converter<?> getNeededConverter(Type formal, Class<?> actual)
659     {
660         if (actual == null)
661         {
662             return null;
663         }
664         Pair<String, String> key = Pair.of(formal.getTypeName(), actual.getTypeName());
665 
666         /* first check for a standard conversion */
667         Converter<?> converter = standardConverterMap.get(key);
668         if (converter == null)
669         {
670             /* then the converters cache map */
671             converter = converterCacheMap.get(key);
672             if (converter == null)
673             {
674                 Class<?> formalClass = IntrospectionUtils.getTypeClass(formal);
675                 /* check for conversion towards string */
676                 if (formal == String.class)
677                 {
678                     converter = toString;
679                 }
680                 /* check for String -> Enum constant conversion */
681                 else if (formalClass != null && formalClass.isEnum() && actual == String.class)
682                 {
683                     final Class<Enum> enumClass = (Class<Enum>)formalClass;
684                     converter = o -> Enum.valueOf(enumClass, (String)o);
685                 }
686 
687                 converterCacheMap.put(key, converter == null ? cacheMiss : converter);
688             }
689         }
690         return converter == cacheMiss ? null : converter;
691     }
692 
693     /**
694      * Add the given converter to the handler.
695      *
696      * @param formal expected formal type
697      * @param actual provided argument type
698      * @param converter converter
699      * @since 2.1
700      */
701     @Override
addConverter(Type formal, Class<?> actual, Converter<?> converter)702     public void addConverter(Type formal, Class<?> actual, Converter<?> converter)
703     {
704         Pair<String, String> key = Pair.of(formal.getTypeName(), actual.getTypeName());
705         converterCacheMap.put(key, converter);
706         Class<?> formalClass = IntrospectionUtils.getTypeClass(formal);
707         if (formalClass != null)
708         {
709             if (formalClass.isPrimitive())
710             {
711                 key = Pair.of(IntrospectionUtils.getBoxedClass(formalClass).getTypeName(), actual.getTypeName());
712                 converterCacheMap.put(key, converter);
713             }
714             else
715             {
716                 Class<?> unboxedFormal = IntrospectionUtils.getUnboxedClass(formalClass);
717                 if (unboxedFormal != formalClass)
718                 {
719                     key = Pair.of(unboxedFormal.getTypeName(), actual.getTypeName());
720                     converterCacheMap.put(key, converter);
721                 }
722             }
723         }
724     }
725 }
726