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