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 java.lang.reflect.*;
016import java.util.*;
017
018import org.apache.juneau.*;
019import org.apache.juneau.parser.*;
020import org.apache.juneau.transform.*;
021
022/**
023 * Utility class for efficiently converting objects between types.
024 * 
025 * <p>
026 * If the value isn't an instance of the specified type, then converts the value if possible.
027 * 
028 * <p>
029 * The following conversions are valid:
030 * <table class='styled'>
031 *    <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr>
032 *    <tr>
033 *       <td>
034 *          A class that is the normal type of a registered {@link PojoSwap}.
035 *       </td>
036 *       <td>
037 *          A value whose class matches the transformed type of that registered {@link PojoSwap}.
038 *       </td>
039 *       <td>&nbsp;</td>
040 *    </tr>
041 *    <tr>
042 *       <td>
043 *          A class that is the transformed type of a registered {@link PojoSwap}.
044 *       </td>
045 *       <td>
046 *          A value whose class matches the normal type of that registered {@link PojoSwap}.
047 *       </td>
048 *       <td>&nbsp;</td>
049 *    </tr>
050 *    <tr>
051 *       <td>
052 *          {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...)
053 *          <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>,
054 *          <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...)
055 *       </td>
056 *       <td>
057 *          {@code Number}, {@code String}, <jk>null</jk>
058 *       </td>
059 *       <td>
060 *          For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type.
061 *       </td>
062 *    </tr>
063 *    <tr>
064 *       <td>
065 *          {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code ObjectMap})
066 *       </td>
067 *       <td>
068 *          {@code Map}
069 *       </td>
070 *       <td>
071 *          If {@code Map} is not constructible, a {@code ObjectMap} is created.
072 *       </td>
073 *    </tr>
074 *    <tr>
075 *       <td>
076 *          <code>Collection</code> (e.g. <code>List</code>, <code>LinkedList</code>, <code>HashSet</code>, <code>ObjectList</code>)
077 *       </td>
078 *       <td>
079 *          <code>Collection&lt;Object&gt;</code>
080 *          <br><code>Object[]</code>
081 *       </td>
082 *       <td>
083 *          If <code>Collection</code> is not constructible, a <code>ObjectList</code> is created.
084 *       </td>
085 *    </tr>
086 *    <tr>
087 *       <td>
088 *          <code>X[]</code> (array of any type X)
089 *       </td>
090 *       <td>
091 *          <code>List&lt;X&gt;</code>
092 *       </td>
093 *       <td>&nbsp;</td>
094 *    </tr>
095 *    <tr>
096 *       <td>
097 *          <code>X[][]</code> (multi-dimensional arrays)
098 *       </td>
099 *       <td>
100 *          <code>List&lt;List&lt;X&gt;&gt;</code>
101 *          <br><code>List&lt;X[]&gt;</code>
102 *          <br><code> List[]&lt;X&gt;</code>
103 *       </td>
104 *       <td>&nbsp;</td>
105 *    </tr>
106 *    <tr>
107 *       <td>
108 *          <code>Enum</code>
109 *       </td>
110 *       <td>
111 *          <code>String</code>
112 *       </td>
113 *       <td>&nbsp;</td>
114 *    </tr>
115 *    <tr>
116 *       <td>
117 *          Bean
118 *       </td>
119 *       <td>
120 *          <code>Map</code>
121 *       </td>
122 *       <td>&nbsp;</td>
123 *    </tr>
124 *    <tr>
125 *       <td>
126 *          <code>String</code>
127 *       </td>
128 *       <td>
129 *          Anything
130 *       </td>
131 *       <td>
132 *          Arrays are converted to JSON arrays
133 *       </td>
134 *    </tr>
135 *    <tr>
136 *       <td>
137 *          Anything with one of the following methods:
138 *          <br><code><jk>public static</jk> T fromString(String)</code>
139 *          <br><code><jk>public static</jk> T valueOf(String)</code>
140 *          <br><code><jk>public</jk> T(String)</code>
141 *       </td>
142 *       <td>
143 *          <code>String</code>
144 *       </td>
145 *       <td>
146 *          <br>
147 *       </td>
148 *    </tr>
149 * </table>
150 */
151public final class ObjectUtils {
152
153   // Session objects are usually not thread safe, but we're not using any feature
154   // of bean sessions that would cause thread safety issues.
155   private static final BeanSession session = BeanContext.DEFAULT.createSession();
156
157   /**
158    * Converts the specified object to the specified type.
159    * 
160    * @param <T> The class type to convert the value to.
161    * @param value The value to convert.
162    * @param type The class type to convert the value to.
163    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
164    * @return The converted value.
165    */
166   public static <T> T toType(Object value, Class<T> type) {
167      return session.convertToType(value, type);
168   }
169
170
171   /**
172    * Converts the specified object to the specified type.
173    * 
174    * @param <T> The class type to convert the value to.
175    * @param value The value to convert.
176    * @param type The class type to convert the value to.
177    * @param args The type arguments.
178    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
179    * @return The converted value.
180    */
181   public static <T> T toType(Object value, Class<T> type, Type...args) {
182      return session.convertToType(value, type, args);
183   }
184
185   /**
186    * Converts the specified object to the specified type.
187    * 
188    * @param <T> The class type to convert the value to.
189    * @param outer
190    *    If class is a member class, this is the instance of the containing class.
191    *    Should be <jk>null</jk> if not a member class.
192    * @param value The value to convert.
193    * @param type The class type to convert the value to.
194    * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type.
195    * @return The converted value.
196    */
197   public static <T> T toMemberType(Object outer, Object value, Class<T> type) {
198      return session.convertToMemberType(outer, value, type);
199   }
200
201   /**
202    * Returns <jk>true</jk> if the specified objects are equal.
203    * 
204    * <p>
205    * Gracefully handles <jk>null</jk>s.
206    * 
207    * @param o1 Object #1
208    * @param o2 Object #2
209    * @return <jk>true</jk> if the objects are equal or both <jk>null</jk>.
210    */
211   public static boolean equals(Object o1, Object o2) {
212      if (o1 == null && o2 == null)
213         return true;
214      if (o1 == null || o2 == null)
215         return false;
216      return o1.equals(o2);
217   }
218
219   /**
220    * Returns <jk>true</jk> if the specified object is empty.
221    * 
222    * <p>
223    * Return <jk>true</jk> if the value is any of the following:
224    * <ul>
225    *    <li><jk>null</jk>
226    *    <li>An empty Collection
227    *    <li>An empty Map
228    *    <li>An empty array
229    *    <li>An empty CharSequence
230    *    <li>An empty String when serialized to a string using {@link Object#toString()}.
231    * </ul>
232    * 
233    * @param o The object to test.
234    * @return <jk>true</jk> if the specified object is empty.
235    */
236   @SuppressWarnings("rawtypes")
237   public static boolean isEmpty(Object o) {
238      if (o == null)
239         return true;
240      if (o instanceof Collection)
241         return ((Collection)o).isEmpty();
242      if (o instanceof Map)
243         return ((Map)o).isEmpty();
244      if (o.getClass().isArray())
245         return (Array.getLength(o) == 0);
246      return o.toString().isEmpty();
247   }
248   
249   /**
250    * Returns the first non-null value in the specified array
251    * 
252    * @param t
253    * @return The first non-null value, or <jk>null</jk> if the array is null or empty or contains only <jk>null</jk> values.
254    */
255   public static <T> T firstNonNull(T[] t) {
256      if (t != null)
257         for (T tt : t)
258            if (tt != null)
259               return tt;
260      return null;
261   }
262   
263   /**
264    * Converts an object to a Boolean.
265    * 
266    * @param o The object to convert.
267    * @return The converted object.
268    */
269   public static Boolean toBoolean(Object o) {
270      return toType(o, Boolean.class);
271   }
272
273   /**
274    * Converts an object to an Integer.
275    * 
276    * @param o The object to convert.
277    * @return The converted object.
278    */
279   public static Integer toInteger(Object o) {
280      return toType(o, Integer.class);
281   }
282
283   /**
284    * Converts an object to a Number.
285    * 
286    * @param o The object to convert.
287    * @return The converted object.
288    */
289   public static Number toNumber(Object o) {
290      if (o == null)
291         return null;
292      if (o instanceof Number)
293         return (Number)o;
294      try {
295         return StringUtils.parseNumber(o.toString(), null);
296      } catch (ParseException e) {
297         throw new RuntimeException(e);
298      }
299   }
300}