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

https://github.com/alibaba/fastjson · Java · 1155 lines · 939 code · 195 blank · 21 comment · 429 complexity · e4606976b6c6f09b63f22e84ec15040b MD5 · raw file

  1. package com.alibaba.fastjson.util;
  2. import java.lang.annotation.Annotation;
  3. import java.lang.reflect.*;
  4. import java.util.*;
  5. import java.util.concurrent.atomic.AtomicBoolean;
  6. import java.util.concurrent.atomic.AtomicInteger;
  7. import java.util.concurrent.atomic.AtomicLong;
  8. import com.alibaba.fastjson.JSON;
  9. import com.alibaba.fastjson.JSONException;
  10. import com.alibaba.fastjson.PropertyNamingStrategy;
  11. import com.alibaba.fastjson.annotation.JSONCreator;
  12. import com.alibaba.fastjson.annotation.JSONField;
  13. import com.alibaba.fastjson.annotation.JSONPOJOBuilder;
  14. import com.alibaba.fastjson.annotation.JSONType;
  15. import com.alibaba.fastjson.parser.Feature;
  16. import com.alibaba.fastjson.serializer.SerializerFeature;
  17. public class JavaBeanInfo {
  18. public final Class<?> clazz;
  19. public final Class<?> builderClass;
  20. public final Constructor<?> defaultConstructor;
  21. public final Constructor<?> creatorConstructor;
  22. public final Method factoryMethod;
  23. public final Method buildMethod;
  24. public final int defaultConstructorParameterSize;
  25. public final FieldInfo[] fields;
  26. public final FieldInfo[] sortedFields;
  27. public final int parserFeatures;
  28. public final JSONType jsonType;
  29. public final String typeName;
  30. public final String typeKey;
  31. public String[] orders;
  32. public Type[] creatorConstructorParameterTypes;
  33. public String[] creatorConstructorParameters;
  34. public boolean kotlin;
  35. public Constructor<?> kotlinDefaultConstructor;
  36. public JavaBeanInfo(Class<?> clazz, //
  37. Class<?> builderClass, //
  38. Constructor<?> defaultConstructor, //
  39. Constructor<?> creatorConstructor, //
  40. Method factoryMethod, //
  41. Method buildMethod, //
  42. JSONType jsonType, //
  43. List<FieldInfo> fieldList) {
  44. this.clazz = clazz;
  45. this.builderClass = builderClass;
  46. this.defaultConstructor = defaultConstructor;
  47. this.creatorConstructor = creatorConstructor;
  48. this.factoryMethod = factoryMethod;
  49. this.parserFeatures = TypeUtils.getParserFeatures(clazz);
  50. this.buildMethod = buildMethod;
  51. this.jsonType = jsonType;
  52. if (jsonType != null) {
  53. String typeName = jsonType.typeName();
  54. String typeKey = jsonType.typeKey();
  55. this.typeKey = typeKey.length() > 0 ? typeKey : null;
  56. if (typeName.length() != 0) {
  57. this.typeName = typeName;
  58. } else {
  59. this.typeName = clazz.getName();
  60. }
  61. String[] orders = jsonType.orders();
  62. this.orders = orders.length == 0 ? null : orders;
  63. } else {
  64. this.typeName = clazz.getName();
  65. this.typeKey = null;
  66. this.orders = null;
  67. }
  68. fields = new FieldInfo[fieldList.size()];
  69. fieldList.toArray(fields);
  70. FieldInfo[] sortedFields = new FieldInfo[fields.length];
  71. if (orders != null) {
  72. LinkedHashMap<String, FieldInfo> map = new LinkedHashMap<String, FieldInfo>(fieldList.size());
  73. for (FieldInfo field : fields) {
  74. map.put(field.name, field);
  75. }
  76. int i = 0;
  77. for (String item : orders) {
  78. FieldInfo field = map.get(item);
  79. if (field != null) {
  80. sortedFields[i++] = field;
  81. map.remove(item);
  82. }
  83. }
  84. for (FieldInfo field : map.values()) {
  85. sortedFields[i++] = field;
  86. }
  87. } else {
  88. System.arraycopy(fields, 0, sortedFields, 0, fields.length);
  89. Arrays.sort(sortedFields);
  90. }
  91. if (Arrays.equals(fields, sortedFields)) {
  92. sortedFields = fields;
  93. }
  94. this.sortedFields = sortedFields;
  95. if (defaultConstructor != null) {
  96. defaultConstructorParameterSize = defaultConstructor.getParameterTypes().length;
  97. } else if (factoryMethod != null) {
  98. defaultConstructorParameterSize = factoryMethod.getParameterTypes().length;
  99. } else {
  100. defaultConstructorParameterSize = 0;
  101. }
  102. if (creatorConstructor != null) {
  103. this.creatorConstructorParameterTypes = creatorConstructor.getParameterTypes();
  104. kotlin = TypeUtils.isKotlin(clazz);
  105. if (kotlin) {
  106. this.creatorConstructorParameters = TypeUtils.getKoltinConstructorParameters(clazz);
  107. try {
  108. this.kotlinDefaultConstructor = clazz.getConstructor();
  109. } catch (Throwable ex) {
  110. // skip
  111. }
  112. Annotation[][] paramAnnotationArrays = TypeUtils.getParameterAnnotations(creatorConstructor);
  113. for (int i = 0; i < creatorConstructorParameters.length && i < paramAnnotationArrays.length; ++i) {
  114. Annotation[] paramAnnotations = paramAnnotationArrays[i];
  115. JSONField fieldAnnotation = null;
  116. for (Annotation paramAnnotation : paramAnnotations) {
  117. if (paramAnnotation instanceof JSONField) {
  118. fieldAnnotation = (JSONField) paramAnnotation;
  119. break;
  120. }
  121. }
  122. if (fieldAnnotation != null) {
  123. String fieldAnnotationName = fieldAnnotation.name();
  124. if (fieldAnnotationName.length() > 0) {
  125. creatorConstructorParameters[i] = fieldAnnotationName;
  126. }
  127. }
  128. }
  129. } else {
  130. boolean match;
  131. if (creatorConstructorParameterTypes.length != fields.length) {
  132. match = false;
  133. } else {
  134. match = true;
  135. for (int i = 0; i < creatorConstructorParameterTypes.length; i++) {
  136. if (creatorConstructorParameterTypes[i] != fields[i].fieldClass) {
  137. match = false;
  138. break;
  139. }
  140. }
  141. }
  142. if (!match) {
  143. this.creatorConstructorParameters = ASMUtils.lookupParameterNames(creatorConstructor);
  144. }
  145. }
  146. }
  147. }
  148. private static FieldInfo getField(List<FieldInfo> fieldList, String propertyName) {
  149. for (FieldInfo item : fieldList) {
  150. if (item.name.equals(propertyName)) {
  151. return item;
  152. }
  153. Field field = item.field;
  154. if (field != null && item.getAnnotation() != null && field.getName().equals(propertyName)) {
  155. return item;
  156. }
  157. }
  158. return null;
  159. }
  160. static boolean add(List<FieldInfo> fieldList, FieldInfo field) {
  161. for (int i = fieldList.size() - 1; i >= 0; --i) {
  162. FieldInfo item = fieldList.get(i);
  163. if (item.name.equals(field.name)) {
  164. if (item.getOnly && !field.getOnly) {
  165. continue;
  166. }
  167. if (item.fieldClass.isAssignableFrom(field.fieldClass)) {
  168. fieldList.set(i, field);
  169. return true;
  170. }
  171. int result = item.compareTo(field);
  172. if (result < 0) {
  173. fieldList.set(i, field);
  174. return true;
  175. } else {
  176. return false;
  177. }
  178. }
  179. }
  180. fieldList.add(field);
  181. return true;
  182. }
  183. public static JavaBeanInfo build(Class<?> clazz, Type type, PropertyNamingStrategy propertyNamingStrategy) {
  184. return build(clazz, type, propertyNamingStrategy, false, TypeUtils.compatibleWithJavaBean, false);
  185. }
  186. private static Map<TypeVariable, Type> buildGenericInfo(Class<?> clazz) {
  187. Class<?> childClass = clazz;
  188. Class<?> currentClass = clazz.getSuperclass();
  189. if (currentClass == null) {
  190. return null;
  191. }
  192. Map<TypeVariable, Type> typeVarMap = null;
  193. //analyse the whole generic info from the class inheritance
  194. for (; currentClass != null && currentClass != Object.class; childClass = currentClass, currentClass = currentClass.getSuperclass()) {
  195. if (childClass.getGenericSuperclass() instanceof ParameterizedType) {
  196. Type[] childGenericParentActualTypeArgs = ((ParameterizedType) childClass.getGenericSuperclass()).getActualTypeArguments();
  197. TypeVariable[] currentTypeParameters = currentClass.getTypeParameters();
  198. for (int i = 0; i < childGenericParentActualTypeArgs.length; i++) {
  199. //if the child class's generic super class actual args is defined in the child class type parameters
  200. if (typeVarMap == null) {
  201. typeVarMap = new HashMap<TypeVariable, Type>();
  202. }
  203. if (typeVarMap.containsKey(childGenericParentActualTypeArgs[i])) {
  204. Type actualArg = typeVarMap.get(childGenericParentActualTypeArgs[i]);
  205. typeVarMap.put(currentTypeParameters[i], actualArg);
  206. } else {
  207. typeVarMap.put(currentTypeParameters[i], childGenericParentActualTypeArgs[i]);
  208. }
  209. }
  210. }
  211. }
  212. return typeVarMap;
  213. }
  214. public static JavaBeanInfo build(Class<?> clazz //
  215. , Type type //
  216. , PropertyNamingStrategy propertyNamingStrategy //
  217. , boolean fieldBased //
  218. , boolean compatibleWithJavaBean
  219. ) {
  220. return build(clazz, type, propertyNamingStrategy, fieldBased, compatibleWithJavaBean, false);
  221. }
  222. public static JavaBeanInfo build(Class<?> clazz //
  223. , Type type //
  224. , PropertyNamingStrategy propertyNamingStrategy //
  225. , boolean fieldBased //
  226. , boolean compatibleWithJavaBean
  227. , boolean jacksonCompatible
  228. ) {
  229. JSONType jsonType = TypeUtils.getAnnotation(clazz,JSONType.class);
  230. if (jsonType != null) {
  231. PropertyNamingStrategy jsonTypeNaming = jsonType.naming();
  232. if (jsonTypeNaming != null && jsonTypeNaming != PropertyNamingStrategy.CamelCase) {
  233. propertyNamingStrategy = jsonTypeNaming;
  234. }
  235. }
  236. Class<?> builderClass = getBuilderClass(clazz, jsonType);
  237. Field[] declaredFields = clazz.getDeclaredFields();
  238. Method[] methods = clazz.getMethods();
  239. Map<TypeVariable, Type> genericInfo = buildGenericInfo(clazz);
  240. boolean kotlin = TypeUtils.isKotlin(clazz);
  241. Constructor[] constructors = clazz.getDeclaredConstructors();
  242. Constructor<?> defaultConstructor = null;
  243. if ((!kotlin) || constructors.length == 1) {
  244. if (builderClass == null) {
  245. defaultConstructor = getDefaultConstructor(clazz, constructors);
  246. } else {
  247. defaultConstructor = getDefaultConstructor(builderClass, builderClass.getDeclaredConstructors());
  248. }
  249. }
  250. Constructor<?> creatorConstructor = null;
  251. Method buildMethod = null;
  252. Method factoryMethod = null;
  253. List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
  254. if (fieldBased) {
  255. for (Class<?> currentClass = clazz; currentClass != null; currentClass = currentClass.getSuperclass()) {
  256. Field[] fields = currentClass.getDeclaredFields();
  257. computeFields(clazz, type, propertyNamingStrategy, fieldList, fields);
  258. }
  259. if (defaultConstructor != null) {
  260. TypeUtils.setAccessible(defaultConstructor);
  261. }
  262. return new JavaBeanInfo(clazz, builderClass, defaultConstructor, null, factoryMethod, buildMethod, jsonType, fieldList);
  263. }
  264. boolean isInterfaceOrAbstract = clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers());
  265. if ((defaultConstructor == null && builderClass == null) || isInterfaceOrAbstract) {
  266. Type mixInType = JSON.getMixInAnnotations(clazz);
  267. if (mixInType instanceof Class) {
  268. Constructor<?>[] mixInConstructors = ((Class<?>) mixInType).getConstructors();
  269. Constructor<?> mixInCreator = getCreatorConstructor(mixInConstructors);
  270. if (mixInCreator != null) {
  271. try {
  272. creatorConstructor = clazz.getConstructor(mixInCreator.getParameterTypes());
  273. } catch (NoSuchMethodException e) {
  274. // skip
  275. }
  276. }
  277. }
  278. if (creatorConstructor == null) {
  279. creatorConstructor = getCreatorConstructor(constructors);
  280. }
  281. if (creatorConstructor != null && !isInterfaceOrAbstract) { // 基于标记 JSONCreator 注解的构造方法
  282. TypeUtils.setAccessible(creatorConstructor);
  283. Class<?>[] types = creatorConstructor.getParameterTypes();
  284. String[] lookupParameterNames = null;
  285. if (types.length > 0) {
  286. Annotation[][] paramAnnotationArrays = TypeUtils.getParameterAnnotations(creatorConstructor);
  287. for (int i = 0; i < types.length && i < paramAnnotationArrays.length; ++i) {
  288. Annotation[] paramAnnotations = paramAnnotationArrays[i];
  289. JSONField fieldAnnotation = null;
  290. for (Annotation paramAnnotation : paramAnnotations) {
  291. if (paramAnnotation instanceof JSONField) {
  292. fieldAnnotation = (JSONField) paramAnnotation;
  293. break;
  294. }
  295. }
  296. Class<?> fieldClass = types[i];
  297. Type fieldType = creatorConstructor.getGenericParameterTypes()[i];
  298. String fieldName = null;
  299. Field field = null;
  300. int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
  301. if (fieldAnnotation != null) {
  302. field = TypeUtils.getField(clazz, fieldAnnotation.name(), declaredFields);
  303. ordinal = fieldAnnotation.ordinal();
  304. serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
  305. parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
  306. fieldName = fieldAnnotation.name();
  307. }
  308. if (fieldName == null || fieldName.length() == 0) {
  309. if (lookupParameterNames == null) {
  310. lookupParameterNames = ASMUtils.lookupParameterNames(creatorConstructor);
  311. }
  312. fieldName = lookupParameterNames[i];
  313. }
  314. if (field == null) {
  315. if (lookupParameterNames == null) {
  316. if (kotlin) {
  317. lookupParameterNames = TypeUtils.getKoltinConstructorParameters(clazz);
  318. } else {
  319. lookupParameterNames = ASMUtils.lookupParameterNames(creatorConstructor);
  320. }
  321. }
  322. if (lookupParameterNames.length > i) {
  323. String parameterName = lookupParameterNames[i];
  324. field = TypeUtils.getField(clazz, parameterName, declaredFields);
  325. }
  326. }
  327. FieldInfo fieldInfo = new FieldInfo(fieldName, clazz, fieldClass, fieldType, field,
  328. ordinal, serialzeFeatures, parserFeatures);
  329. add(fieldList, fieldInfo);
  330. }
  331. }
  332. //return new JavaBeanInfo(clazz, builderClass, null, creatorConstructor, null, null, jsonType, fieldList);
  333. } else if ((factoryMethod = getFactoryMethod(clazz, methods, jacksonCompatible)) != null) {
  334. TypeUtils.setAccessible(factoryMethod);
  335. String[] lookupParameterNames = null;
  336. Class<?>[] types = factoryMethod.getParameterTypes();
  337. if (types.length > 0) {
  338. Annotation[][] paramAnnotationArrays = TypeUtils.getParameterAnnotations(factoryMethod);
  339. for (int i = 0; i < types.length; ++i) {
  340. Annotation[] paramAnnotations = paramAnnotationArrays[i];
  341. JSONField fieldAnnotation = null;
  342. for (Annotation paramAnnotation : paramAnnotations) {
  343. if (paramAnnotation instanceof JSONField) {
  344. fieldAnnotation = (JSONField) paramAnnotation;
  345. break;
  346. }
  347. }
  348. if (fieldAnnotation == null && !(jacksonCompatible && TypeUtils.isJacksonCreator(factoryMethod))) {
  349. throw new JSONException("illegal json creator");
  350. }
  351. String fieldName = null;
  352. int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
  353. if (fieldAnnotation != null) {
  354. fieldName = fieldAnnotation.name();
  355. ordinal = fieldAnnotation.ordinal();
  356. serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
  357. parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
  358. }
  359. if (fieldName == null || fieldName.length() == 0) {
  360. if (lookupParameterNames == null) {
  361. lookupParameterNames = ASMUtils.lookupParameterNames(factoryMethod);
  362. }
  363. fieldName = lookupParameterNames[i];
  364. }
  365. Class<?> fieldClass = types[i];
  366. Type fieldType = factoryMethod.getGenericParameterTypes()[i];
  367. Field field = TypeUtils.getField(clazz, fieldName, declaredFields);
  368. FieldInfo fieldInfo = new FieldInfo(fieldName, clazz, fieldClass, fieldType, field,
  369. ordinal, serialzeFeatures, parserFeatures);
  370. add(fieldList, fieldInfo);
  371. }
  372. return new JavaBeanInfo(clazz, builderClass, null, null, factoryMethod, null, jsonType, fieldList);
  373. }
  374. } else if (!isInterfaceOrAbstract) {
  375. String className = clazz.getName();
  376. String[] paramNames = null;
  377. if (kotlin && constructors.length > 0) {
  378. paramNames = TypeUtils.getKoltinConstructorParameters(clazz);
  379. creatorConstructor = TypeUtils.getKotlinConstructor(constructors, paramNames);
  380. TypeUtils.setAccessible(creatorConstructor);
  381. } else {
  382. for (Constructor constructor : constructors) {
  383. Class<?>[] parameterTypes = constructor.getParameterTypes();
  384. if (className.equals("org.springframework.security.web.authentication.WebAuthenticationDetails")) {
  385. if (parameterTypes.length == 2 && parameterTypes[0] == String.class && parameterTypes[1] == String.class) {
  386. creatorConstructor = constructor;
  387. creatorConstructor.setAccessible(true);
  388. paramNames = ASMUtils.lookupParameterNames(constructor);
  389. break;
  390. } else {
  391. continue;
  392. }
  393. }
  394. if (className.equals("org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken")) {
  395. if (parameterTypes.length == 3
  396. && parameterTypes[0] == Object.class
  397. && parameterTypes[1] == Object.class
  398. && parameterTypes[2] == Collection.class) {
  399. creatorConstructor = constructor;
  400. creatorConstructor.setAccessible(true);
  401. paramNames = new String[] {"principal", "credentials", "authorities"};
  402. break;
  403. } else {
  404. continue;
  405. }
  406. }
  407. if (className.equals("org.springframework.security.core.authority.SimpleGrantedAuthority")) {
  408. if (parameterTypes.length == 1
  409. && parameterTypes[0] == String.class) {
  410. creatorConstructor = constructor;
  411. paramNames = new String[] {"authority"};
  412. break;
  413. } else {
  414. continue;
  415. }
  416. }
  417. //
  418. boolean is_public = (constructor.getModifiers() & Modifier.PUBLIC) != 0;
  419. if (!is_public) {
  420. continue;
  421. }
  422. String[] lookupParameterNames = ASMUtils.lookupParameterNames(constructor);
  423. if (lookupParameterNames == null || lookupParameterNames.length == 0) {
  424. continue;
  425. }
  426. if (creatorConstructor != null
  427. && paramNames != null && lookupParameterNames.length <= paramNames.length) {
  428. continue;
  429. }
  430. paramNames = lookupParameterNames;
  431. creatorConstructor = constructor;
  432. }
  433. }
  434. Class<?>[] types = null;
  435. if (paramNames != null) {
  436. types = creatorConstructor.getParameterTypes();
  437. }
  438. if (paramNames != null
  439. && types.length == paramNames.length) {
  440. Annotation[][] paramAnnotationArrays = TypeUtils.getParameterAnnotations(creatorConstructor);
  441. for (int i = 0; i < types.length; ++i) {
  442. Annotation[] paramAnnotations = paramAnnotationArrays[i];
  443. String paramName = paramNames[i];
  444. JSONField fieldAnnotation = null;
  445. for (Annotation paramAnnotation : paramAnnotations) {
  446. if (paramAnnotation instanceof JSONField) {
  447. fieldAnnotation = (JSONField) paramAnnotation;
  448. break;
  449. }
  450. }
  451. Class<?> fieldClass = types[i];
  452. Type fieldType = creatorConstructor.getGenericParameterTypes()[i];
  453. Field field = TypeUtils.getField(clazz, paramName, declaredFields);
  454. if (field != null) {
  455. if (fieldAnnotation == null) {
  456. fieldAnnotation = TypeUtils.getAnnotation(field, JSONField.class);
  457. }
  458. }
  459. final int ordinal, serialzeFeatures, parserFeatures;
  460. if (fieldAnnotation == null) {
  461. ordinal = 0;
  462. serialzeFeatures = 0;
  463. if ("org.springframework.security.core.userdetails.User".equals(className)
  464. && "password".equals(paramName)) {
  465. parserFeatures = Feature.InitStringFieldAsEmpty.mask;
  466. } else {
  467. parserFeatures = 0;
  468. }
  469. } else {
  470. String nameAnnotated = fieldAnnotation.name();
  471. if (nameAnnotated.length() != 0) {
  472. paramName = nameAnnotated;
  473. }
  474. ordinal = fieldAnnotation.ordinal();
  475. serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
  476. parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
  477. }
  478. FieldInfo fieldInfo = new FieldInfo(paramName, clazz, fieldClass, fieldType, field,
  479. ordinal, serialzeFeatures, parserFeatures);
  480. add(fieldList, fieldInfo);
  481. }
  482. if ((!kotlin) && !clazz.getName().equals("javax.servlet.http.Cookie")) {
  483. return new JavaBeanInfo(clazz, builderClass, null, creatorConstructor, null, null, jsonType, fieldList);
  484. }
  485. } else {
  486. throw new JSONException("default constructor not found. " + clazz);
  487. }
  488. }
  489. }
  490. if (defaultConstructor != null) {
  491. TypeUtils.setAccessible(defaultConstructor);
  492. }
  493. if (builderClass != null) {
  494. String withPrefix = null;
  495. JSONPOJOBuilder builderAnno = TypeUtils.getAnnotation(builderClass, JSONPOJOBuilder.class);
  496. if (builderAnno != null) {
  497. withPrefix = builderAnno.withPrefix();
  498. }
  499. if (withPrefix == null) {
  500. withPrefix = "with";
  501. }
  502. for (Method method : builderClass.getMethods()) {
  503. if (Modifier.isStatic(method.getModifiers())) {
  504. continue;
  505. }
  506. if (!(method.getReturnType().equals(builderClass))) {
  507. continue;
  508. }
  509. int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
  510. JSONField annotation = TypeUtils.getAnnotation(method, JSONField.class);
  511. if (annotation == null) {
  512. annotation = TypeUtils.getSuperMethodAnnotation(clazz, method);
  513. }
  514. if (annotation != null) {
  515. if (!annotation.deserialize()) {
  516. continue;
  517. }
  518. ordinal = annotation.ordinal();
  519. serialzeFeatures = SerializerFeature.of(annotation.serialzeFeatures());
  520. parserFeatures = Feature.of(annotation.parseFeatures());
  521. if (annotation.name().length() != 0) {
  522. String propertyName = annotation.name();
  523. add(fieldList, new FieldInfo(propertyName, method, null, clazz, type, ordinal, serialzeFeatures, parserFeatures,
  524. annotation, null, null, genericInfo));
  525. continue;
  526. }
  527. }
  528. String methodName = method.getName();
  529. StringBuilder properNameBuilder;
  530. if (methodName.startsWith("set") && methodName.length() > 3) {
  531. properNameBuilder = new StringBuilder(methodName.substring(3));
  532. } else {
  533. if (withPrefix.length() == 0){
  534. properNameBuilder = new StringBuilder(methodName);
  535. } else {
  536. if (!methodName.startsWith(withPrefix)) {
  537. continue;
  538. }
  539. if (methodName.length() <= withPrefix.length()) {
  540. continue;
  541. }
  542. properNameBuilder = new StringBuilder(methodName.substring(withPrefix.length()));
  543. }
  544. }
  545. char c0 = properNameBuilder.charAt(0);
  546. if (withPrefix.length() != 0 && !Character.isUpperCase(c0)) {
  547. continue;
  548. }
  549. properNameBuilder.setCharAt(0, Character.toLowerCase(c0));
  550. String propertyName = properNameBuilder.toString();
  551. add(fieldList, new FieldInfo(propertyName, method, null, clazz, type, ordinal, serialzeFeatures, parserFeatures,
  552. annotation, null, null, genericInfo));
  553. }
  554. if (builderClass != null) {
  555. JSONPOJOBuilder builderAnnotation = TypeUtils.getAnnotation(builderClass, JSONPOJOBuilder.class);
  556. String buildMethodName = null;
  557. if (builderAnnotation != null) {
  558. buildMethodName = builderAnnotation.buildMethod();
  559. }
  560. if (buildMethodName == null || buildMethodName.length() == 0) {
  561. buildMethodName = "build";
  562. }
  563. try {
  564. buildMethod = builderClass.getMethod(buildMethodName);
  565. } catch (NoSuchMethodException e) {
  566. // skip
  567. } catch (SecurityException e) {
  568. // skip
  569. }
  570. if (buildMethod == null) {
  571. try {
  572. buildMethod = builderClass.getMethod("create");
  573. } catch (NoSuchMethodException e) {
  574. // skip
  575. } catch (SecurityException e) {
  576. // skip
  577. }
  578. }
  579. if (buildMethod == null) {
  580. throw new JSONException("buildMethod not found.");
  581. }
  582. TypeUtils.setAccessible(buildMethod);
  583. }
  584. }
  585. for (Method method : methods) { //
  586. int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
  587. String methodName = method.getName();
  588. if (Modifier.isStatic(method.getModifiers())) {
  589. continue;
  590. }
  591. // support builder set
  592. Class<?> returnType = method.getReturnType();
  593. if (!(returnType.equals(Void.TYPE) || returnType.equals(method.getDeclaringClass()))) {
  594. continue;
  595. }
  596. if (method.getDeclaringClass() == Object.class) {
  597. continue;
  598. }
  599. Class<?>[] types = method.getParameterTypes();
  600. if (types.length == 0 || types.length > 2) {
  601. continue;
  602. }
  603. JSONField annotation = TypeUtils.getAnnotation(method, JSONField.class);
  604. if (annotation != null
  605. && types.length == 2
  606. && types[0] == String.class
  607. && types[1] == Object.class) {
  608. add(fieldList, new FieldInfo("", method, null, clazz, type, ordinal,
  609. serialzeFeatures, parserFeatures, annotation, null, null, genericInfo));
  610. continue;
  611. }
  612. if (types.length != 1) {
  613. continue;
  614. }
  615. if (annotation == null) {
  616. annotation = TypeUtils.getSuperMethodAnnotation(clazz, method);
  617. }
  618. if (annotation == null && methodName.length() < 4) {
  619. continue;
  620. }
  621. if (annotation != null) {
  622. if (!annotation.deserialize()) {
  623. continue;
  624. }
  625. ordinal = annotation.ordinal();
  626. serialzeFeatures = SerializerFeature.of(annotation.serialzeFeatures());
  627. parserFeatures = Feature.of(annotation.parseFeatures());
  628. if (annotation.name().length() != 0) {
  629. String propertyName = annotation.name();
  630. add(fieldList, new FieldInfo(propertyName, method, null, clazz, type, ordinal, serialzeFeatures, parserFeatures,
  631. annotation, null, null, genericInfo));
  632. continue;
  633. }
  634. }
  635. if (annotation == null && !methodName.startsWith("set") || builderClass != null) { // TODO "set"的判断放在 JSONField 注解后面,意思是允许非 setter 方法标记 JSONField 注解?
  636. continue;
  637. }
  638. char c3 = methodName.charAt(3);
  639. String propertyName;
  640. Field field = null;
  641. // 用于存储KotlinBean中所有的get方法, 方便后续判断
  642. List<String> getMethodNameList = null;
  643. if (kotlin) {
  644. getMethodNameList = new ArrayList();
  645. for (int i = 0; i < methods.length; i++) {
  646. if (methods[i].getName().startsWith("get")) {
  647. getMethodNameList.add(methods[i].getName());
  648. }
  649. }
  650. }
  651. if (Character.isUpperCase(c3) //
  652. || c3 > 512 // for unicode method name
  653. ) {
  654. // 这里本身的逻辑是通过setAbc这类方法名解析出成员变量名为abc或者Abc, 但是在kotlin中, isAbc, abc成员变量的set方法都是setAbc
  655. // 因此如果是kotlin的话还需要进行不一样的判断, 判断的方式是通过get方法进行判断, isAbc的get方法名为isAbc(), abc的get方法名为getAbc()
  656. if (kotlin) {
  657. String getMethodName = "g" + methodName.substring(1);
  658. propertyName = TypeUtils.getPropertyNameByMethodName(getMethodName);
  659. } else {
  660. if (TypeUtils.compatibleWithJavaBean) {
  661. propertyName = TypeUtils.decapitalize(methodName.substring(3));
  662. } else {
  663. propertyName = TypeUtils.getPropertyNameByMethodName(methodName);
  664. }
  665. }
  666. } else if (c3 == '_') {
  667. // 这里本身的逻辑是通过set_abc这类方法名解析出成员变量名为abc, 但是在kotlin中, is_abc和_abc成员变量的set方法都是set_abc
  668. // 因此如果是kotlin的话还需要进行不一样的判断, 判断的方式是通过get方法进行判断, is_abc的get方法名为is_abc(), _abc的get方法名为get_abc()
  669. if (kotlin) {
  670. String getMethodName = "g" + methodName.substring(1);
  671. if (getMethodNameList.contains(getMethodName)) {
  672. propertyName = methodName.substring(3);
  673. } else {
  674. propertyName = "is" + methodName.substring(3);
  675. }
  676. field = TypeUtils.getField(clazz, propertyName, declaredFields);
  677. } else {
  678. propertyName = methodName.substring(4);
  679. field = TypeUtils.getField(clazz, propertyName, declaredFields);
  680. if (field == null) {
  681. String temp = propertyName;
  682. propertyName = methodName.substring(3);
  683. field = TypeUtils.getField(clazz, propertyName, declaredFields);
  684. if (field == null) {
  685. propertyName = temp; //减少修改代码带来的影响
  686. }
  687. }
  688. }
  689. } else if (c3 == 'f') {
  690. propertyName = methodName.substring(3);
  691. } else if (methodName.length() >= 5 && Character.isUpperCase(methodName.charAt(4))) {
  692. propertyName = TypeUtils.decapitalize(methodName.substring(3));
  693. } else {
  694. propertyName = methodName.substring(3);
  695. field = TypeUtils.getField(clazz, propertyName, declaredFields);
  696. if (field == null) {
  697. continue;
  698. }
  699. }
  700. if (field == null) {
  701. field = TypeUtils.getField(clazz, propertyName, declaredFields);
  702. }
  703. if (field == null && types[0] == boolean.class) {
  704. String isFieldName = "is" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
  705. field = TypeUtils.getField(clazz, isFieldName, declaredFields);
  706. }
  707. JSONField fieldAnnotation = null;
  708. if (field != null) {
  709. fieldAnnotation = TypeUtils.getAnnotation(field, JSONField.class);
  710. if (fieldAnnotation != null) {
  711. if (!fieldAnnotation.deserialize()) {
  712. continue;
  713. }
  714. ordinal = fieldAnnotation.ordinal();
  715. serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
  716. parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
  717. if (fieldAnnotation.name().length() != 0) {
  718. propertyName = fieldAnnotation.name();
  719. add(fieldList, new FieldInfo(propertyName, method, field, clazz, type, ordinal,
  720. serialzeFeatures, parserFeatures, annotation, fieldAnnotation, null, genericInfo));
  721. continue;
  722. }
  723. }
  724. }
  725. if (propertyNamingStrategy != null) {
  726. propertyName = propertyNamingStrategy.translate(propertyName);
  727. }
  728. add(fieldList, new FieldInfo(propertyName, method, field, clazz, type, ordinal, serialzeFeatures, parserFeatures,
  729. annotation, fieldAnnotation, null, genericInfo));
  730. }
  731. Field[] fields = clazz.getFields();
  732. computeFields(clazz, type, propertyNamingStrategy, fieldList, fields);
  733. for (Method method : clazz.getMethods()) { // getter methods
  734. String methodName = method.getName();
  735. if (methodName.length() < 4) {
  736. continue;
  737. }
  738. if (Modifier.isStatic(method.getModifiers())) {
  739. continue;
  740. }
  741. if (builderClass == null && methodName.startsWith("get") && Character.isUpperCase(methodName.charAt(3))) {
  742. if (method.getParameterTypes().length != 0) {
  743. continue;
  744. }
  745. if (Collection.class.isAssignableFrom(method.getReturnType()) //
  746. || Map.class.isAssignableFrom(method.getReturnType()) //
  747. || AtomicBoolean.class == method.getReturnType() //
  748. || AtomicInteger.class == method.getReturnType() //
  749. || AtomicLong.class == method.getReturnType() //
  750. ) {
  751. String propertyName;
  752. Field collectionField = null;
  753. JSONField annotation = TypeUtils.getAnnotation(method, JSONField.class);
  754. if (annotation != null && annotation.deserialize()) {
  755. continue;
  756. }
  757. if (annotation != null && annotation.name().length() > 0) {
  758. propertyName = annotation.name();
  759. } else {
  760. propertyName = TypeUtils.getPropertyNameByMethodName(methodName);
  761. Field field = TypeUtils.getField(clazz, propertyName, declaredFields);
  762. if (field != null) {
  763. JSONField fieldAnnotation = TypeUtils.getAnnotation(field, JSONField.class);
  764. if (fieldAnnotation != null && !fieldAnnotation.deserialize()) {
  765. continue;
  766. }
  767. if (Collection.class.isAssignableFrom(method.getReturnType())
  768. || Map.class.isAssignableFrom(method.getReturnType())) {
  769. collectionField = field;
  770. }
  771. }
  772. }
  773. if (propertyNamingStrategy != null) {
  774. propertyName = propertyNamingStrategy.translate(propertyName);
  775. }
  776. FieldInfo fieldInfo = getField(fieldList, propertyName);
  777. if (fieldInfo != null) {
  778. continue;
  779. }
  780. add(fieldList, new FieldInfo(propertyName, method, collectionField, clazz, type, 0, 0, 0, annotation, null, null, genericInfo));
  781. }
  782. }
  783. }
  784. if (fieldList.size() == 0) {
  785. if (TypeUtils.isXmlField(clazz)) {
  786. fieldBased = true;
  787. }
  788. if (fieldBased) {
  789. for (Class<?> currentClass = clazz; currentClass != null; currentClass = currentClass.getSuperclass()) {
  790. computeFields(clazz, type, propertyNamingStrategy, fieldList, declaredFields);
  791. }
  792. }
  793. }
  794. return new JavaBeanInfo(clazz, builderClass, defaultConstructor, creatorConstructor, factoryMethod, buildMethod, jsonType, fieldList);
  795. }
  796. private static void computeFields(Class<?> clazz, Type type, PropertyNamingStrategy propertyNamingStrategy, List<FieldInfo> fieldList, Field[] fields) {
  797. Map<TypeVariable, Type> genericInfo = buildGenericInfo(clazz);
  798. for (Field field : fields) { // public static fields
  799. int modifiers = field.getModifiers();
  800. if ((modifiers & Modifier.STATIC) != 0) {
  801. continue;
  802. }
  803. if ((modifiers & Modifier.FINAL) != 0) {
  804. Class<?> fieldType = field.getType();
  805. boolean supportReadOnly = Map.class.isAssignableFrom(fieldType)
  806. || Collection.class.isAssignableFrom(fieldType)
  807. || AtomicLong.class.equals(fieldType) //
  808. || AtomicInteger.class.equals(fieldType) //
  809. || AtomicBoolean.class.equals(fieldType);
  810. if (!supportReadOnly) {
  811. continue;
  812. }
  813. }
  814. boolean contains = false;
  815. for (FieldInfo item : fieldList) {
  816. if (item.name.equals(field.getName())) {
  817. contains = true;
  818. break; // 已经是 contains = true,无需继续遍历
  819. }
  820. }
  821. if (contains) {
  822. continue;
  823. }
  824. int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
  825. String propertyName = field.getName();
  826. JSONField fieldAnnotation = TypeUtils.getAnnotation(field, JSONField.class);
  827. if (fieldAnnotation != null) {
  828. if (!fieldAnnotation.deserialize()) {
  829. continue;
  830. }
  831. ordinal = fieldAnnotation.ordinal();
  832. serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
  833. parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
  834. if (fieldAnnotation.name().length() != 0) {
  835. propertyName = fieldAnnotation.name();
  836. }
  837. }
  838. if (propertyNamingStrategy != null) {
  839. propertyName = propertyNamingStrategy.translate(propertyName);
  840. }
  841. add(fieldList, new FieldInfo(propertyName, null, field, clazz, type, ordinal, serialzeFeatures, parserFeatures, null,
  842. fieldAnnotation, null, genericInfo));
  843. }
  844. }
  845. static Constructor<?> getDefaultConstructor(Class<?> clazz, final Constructor<?>[] constructors) {
  846. if (Modifier.isAbstract(clazz.getModifiers())) {
  847. return null;
  848. }
  849. Constructor<?> defaultConstructor = null;
  850. for (Constructor<?> constructor : constructors) {
  851. if (constructor.getParameterTypes().length == 0) {
  852. defaultConstructor = constructor;
  853. break;
  854. }
  855. }
  856. if (defaultConstructor == null) {
  857. if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
  858. Class<?>[] types;
  859. for (Constructor<?> constructor : constructors) {
  860. if ((types = constructor.getParameterTypes()).length == 1
  861. && types[0].equals(clazz.getDeclaringClass())) {
  862. defaultConstructor = constructor;
  863. break;
  864. }
  865. }
  866. }
  867. }
  868. return defaultConstructor;
  869. }
  870. public static Constructor<?> getCreatorConstructor(Constructor[] constructors) {
  871. Constructor<?> creatorConstructor = null;
  872. for (Constructor<?> constructor : constructors) {
  873. JSONCreator annotation = constructor.getAnnotation(JSONCreator.class);
  874. if (annotation != null) {
  875. if (creatorConstructor != null) {
  876. throw new JSONException("multi-JSONCreator");
  877. }
  878. creatorConstructor = constructor;
  879. // 不应该break,否则多个构造方法上存在 JSONCreator 注解时,并不会触发上述异常抛出
  880. }
  881. }
  882. if (creatorConstructor != null) {
  883. return creatorConstructor;
  884. }
  885. for (Constructor constructor : constructors) {
  886. Annotation[][] paramAnnotationArrays = TypeUtils.getParameterAnnotations(constructor);
  887. if (paramAnnotationArrays.length == 0) {
  888. continue;
  889. }
  890. boolean match = true;
  891. for (Annotation[] paramAnnotationArray : paramAnnotationArrays) {
  892. boolean paramMatch = false;
  893. for (Annotation paramAnnotation : paramAnnotationArray) {
  894. if (paramAnnotation instanceof JSONField) {
  895. paramMatch = true;
  896. break;
  897. }
  898. }
  899. if (!paramMatch) {
  900. match = false;
  901. break;
  902. }
  903. }
  904. if (match) {
  905. if (creatorConstructor != null) {
  906. throw new JSONException("multi-JSONCreator");
  907. }
  908. creatorConstructor = constructor;
  909. }
  910. }
  911. return creatorConstructor;
  912. }
  913. private static Method getFactoryMethod(Class<?> clazz, Method[] methods, boolean jacksonCompatible) {
  914. Method factoryMethod = null;
  915. for (Method method : methods) {
  916. if (!Modifier.isStatic(method.getModifiers())) {
  917. continue;
  918. }
  919. if (!clazz.isAssignableFrom(method.getReturnType())) {
  920. continue;
  921. }
  922. JSONCreator annotation = TypeUtils.getAnnotation(method, JSONCreator.class);
  923. if (annotation != null) {
  924. if (factoryMethod != null) {
  925. throw new JSONException("multi-JSONCreator");
  926. }
  927. factoryMethod = method;
  928. // 不应该break,否则多个静态工厂方法上存在 JSONCreator 注解时,并不会触发上述异常抛出
  929. }
  930. }
  931. if (factoryMethod == null && jacksonCompatible) {
  932. for (Method method : methods) {
  933. if (TypeUtils.isJacksonCreator(method)) {
  934. factoryMethod = method;
  935. break;
  936. }
  937. }
  938. }
  939. return factoryMethod;
  940. }
  941. /**
  942. * @deprecated
  943. */
  944. public static Class<?> getBuilderClass(JSONType type) {
  945. return getBuilderClass(null, type);
  946. }
  947. public static Class<?> getBuilderClass(Class<?> clazz, JSONType type) {
  948. if (clazz != null && clazz.getName().equals("org.springframework.security.web.savedrequest.DefaultSavedRequest")) {
  949. return TypeUtils.loadClass("org.springframework.security.web.savedrequest.DefaultSavedRequest$Builder");
  950. }
  951. if (type == null) {
  952. return null;
  953. }
  954. Class<?> builderClass = type.builder();
  955. if (builderClass == Void.class) {
  956. return null;
  957. }
  958. return builderClass;
  959. }
  960. }