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

https://github.com/alibaba/fastjson · Java · 592 lines · 490 code · 100 blank · 2 comment · 183 complexity · b3a2f609637a4a0be7731f430dbf1b4e MD5 · raw file

  1. package com.alibaba.fastjson.util;
  2. import java.lang.annotation.Annotation;
  3. import java.lang.reflect.Array;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.GenericArrayType;
  6. import java.lang.reflect.GenericDeclaration;
  7. import java.lang.reflect.InvocationTargetException;
  8. import java.lang.reflect.Member;
  9. import java.lang.reflect.Method;
  10. import java.lang.reflect.Modifier;
  11. import java.lang.reflect.ParameterizedType;
  12. import java.lang.reflect.Type;
  13. import java.lang.reflect.TypeVariable;
  14. import java.util.Map;
  15. import com.alibaba.fastjson.TypeReference;
  16. import com.alibaba.fastjson.annotation.JSONField;
  17. public class FieldInfo implements Comparable<FieldInfo> {
  18. public final String name;
  19. public final Method method;
  20. public final Field field;
  21. private int ordinal = 0;
  22. public final Class<?> fieldClass;
  23. public final Type fieldType;
  24. public final Class<?> declaringClass;
  25. public final boolean getOnly;
  26. public final int serialzeFeatures;
  27. public final int parserFeatures;
  28. public final String label;
  29. private final JSONField fieldAnnotation;
  30. private final JSONField methodAnnotation;
  31. public final boolean fieldAccess;
  32. public final boolean fieldTransient;
  33. public final char[] name_chars;
  34. public final boolean isEnum;
  35. public final boolean jsonDirect;
  36. public final boolean unwrapped;
  37. public final String format;
  38. public final String[] alternateNames;
  39. public final long nameHashCode;
  40. public FieldInfo(String name, //
  41. Class<?> declaringClass, //
  42. Class<?> fieldClass, //
  43. Type fieldType, //
  44. Field field, //
  45. int ordinal, //
  46. int serialzeFeatures, //
  47. int parserFeatures){
  48. if (ordinal < 0) {
  49. ordinal = 0;
  50. }
  51. this.name = name;
  52. this.declaringClass = declaringClass;
  53. this.fieldClass = fieldClass;
  54. this.fieldType = fieldType;
  55. this.method = null;
  56. this.field = field;
  57. this.ordinal = ordinal;
  58. this.serialzeFeatures = serialzeFeatures;
  59. this.parserFeatures = parserFeatures;
  60. isEnum = fieldClass.isEnum();
  61. if (field != null) {
  62. int modifiers = field.getModifiers();
  63. fieldAccess = (modifiers & Modifier.PUBLIC) != 0 || method == null;
  64. fieldTransient = Modifier.isTransient(modifiers);
  65. } else {
  66. fieldTransient = false;
  67. fieldAccess = false;
  68. }
  69. name_chars = genFieldNameChars();
  70. if (field != null) {
  71. TypeUtils.setAccessible(field);
  72. }
  73. this.label = "";
  74. fieldAnnotation = field == null ? null : TypeUtils.getAnnotation(field, JSONField.class);
  75. methodAnnotation = null;
  76. this.getOnly = false;
  77. this.jsonDirect = false;
  78. this.unwrapped = false;
  79. this.format = null;
  80. this.alternateNames = new String[0];
  81. nameHashCode = nameHashCode64(name, fieldAnnotation);
  82. }
  83. public FieldInfo(String name, //
  84. Method method, //
  85. Field field, //
  86. Class<?> clazz, //
  87. Type type, //
  88. int ordinal, //
  89. int serialzeFeatures, //
  90. int parserFeatures, //
  91. JSONField fieldAnnotation, //
  92. JSONField methodAnnotation, //
  93. String label){
  94. this(name, method, field, clazz, type, ordinal, serialzeFeatures, parserFeatures,
  95. fieldAnnotation, methodAnnotation, label, null);
  96. }
  97. public FieldInfo(String name, //
  98. Method method, //
  99. Field field, //
  100. Class<?> clazz, //
  101. Type type, //
  102. int ordinal, //
  103. int serialzeFeatures, //
  104. int parserFeatures, //
  105. JSONField fieldAnnotation, //
  106. JSONField methodAnnotation, //
  107. String label,
  108. Map<TypeVariable, Type> genericInfo){
  109. if (field != null) {
  110. String fieldName = field.getName();
  111. if (fieldName.equals(name)) {
  112. name = fieldName;
  113. }
  114. }
  115. if (ordinal < 0) {
  116. ordinal = 0;
  117. }
  118. this.name = name;
  119. this.method = method;
  120. this.field = field;
  121. this.ordinal = ordinal;
  122. this.serialzeFeatures = serialzeFeatures;
  123. this.parserFeatures = parserFeatures;
  124. this.fieldAnnotation = fieldAnnotation;
  125. this.methodAnnotation = methodAnnotation;
  126. if (field != null) {
  127. int modifiers = field.getModifiers();
  128. fieldAccess = ((modifiers & Modifier.PUBLIC) != 0 || method == null);
  129. fieldTransient = Modifier.isTransient(modifiers)
  130. || TypeUtils.isTransient(method);
  131. } else {
  132. fieldAccess = false;
  133. fieldTransient = TypeUtils.isTransient(method);
  134. }
  135. if (label != null && label.length() > 0) {
  136. this.label = label;
  137. } else {
  138. this.label = "";
  139. }
  140. String format = null;
  141. JSONField annotation = getAnnotation();
  142. nameHashCode = nameHashCode64(name, annotation);
  143. boolean jsonDirect = false;
  144. if (annotation != null) {
  145. format = annotation.format();
  146. if (format.trim().length() == 0) {
  147. format = null;
  148. }
  149. jsonDirect = annotation.jsonDirect();
  150. unwrapped = annotation.unwrapped();
  151. alternateNames = annotation.alternateNames();
  152. } else {
  153. jsonDirect = false;
  154. unwrapped = false;
  155. alternateNames = new String[0];
  156. }
  157. this.format = format;
  158. name_chars = genFieldNameChars();
  159. if (method != null) {
  160. TypeUtils.setAccessible(method);
  161. }
  162. if (field != null) {
  163. TypeUtils.setAccessible(field);
  164. }
  165. boolean getOnly = false;
  166. Type fieldType;
  167. Class<?> fieldClass;
  168. if (method != null) {
  169. Class<?>[] types;
  170. if ((types = method.getParameterTypes()).length == 1) {
  171. fieldClass = types[0];
  172. fieldType = method.getGenericParameterTypes()[0];
  173. } else if (types.length == 2 && types[0] == String.class && types[1] == Object.class) {
  174. fieldType = fieldClass = types[0];
  175. } else {
  176. fieldClass = method.getReturnType();
  177. fieldType = method.getGenericReturnType();
  178. getOnly = true;
  179. }
  180. this.declaringClass = method.getDeclaringClass();
  181. } else {
  182. fieldClass = field.getType();
  183. fieldType = field.getGenericType();
  184. this.declaringClass = field.getDeclaringClass();
  185. getOnly = Modifier.isFinal(field.getModifiers());
  186. }
  187. this.getOnly = getOnly;
  188. this.jsonDirect = jsonDirect && fieldClass == String.class;
  189. if (clazz != null && fieldClass == Object.class && fieldType instanceof TypeVariable) {
  190. TypeVariable<?> tv = (TypeVariable<?>) fieldType;
  191. Type genericFieldType = getInheritGenericType(clazz, type, tv);
  192. if (genericFieldType != null) {
  193. this.fieldClass = TypeUtils.getClass(genericFieldType);
  194. this.fieldType = genericFieldType;
  195. isEnum = fieldClass.isEnum();
  196. return;
  197. }
  198. }
  199. Type genericFieldType = fieldType;
  200. if (!(fieldType instanceof Class)) {
  201. genericFieldType = getFieldType(clazz, type != null ? type : clazz, fieldType, genericInfo);
  202. if (genericFieldType != fieldType) {
  203. if (genericFieldType instanceof ParameterizedType) {
  204. fieldClass = TypeUtils.getClass(genericFieldType);
  205. } else if (genericFieldType instanceof Class) {
  206. fieldClass = TypeUtils.getClass(genericFieldType);
  207. }
  208. }
  209. }
  210. this.fieldType = genericFieldType;
  211. this.fieldClass = fieldClass;
  212. isEnum = fieldClass.isEnum();
  213. }
  214. private long nameHashCode64(String name, JSONField annotation)
  215. {
  216. if (annotation != null && annotation.name().length() != 0) {
  217. return TypeUtils.fnv1a_64_lower(name);
  218. }
  219. return TypeUtils.fnv1a_64_extract(name);
  220. }
  221. protected char[] genFieldNameChars() {
  222. int nameLen = this.name.length();
  223. char[] name_chars = new char[nameLen + 3];
  224. this.name.getChars(0, this.name.length(), name_chars, 1);
  225. name_chars[0] = '"';
  226. name_chars[nameLen + 1] = '"';
  227. name_chars[nameLen + 2] = ':';
  228. return name_chars;
  229. }
  230. @SuppressWarnings("unchecked")
  231. public <T extends Annotation> T getAnnation(Class<T> annotationClass) {
  232. if (annotationClass == JSONField.class) {
  233. return (T) getAnnotation();
  234. }
  235. T annotatition = null;
  236. if (method != null) {
  237. annotatition = TypeUtils.getAnnotation(method, annotationClass);
  238. }
  239. if (annotatition == null && field != null) {
  240. annotatition = TypeUtils.getAnnotation(field, annotationClass);
  241. }
  242. return annotatition;
  243. }
  244. public static Type getFieldType(final Class<?> clazz, final Type type, Type fieldType){
  245. return getFieldType(clazz, type, fieldType, null);
  246. }
  247. public static Type getFieldType(final Class<?> clazz, final Type type, Type fieldType, Map<TypeVariable, Type> genericInfo) {
  248. if (clazz == null || type == null) {
  249. return fieldType;
  250. }
  251. if (fieldType instanceof GenericArrayType) {
  252. GenericArrayType genericArrayType = (GenericArrayType) fieldType;
  253. Type componentType = genericArrayType.getGenericComponentType();
  254. Type componentTypeX = getFieldType(clazz, type, componentType, genericInfo);
  255. if (componentType != componentTypeX) {
  256. Type fieldTypeX = Array.newInstance(TypeUtils.getClass(componentTypeX), 0).getClass();
  257. return fieldTypeX;
  258. }
  259. return fieldType;
  260. }
  261. if (!TypeUtils.isGenericParamType(type)) {
  262. return fieldType;
  263. }
  264. if (fieldType instanceof TypeVariable) {
  265. ParameterizedType paramType = (ParameterizedType) TypeUtils.getGenericParamType(type);
  266. Class<?> parameterizedClass = TypeUtils.getClass(paramType);
  267. final TypeVariable<?> typeVar = (TypeVariable<?>) fieldType;
  268. TypeVariable<?>[] typeVariables = parameterizedClass.getTypeParameters();
  269. for (int i = 0; i < typeVariables.length; ++i) {
  270. if (typeVariables[i].getName().equals(typeVar.getName())) {
  271. fieldType = paramType.getActualTypeArguments()[i];
  272. return fieldType;
  273. }
  274. }
  275. }
  276. if (fieldType instanceof ParameterizedType) {
  277. ParameterizedType parameterizedFieldType = (ParameterizedType) fieldType;
  278. Type[] arguments = parameterizedFieldType.getActualTypeArguments();
  279. TypeVariable<?>[] typeVariables;
  280. ParameterizedType paramType;
  281. boolean changed = getArgument(arguments, genericInfo);
  282. //if genericInfo is not working use the old path;
  283. if(!changed){
  284. if (type instanceof ParameterizedType) {
  285. paramType = (ParameterizedType) type;
  286. typeVariables = clazz.getTypeParameters();
  287. } else if(clazz.getGenericSuperclass() instanceof ParameterizedType) {
  288. paramType = (ParameterizedType) clazz.getGenericSuperclass();
  289. typeVariables = clazz.getSuperclass().getTypeParameters();
  290. } else {
  291. paramType = parameterizedFieldType;
  292. typeVariables = type.getClass().getTypeParameters();
  293. }
  294. changed = getArgument(arguments, typeVariables, paramType.getActualTypeArguments());
  295. }
  296. if (changed) {
  297. fieldType = TypeReference.intern(
  298. new ParameterizedTypeImpl(arguments, parameterizedFieldType.getOwnerType(),
  299. parameterizedFieldType.getRawType())
  300. );
  301. return fieldType;
  302. }
  303. }
  304. return fieldType;
  305. }
  306. private static boolean getArgument(Type[] typeArgs, Map<TypeVariable, Type> genericInfo){
  307. if(genericInfo == null || genericInfo.size() == 0){
  308. return false;
  309. }
  310. boolean changed = false;
  311. for (int i = 0; i < typeArgs.length; ++i) {
  312. Type typeArg = typeArgs[i];
  313. if (typeArg instanceof ParameterizedType) {
  314. ParameterizedType p_typeArg = (ParameterizedType) typeArg;
  315. Type[] p_typeArg_args = p_typeArg.getActualTypeArguments();
  316. boolean p_changed = getArgument(p_typeArg_args, genericInfo);
  317. if (p_changed) {
  318. typeArgs[i] = TypeReference.intern(
  319. new ParameterizedTypeImpl(p_typeArg_args, p_typeArg.getOwnerType(), p_typeArg.getRawType())
  320. );
  321. changed = true;
  322. }
  323. } else if (typeArg instanceof TypeVariable) {
  324. if (genericInfo.containsKey(typeArg)) {
  325. typeArgs[i] = genericInfo.get(typeArg);
  326. changed = true;
  327. }
  328. }
  329. }
  330. return changed;
  331. }
  332. private static boolean getArgument(Type[] typeArgs, TypeVariable[] typeVariables, Type[] arguments) {
  333. if (arguments == null || typeVariables.length == 0) {
  334. return false;
  335. }
  336. boolean changed = false;
  337. for (int i = 0; i < typeArgs.length; ++i) {
  338. Type typeArg = typeArgs[i];
  339. if (typeArg instanceof ParameterizedType) {
  340. ParameterizedType p_typeArg = (ParameterizedType) typeArg;
  341. Type[] p_typeArg_args = p_typeArg.getActualTypeArguments();
  342. boolean p_changed = getArgument(p_typeArg_args, typeVariables, arguments);
  343. if (p_changed) {
  344. typeArgs[i] = TypeReference.intern(
  345. new ParameterizedTypeImpl(p_typeArg_args, p_typeArg.getOwnerType(), p_typeArg.getRawType())
  346. );
  347. changed = true;
  348. }
  349. } else if (typeArg instanceof TypeVariable) {
  350. for (int j = 0; j < typeVariables.length; ++j) {
  351. if (typeArg.equals(typeVariables[j])) {
  352. typeArgs[i] = arguments[j];
  353. changed = true;
  354. }
  355. }
  356. }
  357. }
  358. return changed;
  359. }
  360. private static Type getInheritGenericType(Class<?> clazz, Type type, TypeVariable<?> tv) {
  361. GenericDeclaration gd = tv.getGenericDeclaration();
  362. Class<?> class_gd = null;
  363. if (gd instanceof Class) {
  364. class_gd = (Class<?>) tv.getGenericDeclaration();
  365. }
  366. Type[] arguments = null;
  367. if (class_gd == clazz) {
  368. if (type instanceof ParameterizedType) {
  369. ParameterizedType ptype = (ParameterizedType) type;
  370. arguments = ptype.getActualTypeArguments();
  371. }
  372. } else {
  373. for (Class<?> c = clazz; c != null && c != Object.class && c != class_gd; c = c.getSuperclass()) {
  374. Type superType = c.getGenericSuperclass();
  375. if (superType instanceof ParameterizedType) {
  376. ParameterizedType p_superType = (ParameterizedType) superType;
  377. Type[] p_superType_args = p_superType.getActualTypeArguments();
  378. getArgument(p_superType_args, c.getTypeParameters(), arguments);
  379. arguments = p_superType_args;
  380. }
  381. }
  382. }
  383. if (arguments == null || class_gd == null) {
  384. return null;
  385. }
  386. Type actualType = null;
  387. TypeVariable<?>[] typeVariables = class_gd.getTypeParameters();
  388. for (int j = 0; j < typeVariables.length; ++j) {
  389. if (tv.equals(typeVariables[j])) {
  390. actualType = arguments[j];
  391. break;
  392. }
  393. }
  394. return actualType;
  395. }
  396. public String toString() {
  397. return this.name;
  398. }
  399. public Member getMember() {
  400. if (method != null) {
  401. return method;
  402. } else {
  403. return field;
  404. }
  405. }
  406. protected Class<?> getDeclaredClass() {
  407. if (this.method != null) {
  408. return this.method.getDeclaringClass();
  409. }
  410. if (this.field != null) {
  411. return this.field.getDeclaringClass();
  412. }
  413. return null;
  414. }
  415. public int compareTo(FieldInfo o) {
  416. // Deal extend bridge
  417. if (o.method != null && this.method != null
  418. && o.method.isBridge() && !this.method.isBridge()
  419. && o.method.getName().equals(this.method.getName())) {
  420. return 1;
  421. }
  422. if (this.ordinal < o.ordinal) {
  423. return -1;
  424. }
  425. if (this.ordinal > o.ordinal) {
  426. return 1;
  427. }
  428. int result = this.name.compareTo(o.name);
  429. if (result != 0) {
  430. return result;
  431. }
  432. Class<?> thisDeclaringClass = this.getDeclaredClass();
  433. Class<?> otherDeclaringClass = o.getDeclaredClass();
  434. if (thisDeclaringClass != null && otherDeclaringClass != null && thisDeclaringClass != otherDeclaringClass) {
  435. if (thisDeclaringClass.isAssignableFrom(otherDeclaringClass)) {
  436. return -1;
  437. }
  438. if (otherDeclaringClass.isAssignableFrom(thisDeclaringClass)) {
  439. return 1;
  440. }
  441. }
  442. boolean isSampeType = this.field != null && this.field.getType() == this.fieldClass;
  443. boolean oSameType = o.field != null && o.field.getType() == o.fieldClass;
  444. if (isSampeType && !oSameType) {
  445. return 1;
  446. }
  447. if (oSameType && !isSampeType) {
  448. return -1;
  449. }
  450. if (o.fieldClass.isPrimitive() && !this.fieldClass.isPrimitive()) {
  451. return 1;
  452. }
  453. if (this.fieldClass.isPrimitive() && !o.fieldClass.isPrimitive()) {
  454. return -1;
  455. }
  456. if (o.fieldClass.getName().startsWith("java.") && !this.fieldClass.getName().startsWith("java.")) {
  457. return 1;
  458. }
  459. if (this.fieldClass.getName().startsWith("java.") && !o.fieldClass.getName().startsWith("java.")) {
  460. return -1;
  461. }
  462. return this.fieldClass.getName().compareTo(o.fieldClass.getName());
  463. }
  464. public JSONField getAnnotation() {
  465. if (this.fieldAnnotation != null) {
  466. return this.fieldAnnotation;
  467. }
  468. return this.methodAnnotation;
  469. }
  470. public String getFormat() {
  471. return format;
  472. }
  473. public Object get(Object javaObject) throws IllegalAccessException, InvocationTargetException {
  474. return method != null
  475. ? method.invoke(javaObject)
  476. : field.get(javaObject);
  477. }
  478. public void set(Object javaObject, Object value) throws IllegalAccessException, InvocationTargetException {
  479. if (method != null) {
  480. method.invoke(javaObject, new Object[] { value });
  481. return;
  482. }
  483. field.set(javaObject, value);
  484. }
  485. public void setAccessible() throws SecurityException {
  486. if (method != null) {
  487. TypeUtils.setAccessible(method);
  488. return;
  489. }
  490. TypeUtils.setAccessible(field);
  491. }
  492. }