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.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.StringUtils.*; 021import static org.apache.juneau.commons.utils.ThrowableUtils.*; 022 023import java.util.*; 024 025import org.apache.juneau.*; 026import org.apache.juneau.commons.collections.*; 027import org.apache.juneau.parser.*; 028import org.apache.juneau.swap.*; 029import org.apache.juneau.utils.*; 030 031/** 032 * Utility class for efficiently converting objects between types. 033 * 034 * <p> 035 * If the value isn't an instance of the specified type, then converts the value if possible. 036 * 037 * <p> 038 * The following conversions are valid: 039 * <table class='styled'> 040 * <tr><th>Convert to type</th><th>Valid input value types</th><th>Notes</th></tr> 041 * <tr> 042 * <td> 043 * A class that is the normal type of a registered {@link ObjectSwap}. 044 * </td> 045 * <td> 046 * A value whose class matches the transformed type of that registered {@link ObjectSwap}. 047 * </td> 048 * <td> </td> 049 * </tr> 050 * <tr> 051 * <td> 052 * A class that is the transformed type of a registered {@link ObjectSwap}. 053 * </td> 054 * <td> 055 * A value whose class matches the normal type of that registered {@link ObjectSwap}. 056 * </td> 057 * <td> </td> 058 * </tr> 059 * <tr> 060 * <td> 061 * {@code Number} (e.g. {@code Integer}, {@code Short}, {@code Float},...) 062 * <br><code>Number.<jsf>TYPE</jsf></code> (e.g. <code>Integer.<jsf>TYPE</jsf></code>, 063 * <code>Short.<jsf>TYPE</jsf></code>, <code>Float.<jsf>TYPE</jsf></code>,...) 064 * </td> 065 * <td> 066 * {@code Number}, {@code String}, <jk>null</jk> 067 * </td> 068 * <td> 069 * For primitive {@code TYPES}, <jk>null</jk> returns the JVM default value for that type. 070 * </td> 071 * </tr> 072 * <tr> 073 * <td> 074 * {@code Map} (e.g. {@code Map}, {@code HashMap}, {@code TreeMap}, {@code JsonMap}) 075 * </td> 076 * <td> 077 * {@code Map} 078 * </td> 079 * <td> 080 * If {@code Map} is not constructible, an {@code JsonMap} is created. 081 * </td> 082 * </tr> 083 * <tr> 084 * <td> 085 * <c>Collection</c> (e.g. <c>List</c>, <c>LinkedList</c>, <c>HashSet</c>, <c>JsonList</c>) 086 * </td> 087 * <td> 088 * <c>Collection<Object></c> 089 * <br><c>Object[]</c> 090 * </td> 091 * <td> 092 * If <c>Collection</c> is not constructible, a <c>JsonList</c> is created. 093 * </td> 094 * </tr> 095 * <tr> 096 * <td> 097 * <c>X[]</c> (array of any type X) 098 * </td> 099 * <td> 100 * <c>List<X></c> 101 * </td> 102 * <td> </td> 103 * </tr> 104 * <tr> 105 * <td> 106 * <c>X[][]</c> (multi-dimensional arrays) 107 * </td> 108 * <td> 109 * <c>List<List<X>></c> 110 * <br><c>List<X[]></c> 111 * <br><c> List[]<X></c> 112 * </td> 113 * <td> </td> 114 * </tr> 115 * <tr> 116 * <td> 117 * <c>Enum</c> 118 * </td> 119 * <td> 120 * <c>String</c> 121 * </td> 122 * <td> </td> 123 * </tr> 124 * <tr> 125 * <td> 126 * Bean 127 * </td> 128 * <td> 129 * <c>Map</c> 130 * </td> 131 * <td> </td> 132 * </tr> 133 * <tr> 134 * <td> 135 * <c>String</c> 136 * </td> 137 * <td> 138 * Anything 139 * </td> 140 * <td> 141 * Arrays are converted to JSON arrays 142 * </td> 143 * </tr> 144 * <tr> 145 * <td> 146 * Anything with one of the following methods: 147 * <br><code><jk>public static</jk> T fromString(String)</code> 148 * <br><code><jk>public static</jk> T valueOf(String)</code> 149 * <br><code><jk>public</jk> T(String)</code> 150 * </td> 151 * <td> 152 * <c>String</c> 153 * </td> 154 * <td> 155 * <br> 156 * </td> 157 * </tr> 158 * </table> 159 * 160 */ 161public class ConverterUtils { 162 163 // Session objects are usually not thread safe, but we're not using any feature 164 // of bean sessions that would cause thread safety issues. 165 private static final BeanSession session = BeanContext.DEFAULT_SESSION; 166 167 /** 168 * Converts an object to a Boolean. 169 * 170 * @param o The object to convert. 171 * @return The converted object. 172 */ 173 public static Boolean toBoolean(Object o) { 174 return toType(o, Boolean.class); 175 } 176 177 /** 178 * Converts an object to an Integer. 179 * 180 * @param o The object to convert. 181 * @return The converted object. 182 */ 183 public static Integer toInteger(Object o) { 184 return toType(o, Integer.class); 185 } 186 187 /** 188 * Converts an object to a Number. 189 * 190 * @param o The object to convert. 191 * @return The converted object. 192 */ 193 public static Number toNumber(Object o) { 194 if (o == null) 195 return null; 196 if (o instanceof Number o2) 197 return o2; 198 try { 199 return parseNumber(o.toString(), null); 200 } catch (ParseException e) { 201 throw toRex(e); 202 } 203 } 204 205 /** 206 * Converts the specified object to the specified type. 207 * 208 * @param <T> The class type to convert the value to. 209 * @param value The value to convert. 210 * @param type The class type to convert the value to. 211 * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type. 212 * @return The converted value. 213 */ 214 public static <T> T toType(Object value, Class<T> type) { 215 return session.convertToType(value, type); 216 } 217 218 /** 219 * Converts the specified object to a {@link Lists} with elements of the specified type. 220 * 221 * <p> 222 * The input value can be any of the following: 223 * <ul> 224 * <li>An array of objects convertible to the element type 225 * <li>A {@link Collection} of objects convertible to the element type 226 * <li>A single object convertible to the element type (creates a list with one element) 227 * <li>A JSON array string that can be parsed into objects of the element type 228 * </ul> 229 * 230 * @param <T> The element type. 231 * @param value The value to convert. Can be <jk>null</jk>. 232 * @param type The element type class. 233 * @return A new {@link Lists} containing the converted elements. 234 */ 235 public static <T> Lists<T> toListBuilder(Object value, Class<T> type) { 236 return listb(type).elementFunction(o -> GenericConverter.INSTANCE.convertTo(type, o)).addAny(value); 237 } 238 239 /** 240 * Converts the specified object to a {@link Maps} with keys and values of the specified types. 241 * 242 * <p> 243 * The input value can be any of the following: 244 * <ul> 245 * <li>A {@link java.util.Map Map} with entries convertible to the key/value types 246 * <li>A JSON object string that can be parsed into a map with the specified key/value types 247 * <li>An object with bean properties that can be converted to map entries 248 * </ul> 249 * 250 * @param <K> The key type. 251 * @param <V> The value type. 252 * @param value The value to convert. Can be <jk>null</jk>. 253 * @param keyType The key type class. 254 * @param valueType The value type class. 255 * @return A new {@link Maps} containing the converted entries. 256 */ 257 public static <K,V> Maps<K,V> toMapBuilder(Object value, Class<K> keyType, Class<V> valueType) { 258 return mapb(keyType, valueType) 259 .keyFunction(o -> GenericConverter.INSTANCE.convertTo(keyType, o)) 260 .valueFunction(o -> GenericConverter.INSTANCE.convertTo(valueType, o)) 261 .addAny(value); 262 } 263 264 /** 265 * Converts the specified object to a {@link Sets} with elements of the specified type. 266 * 267 * <p> 268 * The input value can be any of the following: 269 * <ul> 270 * <li>An array of objects convertible to the element type 271 * <li>A {@link Collection} of objects convertible to the element type 272 * <li>A single object convertible to the element type (creates a set with one element) 273 * <li>A JSON array string that can be parsed into objects of the element type 274 * </ul> 275 * 276 * <p> 277 * Duplicate elements (after conversion) will be automatically removed as per {@link java.util.Set Set} semantics. 278 * 279 * @param <T> The element type. 280 * @param value The value to convert. Can be <jk>null</jk>. 281 * @param type The element type class. 282 * @return A new {@link Sets} containing the converted elements. 283 */ 284 public static <T> Sets<T> toSetBuilder(Object value, Class<T> type) { 285 return setb(type).elementFunction(o -> GenericConverter.INSTANCE.convertTo(type, o)).addAny(value); 286 } 287}