001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.internal;
014
015import static org.apache.juneau.common.internal.ThrowableUtils.*;
016
017import java.lang.reflect.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.common.internal.*;
021import org.apache.juneau.parser.*;
022import org.apache.juneau.swap.*;
023
024/**
025 * Utility class for efficiently converting objects between types.
026 *
027 * <p>
028 * If the value isn't an instance of the specified type, then converts the value if possible.
029 *
030 * <p>
031 * The following conversions are valid:
032 * <table class='styled'>
033 *    <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr>
034 *    <tr>
035 *       <td>
036 *          A class that is the normal type of a registered {@link ObjectSwap}.
037 *       </td>
038 *       <td>
039 *          A value whose class matches the transformed type of that registered {@link ObjectSwap}.
040 *       </td>
041 *       <td>&nbsp;</td>
042 *    </tr>
043 *    <tr>
044 *       <td>
045 *          A class that is the transformed type of a registered {@link ObjectSwap}.
046 *       </td>
047 *       <td>
048 *          A value whose class matches the normal type of that registered {@link ObjectSwap}.
049 *       </td>
050 *       <td>&nbsp;</td>
051 *    </tr>
052 *    <tr>
053 *       <td>
054 *          {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...)
055 *          <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>,
056 *          <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...)
057 *       </td>
058 *       <td>
059 *          {@code Number}, {@code String}, <jk>null</jk>
060 *       </td>
061 *       <td>
062 *          For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type.
063 *       </td>
064 *    </tr>
065 *    <tr>
066 *       <td>
067 *          {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code JsonMap})
068 *       </td>
069 *       <td>
070 *          {@code Map}
071 *       </td>
072 *       <td>
073 *          If {@code Map} is not constructible, an {@code JsonMap} is created.
074 *       </td>
075 *    </tr>
076 *    <tr>
077 *       <td>
078 *          <c>Collection</c> (e.g. <c>List</c>, <c>LinkedList</c>, <c>HashSet</c>, <c>JsonList</c>)
079 *       </td>
080 *       <td>
081 *          <c>Collection&lt;Object&gt;</c>
082 *          <br><c>Object[]</c>
083 *       </td>
084 *       <td>
085 *          If <c>Collection</c> is not constructible, a <c>JsonList</c> is created.
086 *       </td>
087 *    </tr>
088 *    <tr>
089 *       <td>
090 *          <c>X[]</c> (array of any type X)
091 *       </td>
092 *       <td>
093 *          <c>List&lt;X&gt;</c>
094 *       </td>
095 *       <td>&nbsp;</td>
096 *    </tr>
097 *    <tr>
098 *       <td>
099 *          <c>X[][]</c> (multi-dimensional arrays)
100 *       </td>
101 *       <td>
102 *          <c>List&lt;List&lt;X&gt;&gt;</c>
103 *          <br><c>List&lt;X[]&gt;</c>
104 *          <br><c> List[]&lt;X&gt;</c>
105 *       </td>
106 *       <td>&nbsp;</td>
107 *    </tr>
108 *    <tr>
109 *       <td>
110 *          <c>Enum</c>
111 *       </td>
112 *       <td>
113 *          <c>String</c>
114 *       </td>
115 *       <td>&nbsp;</td>
116 *    </tr>
117 *    <tr>
118 *       <td>
119 *          Bean
120 *       </td>
121 *       <td>
122 *          <c>Map</c>
123 *       </td>
124 *       <td>&nbsp;</td>
125 *    </tr>
126 *    <tr>
127 *       <td>
128 *          <c>String</c>
129 *       </td>
130 *       <td>
131 *          Anything
132 *       </td>
133 *       <td>
134 *          Arrays are converted to JSON arrays
135 *       </td>
136 *    </tr>
137 *    <tr>
138 *       <td>
139 *          Anything with one of the following methods:
140 *          <br><code><jk>public static</jk> T fromString(String)</code>
141 *          <br><code><jk>public static</jk> T valueOf(String)</code>
142 *          <br><code><jk>public</jk> T(String)</code>
143 *       </td>
144 *       <td>
145 *          <c>String</c>
146 *       </td>
147 *       <td>
148 *          <br>
149 *       </td>
150 *    </tr>
151 * </table>
152 *
153 * <h5 class='section'>See Also:</h5><ul>
154 * </ul>
155 */
156public final class ConverterUtils {
157
158   // Session objects are usually not thread safe, but we're not using any feature
159   // of bean sessions that would cause thread safety issues.
160   private static final BeanSession session = BeanContext.DEFAULT_SESSION;
161
162   /**
163    * Converts the specified object to the specified type.
164    *
165    * @param <T> The class type to convert the value to.
166    * @param value The value to convert.
167    * @param type The class type to convert the value to.
168    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
169    * @return The converted value.
170    */
171   public static <T> T toType(Object value, Class<T> type) {
172      return session.convertToType(value, type);
173   }
174
175
176   /**
177    * Converts the specified object to the specified type.
178    *
179    * @param <T> The class type to convert the value to.
180    * @param value The value to convert.
181    * @param type The class type to convert the value to.
182    * @param args The type arguments.
183    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
184    * @return The converted value.
185    */
186   public static <T> T toType(Object value, Class<T> type, Type...args) {
187      return session.convertToType(value, type, args);
188   }
189
190   /**
191    * Converts an object to a Boolean.
192    *
193    * @param o The object to convert.
194    * @return The converted object.
195    */
196   public static Boolean toBoolean(Object o) {
197      return toType(o, Boolean.class);
198   }
199
200   /**
201    * Converts an object to an Integer.
202    *
203    * @param o The object to convert.
204    * @return The converted object.
205    */
206   public static Integer toInteger(Object o) {
207      return toType(o, Integer.class);
208   }
209
210   /**
211    * Converts an object to a Number.
212    *
213    * @param o The object to convert.
214    * @return The converted object.
215    */
216   public static Number toNumber(Object o) {
217      if (o == null)
218         return null;
219      if (o instanceof Number)
220         return (Number)o;
221      try {
222         return StringUtils.parseNumber(o.toString(), null);
223      } catch (ParseException e) {
224         throw asRuntimeException(e);
225      }
226   }
227}