1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.lang.reflect.Field;
4 import java.lang.reflect.Modifier;
5 import java.util.*;
6
7 import com.fasterxml.jackson.databind.AnnotationIntrospector;
8 import com.fasterxml.jackson.databind.JavaType;
9 import com.fasterxml.jackson.databind.introspect.ClassIntrospector.MixInResolver;
10 import com.fasterxml.jackson.databind.type.TypeFactory;
11 import com.fasterxml.jackson.databind.util.ClassUtil;
12
13 public class AnnotatedFieldCollector
14 extends CollectorBase
15 {
16
17
18 private final TypeFactory _typeFactory;
19 private final MixInResolver _mixInResolver;
20
21
24 private final boolean _collectAnnotations;
25
26
27
28 AnnotatedFieldCollector(AnnotationIntrospector intr,
29 TypeFactory types, MixInResolver mixins, boolean collectAnnotations)
30 {
31 super(intr);
32 _typeFactory = types;
33 _mixInResolver = (intr == null) ? null : mixins;
34 _collectAnnotations = collectAnnotations;
35 }
36
37 public static List<AnnotatedField> collectFields(AnnotationIntrospector intr,
38 TypeResolutionContext tc,
39 MixInResolver mixins, TypeFactory types,
40 JavaType type, boolean collectAnnotations)
41 {
42 return new AnnotatedFieldCollector(intr, types, mixins, collectAnnotations)
43 .collect(tc, type);
44 }
45
46 List<AnnotatedField> collect(TypeResolutionContext tc, JavaType type)
47 {
48 Map<String,FieldBuilder> foundFields = _findFields(tc, type, null);
49 if (foundFields == null) {
50 return Collections.emptyList();
51 }
52 List<AnnotatedField> result = new ArrayList<>(foundFields.size());
53 for (FieldBuilder b : foundFields.values()) {
54 result.add(b.build());
55 }
56 return result;
57 }
58
59 private Map<String,FieldBuilder> _findFields(TypeResolutionContext tc,
60 JavaType type, Map<String,FieldBuilder> fields)
61 {
62
63
64
65 JavaType parent = type.getSuperClass();
66 if (parent == null) {
67 return fields;
68 }
69 final Class<?> cls = type.getRawClass();
70
71 fields = _findFields(new TypeResolutionContext.Basic(_typeFactory, parent.getBindings()),
72 parent, fields);
73 for (Field f : cls.getDeclaredFields()) {
74
75 if (!_isIncludableField(f)) {
76 continue;
77 }
78
79
80
81 if (fields == null) {
82 fields = new LinkedHashMap<>();
83 }
84 FieldBuilder b = new FieldBuilder(tc, f);
85 if (_collectAnnotations) {
86 b.annotations = collectAnnotations(b.annotations, f.getDeclaredAnnotations());
87 }
88 fields.put(f.getName(), b);
89 }
90
91 if ((fields != null) && (_mixInResolver != null)) {
92 Class<?> mixin = _mixInResolver.findMixInClassFor(cls);
93 if (mixin != null) {
94 _addFieldMixIns(mixin, cls, fields);
95 }
96 }
97 return fields;
98 }
99
100
105 private void _addFieldMixIns(Class<?> mixInCls, Class<?> targetClass,
106 Map<String,FieldBuilder> fields)
107 {
108 List<Class<?>> parents = ClassUtil.findSuperClasses(mixInCls, targetClass, true);
109 for (Class<?> mixin : parents) {
110 for (Field mixinField : mixin.getDeclaredFields()) {
111
112 if (!_isIncludableField(mixinField)) {
113 continue;
114 }
115 String name = mixinField.getName();
116
117 FieldBuilder b = fields.get(name);
118 if (b != null) {
119 b.annotations = collectAnnotations(b.annotations, mixinField.getDeclaredAnnotations());
120 }
121 }
122 }
123 }
124
125 private boolean _isIncludableField(Field f)
126 {
127
128 if (f.isSynthetic()) {
129 return false;
130 }
131
132
133 int mods = f.getModifiers();
134 if (Modifier.isStatic(mods)) {
135 return false;
136 }
137 return true;
138 }
139
140 private final static class FieldBuilder {
141 public final TypeResolutionContext typeContext;
142 public final Field field;
143
144 public AnnotationCollector annotations;
145
146 public FieldBuilder(TypeResolutionContext tc, Field f) {
147 typeContext = tc;
148 field = f;
149 annotations = AnnotationCollector.emptyCollector();
150 }
151
152 public AnnotatedField build() {
153 return new AnnotatedField(typeContext, field, annotations.asAnnotationMap());
154 }
155 }
156 }
157