/src/main/java/com/alibaba/fastjson/util/TypeUtils.java

https://github.com/flydream/fastjson · Java · 855 lines · 647 code · 185 blank · 23 comment · 253 complexity · 31dbb954b3e23de07feaca620551bb02 MD5 · raw file

  1. /*
  2. * Copyright 1999-2101 Alibaba Group.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.alibaba.fastjson.util;
  17. import java.lang.reflect.Array;
  18. import java.lang.reflect.Field;
  19. import java.lang.reflect.Method;
  20. import java.lang.reflect.Modifier;
  21. import java.lang.reflect.ParameterizedType;
  22. import java.lang.reflect.Proxy;
  23. import java.lang.reflect.Type;
  24. import java.lang.reflect.TypeVariable;
  25. import java.lang.reflect.WildcardType;
  26. import java.math.BigDecimal;
  27. import java.math.BigInteger;
  28. import java.util.ArrayList;
  29. import java.util.Calendar;
  30. import java.util.Collection;
  31. import java.util.Date;
  32. import java.util.HashMap;
  33. import java.util.Iterator;
  34. import java.util.LinkedHashMap;
  35. import java.util.List;
  36. import java.util.Map;
  37. import com.alibaba.fastjson.JSONException;
  38. import com.alibaba.fastjson.JSONObject;
  39. import com.alibaba.fastjson.annotation.JSONField;
  40. import com.alibaba.fastjson.parser.ParserConfig;
  41. import com.alibaba.fastjson.parser.deserializer.FieldDeserializer;
  42. /**
  43. * @author wenshao<szujobs@hotmail.com>
  44. */
  45. public class TypeUtils {
  46. public static final String castToString(Object value) {
  47. if (value == null) {
  48. return null;
  49. }
  50. return value.toString();
  51. }
  52. public static final Byte castToByte(Object value) {
  53. if (value == null) {
  54. return null;
  55. }
  56. if (value instanceof Number) {
  57. return ((Number) value).byteValue();
  58. }
  59. if (value instanceof String) {
  60. String strVal = (String) value;
  61. if (strVal.length() == 0) {
  62. return null;
  63. }
  64. return Byte.parseByte(strVal);
  65. }
  66. throw new JSONException("can not cast to byte, value : " + value);
  67. }
  68. public static final Character castToChar(Object value) {
  69. if (value == null) {
  70. return null;
  71. }
  72. if (value instanceof Character) {
  73. return (Character) value;
  74. }
  75. if (value instanceof String) {
  76. String strVal = (String) value;
  77. if (strVal.length() == 0) {
  78. return null;
  79. }
  80. if (strVal.length() != 1) {
  81. throw new JSONException("can not cast to byte, value : " + value);
  82. }
  83. return strVal.charAt(0);
  84. }
  85. throw new JSONException("can not cast to byte, value : " + value);
  86. }
  87. public static final Short castToShort(Object value) {
  88. if (value == null) {
  89. return null;
  90. }
  91. if (value instanceof Number) {
  92. return ((Number) value).shortValue();
  93. }
  94. if (value instanceof String) {
  95. String strVal = (String) value;
  96. if (strVal.length() == 0) {
  97. return null;
  98. }
  99. return Short.parseShort(strVal);
  100. }
  101. throw new JSONException("can not cast to short, value : " + value);
  102. }
  103. public static final BigDecimal castToBigDecimal(Object value) {
  104. if (value == null) {
  105. return null;
  106. }
  107. if (value instanceof BigDecimal) {
  108. return (BigDecimal) value;
  109. }
  110. if (value instanceof BigInteger) {
  111. return new BigDecimal((BigInteger) value);
  112. }
  113. String strVal = value.toString();
  114. if (strVal.length() == 0) {
  115. return null;
  116. }
  117. return new BigDecimal(strVal);
  118. }
  119. public static final BigInteger castToBigInteger(Object value) {
  120. if (value == null) {
  121. return null;
  122. }
  123. if (value instanceof BigInteger) {
  124. return (BigInteger) value;
  125. }
  126. String strVal = value.toString();
  127. if (strVal.length() == 0) {
  128. return null;
  129. }
  130. return new BigInteger(strVal);
  131. }
  132. public static final Float castToFloat(Object value) {
  133. if (value == null) {
  134. return null;
  135. }
  136. if (value instanceof Number) {
  137. return ((Number) value).floatValue();
  138. }
  139. if (value instanceof String) {
  140. String strVal = value.toString();
  141. if (strVal.length() == 0) {
  142. return null;
  143. }
  144. return Float.parseFloat(strVal);
  145. }
  146. throw new JSONException("can not cast to float, value : " + value);
  147. }
  148. public static final Double castToDouble(Object value) {
  149. if (value == null) {
  150. return null;
  151. }
  152. if (value instanceof Number) {
  153. return ((Number) value).doubleValue();
  154. }
  155. if (value instanceof String) {
  156. String strVal = value.toString();
  157. if (strVal.length() == 0) {
  158. return null;
  159. }
  160. return Double.parseDouble(strVal);
  161. }
  162. throw new JSONException("can not cast to double, value : " + value);
  163. }
  164. public static final Date castToDate(Object value) {
  165. if (value == null) {
  166. return null;
  167. }
  168. if (value instanceof Calendar) {
  169. return ((Calendar) value).getTime();
  170. }
  171. if (value instanceof Date) {
  172. return (Date) value;
  173. }
  174. long longValue = 0;
  175. if (value instanceof Number) {
  176. longValue = ((Number) value).longValue();
  177. }
  178. if (value instanceof String) {
  179. String strVal = (String) value;
  180. if (strVal.length() == 0) {
  181. return null;
  182. }
  183. longValue = Long.parseLong(strVal);
  184. }
  185. if (longValue <= 0) {
  186. throw new JSONException("can not cast to Date, value : " + value);
  187. }
  188. return new Date(longValue);
  189. }
  190. public static final java.sql.Date castToSqlDate(Object value) {
  191. if (value == null) {
  192. return null;
  193. }
  194. if (value instanceof Calendar) {
  195. return new java.sql.Date(((Calendar) value).getTimeInMillis());
  196. }
  197. if (value instanceof java.sql.Date) {
  198. return (java.sql.Date) value;
  199. }
  200. if (value instanceof java.util.Date) {
  201. return new java.sql.Date(((java.util.Date) value).getTime());
  202. }
  203. long longValue = 0;
  204. if (value instanceof Number) {
  205. longValue = ((Number) value).longValue();
  206. }
  207. if (value instanceof String) {
  208. String strVal = (String) value;
  209. if (strVal.length() == 0) {
  210. return null;
  211. }
  212. longValue = Long.parseLong(strVal);
  213. }
  214. if (longValue <= 0) {
  215. throw new JSONException("can not cast to Date, value : " + value);
  216. }
  217. return new java.sql.Date(longValue);
  218. }
  219. public static final java.sql.Timestamp castToTimestamp(Object value) {
  220. if (value == null) {
  221. return null;
  222. }
  223. if (value instanceof Calendar) {
  224. return new java.sql.Timestamp(((Calendar) value).getTimeInMillis());
  225. }
  226. if (value instanceof java.sql.Timestamp) {
  227. return (java.sql.Timestamp) value;
  228. }
  229. if (value instanceof java.util.Date) {
  230. return new java.sql.Timestamp(((java.util.Date) value).getTime());
  231. }
  232. long longValue = 0;
  233. if (value instanceof Number) {
  234. longValue = ((Number) value).longValue();
  235. }
  236. if (value instanceof String) {
  237. String strVal = (String) value;
  238. if (strVal.length() == 0) {
  239. return null;
  240. }
  241. longValue = Long.parseLong(strVal);
  242. }
  243. if (longValue <= 0) {
  244. throw new JSONException("can not cast to Date, value : " + value);
  245. }
  246. return new java.sql.Timestamp(longValue);
  247. }
  248. public static final Long castToLong(Object value) {
  249. if (value == null) {
  250. return null;
  251. }
  252. if (value instanceof Number) {
  253. return ((Number) value).longValue();
  254. }
  255. if (value instanceof String) {
  256. String strVal = (String) value;
  257. if (strVal.length() == 0) {
  258. return null;
  259. }
  260. return Long.parseLong(strVal);
  261. }
  262. throw new JSONException("can not cast to long, value : " + value);
  263. }
  264. public static final Integer castToInt(Object value) {
  265. if (value == null) {
  266. return null;
  267. }
  268. if (value instanceof Integer) {
  269. return (Integer) value;
  270. }
  271. if (value instanceof Number) {
  272. return ((Number) value).intValue();
  273. }
  274. if (value instanceof String) {
  275. String strVal = (String) value;
  276. if (strVal.length() == 0) {
  277. return null;
  278. }
  279. return Integer.parseInt(strVal);
  280. }
  281. throw new JSONException("can not cast to int, value : " + value);
  282. }
  283. public static final byte[] castToBytes(Object value) {
  284. if (value instanceof byte[]) {
  285. return (byte[]) value;
  286. }
  287. if (value instanceof String) {
  288. return Base64.decodeFast((String) value);
  289. }
  290. throw new JSONException("can not cast to int, value : " + value);
  291. }
  292. public static final Boolean castToBoolean(Object value) {
  293. if (value == null) {
  294. return null;
  295. }
  296. if (value instanceof Boolean) {
  297. return (Boolean) value;
  298. }
  299. if (value instanceof Number) {
  300. return ((Number) value).intValue() == 1;
  301. }
  302. if (value instanceof String) {
  303. String str = (String) value;
  304. if (str.length() == 0) {
  305. return null;
  306. }
  307. if ("true".equals(str)) {
  308. return Boolean.TRUE;
  309. }
  310. if ("false".equals(str)) {
  311. return Boolean.FALSE;
  312. }
  313. if ("1".equals(str)) {
  314. return Boolean.TRUE;
  315. }
  316. }
  317. throw new JSONException("can not cast to int, value : " + value);
  318. }
  319. public static final <T> T castToJavaBean(Object obj, Class<T> clazz) {
  320. return cast(obj, clazz, ParserConfig.getGlobalInstance());
  321. }
  322. @SuppressWarnings({ "unchecked", "rawtypes" })
  323. public static final <T> T cast(Object obj, Class<T> clazz, ParserConfig mapping) {
  324. if (obj == null) {
  325. return null;
  326. }
  327. if (clazz == obj.getClass()) {
  328. return (T) obj;
  329. }
  330. if (obj instanceof Map) {
  331. if (clazz == Map.class) {
  332. return (T) obj;
  333. }
  334. return castToJavaBean((Map<String, Object>) obj, clazz, mapping);
  335. }
  336. if (clazz.isArray()) {
  337. if (obj instanceof Collection) {
  338. Collection collection = (Collection) obj;
  339. int index = 0;
  340. Object array = Array.newInstance(clazz.getComponentType(), collection.size());
  341. for (Object item : collection) {
  342. Object value = cast(item, clazz.getComponentType(), mapping);
  343. Array.set(array, index, value);
  344. index++;
  345. }
  346. return (T) array;
  347. }
  348. }
  349. if (clazz.isAssignableFrom(obj.getClass())) {
  350. return (T) obj;
  351. }
  352. if (clazz == boolean.class || clazz == Boolean.class) {
  353. return (T) castToBoolean(obj);
  354. }
  355. if (clazz == byte.class || clazz == Byte.class) {
  356. return (T) castToByte(obj);
  357. }
  358. // if (clazz == char.class || clazz == Character.class) {
  359. // return (T) castToCharacter(obj);
  360. // }
  361. if (clazz == short.class || clazz == Short.class) {
  362. return (T) castToShort(obj);
  363. }
  364. if (clazz == int.class || clazz == Integer.class) {
  365. return (T) castToInt(obj);
  366. }
  367. if (clazz == long.class || clazz == Long.class) {
  368. return (T) castToLong(obj);
  369. }
  370. if (clazz == float.class || clazz == Float.class) {
  371. return (T) castToFloat(obj);
  372. }
  373. if (clazz == double.class || clazz == Double.class) {
  374. return (T) castToDouble(obj);
  375. }
  376. if (clazz == String.class) {
  377. return (T) castToString(obj);
  378. }
  379. if (clazz == BigDecimal.class) {
  380. return (T) castToBigDecimal(obj);
  381. }
  382. if (clazz == BigInteger.class) {
  383. return (T) castToBigInteger(obj);
  384. }
  385. if (clazz == Date.class) {
  386. return (T) castToDate(obj);
  387. }
  388. if (clazz == java.sql.Date.class) {
  389. return (T) castToSqlDate(obj);
  390. }
  391. if (clazz == java.sql.Timestamp.class) {
  392. return (T) castToTimestamp(obj);
  393. }
  394. if (clazz.isEnum()) {
  395. return (T) castToEnum(obj, clazz, mapping);
  396. }
  397. if (obj instanceof String) {
  398. String strVal = (String) obj;
  399. if (strVal.length() == 0) {
  400. return null;
  401. }
  402. }
  403. throw new JSONException("can not cast to : " + clazz.getName());
  404. }
  405. @SuppressWarnings({ "unchecked", "rawtypes" })
  406. public static final <T> T castToEnum(Object obj, Class<T> clazz, ParserConfig mapping) {
  407. try {
  408. if (obj instanceof String) {
  409. String name = (String) obj;
  410. if (name.length() == 0) {
  411. return null;
  412. }
  413. return (T) Enum.valueOf((Class<? extends Enum>) clazz, name);
  414. }
  415. if (obj instanceof Number) {
  416. int ordinal = ((Number) obj).intValue();
  417. Method method = clazz.getMethod("values");
  418. Object[] values = (Object[]) method.invoke(null);
  419. for (Object value : values) {
  420. Enum e = (Enum) value;
  421. if (e.ordinal() == ordinal) {
  422. return (T) e;
  423. }
  424. }
  425. }
  426. } catch (Exception ex) {
  427. throw new JSONException("can not cast to : " + clazz.getName(), ex);
  428. }
  429. throw new JSONException("can not cast to : " + clazz.getName());
  430. }
  431. @SuppressWarnings("unchecked")
  432. public static final <T> T cast(Object obj, Type type, ParserConfig mapping) {
  433. if (obj == null) {
  434. return null;
  435. }
  436. if (type instanceof Class) {
  437. return (T) cast(obj, (Class<T>) type, mapping);
  438. }
  439. if (type instanceof ParameterizedType) {
  440. return (T) cast(obj, (ParameterizedType) type, mapping);
  441. }
  442. if (obj instanceof String) {
  443. String strVal = (String) obj;
  444. if (strVal.length() == 0) {
  445. return null;
  446. }
  447. }
  448. if (type instanceof TypeVariable) {
  449. return (T) obj;
  450. }
  451. throw new JSONException("can not cast to : " + type);
  452. }
  453. @SuppressWarnings({ "rawtypes", "unchecked" })
  454. public static final <T> T cast(Object obj, ParameterizedType type, ParserConfig mapping) {
  455. Type rawTye = type.getRawType();
  456. if (rawTye == List.class || rawTye == ArrayList.class) {
  457. Type itemType = type.getActualTypeArguments()[0];
  458. if (obj instanceof Iterable) {
  459. List list = new ArrayList();
  460. for (Iterator it = ((Iterable) obj).iterator(); it.hasNext();) {
  461. Object item = it.next();
  462. list.add(cast(item, itemType, mapping));
  463. }
  464. return (T) list;
  465. }
  466. }
  467. if (rawTye == Map.class || rawTye == HashMap.class) {
  468. Type keyType = type.getActualTypeArguments()[0];
  469. Type valueType = type.getActualTypeArguments()[1];
  470. if (obj instanceof Map) {
  471. Map map = new HashMap();
  472. for (Map.Entry entry : ((Map<?, ?>) obj).entrySet()) {
  473. Object key = cast(entry.getKey(), keyType, mapping);
  474. Object value = cast(entry.getValue(), valueType, mapping);
  475. map.put(key, value);
  476. }
  477. return (T) map;
  478. }
  479. }
  480. if (obj instanceof String) {
  481. String strVal = (String) obj;
  482. if (strVal.length() == 0) {
  483. return null;
  484. }
  485. }
  486. if (type.getActualTypeArguments().length == 1) {
  487. Type argType = type.getActualTypeArguments()[0];
  488. if (argType instanceof WildcardType) {
  489. return (T) cast(obj, rawTye, mapping);
  490. }
  491. }
  492. throw new JSONException("can not cast to : " + type);
  493. }
  494. @SuppressWarnings({ "unchecked" })
  495. public static final <T> T castToJavaBean(Map<String, Object> map, Class<T> clazz, ParserConfig mapping) {
  496. try {
  497. if (clazz == StackTraceElement.class) {
  498. String declaringClass = (String) map.get("className");
  499. String methodName = (String) map.get("methodName");
  500. String fileName = (String) map.get("fileName");
  501. int lineNumber;
  502. {
  503. Number value = (Number) map.get("lineNumber");
  504. if (value == null) {
  505. lineNumber = 0;
  506. } else {
  507. lineNumber = value.intValue();
  508. }
  509. }
  510. return (T) new StackTraceElement(declaringClass, methodName, fileName, lineNumber);
  511. }
  512. {
  513. Object iClassObject = map.get("@type");
  514. if (iClassObject instanceof String) {
  515. String className = (String) iClassObject;
  516. clazz = (Class<T>) loadClass(className);
  517. }
  518. }
  519. if (clazz.isInterface()) {
  520. JSONObject object;
  521. if (map instanceof JSONObject) {
  522. object = (JSONObject) map;
  523. } else {
  524. object = new JSONObject(map);
  525. }
  526. return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
  527. new Class<?>[] { clazz }, object);
  528. }
  529. Map<String, FieldDeserializer> setters = mapping.getFieldDeserializers(clazz);
  530. T object = clazz.newInstance();
  531. for (Map.Entry<String, FieldDeserializer> entry : setters.entrySet()) {
  532. String key = entry.getKey();
  533. Method method = entry.getValue().getMethod();
  534. if (map.containsKey(key)) {
  535. Object value = map.get(key);
  536. value = cast(value, method.getGenericParameterTypes()[0], mapping);
  537. method.invoke(object, new Object[] { value });
  538. }
  539. }
  540. return object;
  541. } catch (Exception e) {
  542. throw new JSONException(e.getMessage(), e);
  543. }
  544. }
  545. public static Class<?> loadClass(String className) {
  546. Class<?> clazz = null;
  547. try {
  548. clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
  549. return clazz;
  550. } catch (Throwable e) {
  551. // skip
  552. }
  553. try {
  554. clazz = Class.forName(className);
  555. return clazz;
  556. } catch (Throwable e) {
  557. // skip
  558. }
  559. return clazz;
  560. }
  561. public static List<FieldInfo> computeGetters(Class<?> clazz, Map<String, String> aliasMap) {
  562. List<FieldInfo> fieldInfoList = new ArrayList<FieldInfo>();
  563. Map<String, FieldInfo> fieldInfoMap = new LinkedHashMap<String, FieldInfo>();
  564. for (Method method : clazz.getMethods()) {
  565. String methodName = method.getName();
  566. if (Modifier.isStatic(method.getModifiers())) {
  567. continue;
  568. }
  569. if (method.getReturnType().equals(Void.TYPE)) {
  570. continue;
  571. }
  572. if (method.getParameterTypes().length != 0) {
  573. continue;
  574. }
  575. JSONField annotation = method.getAnnotation(JSONField.class);
  576. if (annotation != null) {
  577. if (!annotation.serialize()) {
  578. continue;
  579. }
  580. if (annotation.name().length() != 0) {
  581. String propertyName = annotation.name();
  582. if (aliasMap != null) {
  583. propertyName = aliasMap.get(propertyName);
  584. if (propertyName == null) {
  585. continue;
  586. }
  587. }
  588. fieldInfoMap.put(propertyName, new FieldInfo(propertyName, method, null));
  589. continue;
  590. }
  591. }
  592. if (methodName.startsWith("get")) {
  593. if (methodName.length() < 4) {
  594. continue;
  595. }
  596. if (methodName.equals("getClass")) {
  597. continue;
  598. }
  599. if (!Character.isUpperCase(methodName.charAt(3))) {
  600. continue;
  601. }
  602. String propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
  603. Field field = ParserConfig.getField(clazz, propertyName);
  604. if (field != null) {
  605. JSONField fieldAnnotation = field.getAnnotation(JSONField.class);
  606. if (fieldAnnotation != null && fieldAnnotation.name().length() != 0) {
  607. propertyName = fieldAnnotation.name();
  608. if (aliasMap != null) {
  609. propertyName = aliasMap.get(propertyName);
  610. if (propertyName == null) {
  611. continue;
  612. }
  613. }
  614. }
  615. }
  616. if (aliasMap != null) {
  617. propertyName = aliasMap.get(propertyName);
  618. if (propertyName == null) {
  619. continue;
  620. }
  621. }
  622. fieldInfoMap.put(propertyName, new FieldInfo(propertyName, method, field));
  623. }
  624. if (methodName.startsWith("is")) {
  625. if (methodName.length() < 3) {
  626. continue;
  627. }
  628. if (!Character.isUpperCase(methodName.charAt(2))) {
  629. continue;
  630. }
  631. String propertyName = Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3);
  632. Field field = ParserConfig.getField(clazz, propertyName);
  633. if (field != null) {
  634. JSONField fieldAnnotation = field.getAnnotation(JSONField.class);
  635. if (fieldAnnotation != null && fieldAnnotation.name().length() != 0) {
  636. propertyName = fieldAnnotation.name();
  637. if (aliasMap != null) {
  638. propertyName = aliasMap.get(propertyName);
  639. if (propertyName == null) {
  640. continue;
  641. }
  642. }
  643. }
  644. }
  645. if (aliasMap != null) {
  646. propertyName = aliasMap.get(propertyName);
  647. if (propertyName == null) {
  648. continue;
  649. }
  650. }
  651. fieldInfoMap.put(propertyName, new FieldInfo(propertyName, method, field));
  652. }
  653. }
  654. for (Field field : clazz.getFields()) {
  655. if (Modifier.isStatic(field.getModifiers())) {
  656. continue;
  657. }
  658. if (!Modifier.isPublic(field.getModifiers())) {
  659. continue;
  660. }
  661. if (!fieldInfoMap.containsKey(field.getName())) {
  662. fieldInfoMap.put(field.getName(), new FieldInfo(field.getName(), null, field));
  663. }
  664. }
  665. for (FieldInfo fieldInfo : fieldInfoMap.values()) {
  666. fieldInfoList.add(fieldInfo);
  667. }
  668. return fieldInfoList;
  669. }
  670. }