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> </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> </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<Object></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<X></code> 092 * </td> 093 * <td> </td> 094 * </tr> 095 * <tr> 096 * <td> 097 * <code>X[][]</code> (multi-dimensional arrays) 098 * </td> 099 * <td> 100 * <code>List<List<X>></code> 101 * <br><code>List<X[]></code> 102 * <br><code> List[]<X></code> 103 * </td> 104 * <td> </td> 105 * </tr> 106 * <tr> 107 * <td> 108 * <code>Enum</code> 109 * </td> 110 * <td> 111 * <code>String</code> 112 * </td> 113 * <td> </td> 114 * </tr> 115 * <tr> 116 * <td> 117 * Bean 118 * </td> 119 * <td> 120 * <code>Map</code> 121 * </td> 122 * <td> </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}