blob: f3db0dc1a85003d65b7b39fd4e92147dd6fd1628 [file] [log] [blame]
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001package com.fasterxml.jackson.databind.introspect;
2
Tatu Salorantae40a7692012-01-25 17:36:36 -08003import com.fasterxml.jackson.databind.AnnotationIntrospector;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08004
5/**
6 * Helper class used for aggregating information about a single
7 * potential POJO property.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08008 */
9public class POJOPropertyBuilder
10 extends BeanPropertyDefinition
11 implements Comparable<POJOPropertyBuilder>
12{
13 /**
Tatu Salorantae40a7692012-01-25 17:36:36 -080014 * Whether property is being composed for serialization
15 * (true) or deserialization (false)
16 */
17 protected final boolean _forSerialization;
18
19 protected final AnnotationIntrospector _annotationIntrospector;
20
21 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080022 * External name of logical property; may change with
23 * renaming (by new instance being constructed using
24 * a new name)
25 */
26 protected final String _name;
27
28 /**
29 * Original internal name, derived from accessor, of this
30 * property. Will not be changed by renaming.
31 */
32 protected final String _internalName;
33
Tatu Saloranta65c410c2012-01-27 20:44:45 -080034 protected Linked<AnnotatedField> _fields;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080035
Tatu Saloranta65c410c2012-01-27 20:44:45 -080036 protected Linked<AnnotatedParameter> _ctorParameters;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080037
Tatu Saloranta65c410c2012-01-27 20:44:45 -080038 protected Linked<AnnotatedMethod> _getters;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080039
Tatu Saloranta65c410c2012-01-27 20:44:45 -080040 protected Linked<AnnotatedMethod> _setters;
Tatu Salorantae40a7692012-01-25 17:36:36 -080041
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -080042 public POJOPropertyBuilder(String internalName,
43 AnnotationIntrospector annotationIntrospector, boolean forSerialization)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080044 {
45 _internalName = internalName;
46 _name = internalName;
Tatu Salorantae40a7692012-01-25 17:36:36 -080047 _annotationIntrospector = annotationIntrospector;
48 _forSerialization = forSerialization;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080049 }
50
51 public POJOPropertyBuilder(POJOPropertyBuilder src, String newName)
52 {
53 _internalName = src._internalName;
54 _name = newName;
Tatu Salorantae40a7692012-01-25 17:36:36 -080055 _annotationIntrospector = src._annotationIntrospector;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080056 _fields = src._fields;
57 _ctorParameters = src._ctorParameters;
58 _getters = src._getters;
59 _setters = src._setters;
Tatu Salorantae40a7692012-01-25 17:36:36 -080060 _forSerialization = src._forSerialization;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080061 }
Tatu Salorantafbd795b2012-01-26 22:02:30 -080062
63 /*
64 /**********************************************************
65 /* Fluent factory methods
66 /**********************************************************
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080067 */
Tatu Salorantafbd795b2012-01-26 22:02:30 -080068
69 @Override
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080070 public POJOPropertyBuilder withName(String newName) {
71 return new POJOPropertyBuilder(this, newName);
72 }
73
74 /*
75 /**********************************************************
76 /* Comparable implementation: sort alphabetically, except
77 /* that properties with constructor parameters sorted
78 /* before other properties
79 /**********************************************************
80 */
81
Tatu Salorantaf1c79d42012-04-17 07:57:41 -070082// @Override
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080083 public int compareTo(POJOPropertyBuilder other)
84 {
85 // first, if one has ctor params, that should come first:
86 if (_ctorParameters != null) {
87 if (other._ctorParameters == null) {
88 return -1;
89 }
90 } else if (other._ctorParameters != null) {
91 return 1;
92 }
93 /* otherwise sort by external name (including sorting of
94 * ctor parameters)
95 */
96 return getName().compareTo(other.getName());
97 }
98
99 /*
100 /**********************************************************
101 /* BeanPropertyDefinition implementation
102 /**********************************************************
103 */
104
105 @Override
106 public String getName() { return _name; }
107
108 @Override
109 public String getInternalName() { return _internalName; }
Tatu Salorantad8e52fa2012-03-12 23:17:45 -0700110
111 @Override
112 public boolean isExplicitlyIncluded() {
113 return _anyExplicitNames(_fields)
114 || _anyExplicitNames(_getters)
115 || _anyExplicitNames(_setters)
116 || _anyExplicitNames(_ctorParameters)
117 ;
118 }
119
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800120
121 @Override
122 public boolean hasGetter() { return _getters != null; }
123
124 @Override
125 public boolean hasSetter() { return _setters != null; }
126
127 @Override
128 public boolean hasField() { return _fields != null; }
129
130 @Override
131 public boolean hasConstructorParameter() { return _ctorParameters != null; }
132
133 @Override
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800134 public boolean couldSerialize() {
135 return (_getters != null) || (_fields != null);
136 }
137
138 @Override
139 public AnnotatedMethod getGetter()
140 {
141 if (_getters == null) {
142 return null;
143 }
144 // If multiple, verify that they do not conflict...
145 AnnotatedMethod getter = _getters.value;
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800146 Linked<AnnotatedMethod> next = _getters.next;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800147 for (; next != null; next = next.next) {
148 /* [JACKSON-255] Allow masking, i.e. report exception only if
149 * declarations in same class, or there's no inheritance relationship
150 * (sibling interfaces etc)
151 */
152 AnnotatedMethod nextGetter = next.value;
153 Class<?> getterClass = getter.getDeclaringClass();
154 Class<?> nextClass = nextGetter.getDeclaringClass();
155 if (getterClass != nextClass) {
156 if (getterClass.isAssignableFrom(nextClass)) { // next is more specific
157 getter = nextGetter;
158 continue;
159 }
160 if (nextClass.isAssignableFrom(getterClass)) { // getter more specific
161 continue;
162 }
163 }
164 throw new IllegalArgumentException("Conflicting getter definitions for property \""+getName()+"\": "
165 +getter.getFullName()+" vs "+nextGetter.getFullName());
166 }
167 return getter;
168 }
169
170 @Override
171 public AnnotatedMethod getSetter()
172 {
173 if (_setters == null) {
174 return null;
175 }
176 // If multiple, verify that they do not conflict...
177 AnnotatedMethod setter = _setters.value;
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800178 Linked<AnnotatedMethod> next = _setters.next;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800179 for (; next != null; next = next.next) {
180 /* [JACKSON-255] Allow masking, i.e. report exception only if
181 * declarations in same class, or there's no inheritance relationship
182 * (sibling interfaces etc)
183 */
184 AnnotatedMethod nextSetter = next.value;
185 Class<?> setterClass = setter.getDeclaringClass();
186 Class<?> nextClass = nextSetter.getDeclaringClass();
187 if (setterClass != nextClass) {
188 if (setterClass.isAssignableFrom(nextClass)) { // next is more specific
189 setter = nextSetter;
190 continue;
191 }
192 if (nextClass.isAssignableFrom(setterClass)) { // getter more specific
193 continue;
194 }
195 }
196 throw new IllegalArgumentException("Conflicting setter definitions for property \""+getName()+"\": "
197 +setter.getFullName()+" vs "+nextSetter.getFullName());
198 }
199 return setter;
200 }
201
202 @Override
203 public AnnotatedField getField()
204 {
205 if (_fields == null) {
206 return null;
207 }
208 // If multiple, verify that they do not conflict...
209 AnnotatedField field = _fields.value;
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800210 Linked<AnnotatedField> next = _fields.next;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800211 for (; next != null; next = next.next) {
212 AnnotatedField nextField = next.value;
213 Class<?> fieldClass = field.getDeclaringClass();
214 Class<?> nextClass = nextField.getDeclaringClass();
215 if (fieldClass != nextClass) {
216 if (fieldClass.isAssignableFrom(nextClass)) { // next is more specific
217 field = nextField;
218 continue;
219 }
220 if (nextClass.isAssignableFrom(fieldClass)) { // getter more specific
221 continue;
222 }
223 }
224 throw new IllegalArgumentException("Multiple fields representing property \""+getName()+"\": "
225 +field.getFullName()+" vs "+nextField.getFullName());
226 }
227 return field;
228 }
229
230 @Override
231 public AnnotatedParameter getConstructorParameter()
232 {
233 if (_ctorParameters == null) {
234 return null;
235 }
236 /* Hmmh. Checking for constructor parameters is trickier; for one,
237 * we must allow creator and factory method annotations.
238 * If this is the case, constructor parameter has the precedence.
239 *
240 * So, for now, just try finding the first constructor parameter;
241 * if none, first factory method. And don't check for dups, if we must,
242 * can start checking for them later on.
243 */
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800244 Linked<AnnotatedParameter> curr = _ctorParameters;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800245 do {
246 if (curr.value.getOwner() instanceof AnnotatedConstructor) {
247 return curr.value;
248 }
249 curr = curr.next;
250 } while (curr != null);
251 return _ctorParameters.value;
252 }
253
Tatu Salorantae40a7692012-01-25 17:36:36 -0800254 @Override
255 public AnnotatedMember getAccessor()
256 {
257 AnnotatedMember m = getGetter();
258 if (m == null) {
259 m = getField();
260 }
261 return m;
262 }
263
264 @Override
265 public AnnotatedMember getMutator()
266 {
267 AnnotatedMember m = getConstructorParameter();
268 if (m == null) {
269 m = getSetter();
270 if (m == null) {
271 m = getField();
272 }
273 }
274 return m;
275 }
276
Tatu9550e092012-02-03 17:20:13 -0800277 /*
278 /*****************************************************
279 /* Implementations of refinement accessors
280 /*****************************************************
Tatu Salorantae40a7692012-01-25 17:36:36 -0800281 */
Tatu9550e092012-02-03 17:20:13 -0800282
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800283 @Override
284 public Class<?>[] findViews() {
285 return fromMemberAnnotation(new WithMember<Class<?>[]>() {
Tatu Salorantaf1c79d42012-04-17 07:57:41 -0700286 public Class<?>[] withMember(AnnotatedMember member) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800287 return _annotationIntrospector.findViews(member);
Tatu Saloranta19ab5802012-01-26 22:26:18 -0800288 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800289 });
290 }
291
292 @Override
293 public AnnotationIntrospector.ReferenceProperty findReferenceType() {
294 return fromMemberAnnotation(new WithMember<AnnotationIntrospector.ReferenceProperty>() {
Tatu Salorantaf1c79d42012-04-17 07:57:41 -0700295 public AnnotationIntrospector.ReferenceProperty withMember(AnnotatedMember member) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800296 return _annotationIntrospector.findReferenceType(member);
Tatu Saloranta19ab5802012-01-26 22:26:18 -0800297 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800298 });
Tatu Salorantae40a7692012-01-25 17:36:36 -0800299 }
Tatu9550e092012-02-03 17:20:13 -0800300
Tatu Salorantaeffb8fd2012-02-04 19:20:10 -0800301 @Override
Tatu9550e092012-02-03 17:20:13 -0800302 public boolean isTypeId() {
303 Boolean b = fromMemberAnnotation(new WithMember<Boolean>() {
Tatu Salorantaf1c79d42012-04-17 07:57:41 -0700304 public Boolean withMember(AnnotatedMember member) {
Tatu9550e092012-02-03 17:20:13 -0800305 return _annotationIntrospector.isTypeId(member);
306 }
307 });
308 return (b != null) && b.booleanValue();
309 }
Tatu Salorantaeffb8fd2012-02-04 19:20:10 -0800310
311 @Override
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800312 public boolean isRequired() {
313 Boolean b = fromMemberAnnotation(new WithMember<Boolean>() {
Tatu Salorantaf1c79d42012-04-17 07:57:41 -0700314 public Boolean withMember(AnnotatedMember member) {
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800315 return _annotationIntrospector.hasRequiredMarker(member);
316 }
317 });
318 return (b != null) && b.booleanValue();
319 }
320
321 @Override
Tatu Salorantad4531822012-02-06 22:44:40 -0800322 public ObjectIdInfo findObjectIdInfo() {
323 return fromMemberAnnotation(new WithMember<ObjectIdInfo>() {
Tatu Salorantaf1c79d42012-04-17 07:57:41 -0700324 public ObjectIdInfo withMember(AnnotatedMember member) {
Tatu Salorantad4531822012-02-06 22:44:40 -0800325 return _annotationIntrospector.findObjectIdInfo(member);
Tatu Salorantaeffb8fd2012-02-04 19:20:10 -0800326 }
327 });
Tatu Salorantaeffb8fd2012-02-04 19:20:10 -0800328 }
Tatu Salorantae40a7692012-01-25 17:36:36 -0800329
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800330 /*
331 /**********************************************************
332 /* Data aggregation
333 /**********************************************************
334 */
335
336 public void addField(AnnotatedField a, String ename, boolean visible, boolean ignored) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800337 _fields = new Linked<AnnotatedField>(a, _fields, ename, visible, ignored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800338 }
339
340 public void addCtor(AnnotatedParameter a, String ename, boolean visible, boolean ignored) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800341 _ctorParameters = new Linked<AnnotatedParameter>(a, _ctorParameters, ename, visible, ignored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800342 }
343
344 public void addGetter(AnnotatedMethod a, String ename, boolean visible, boolean ignored) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800345 _getters = new Linked<AnnotatedMethod>(a, _getters, ename, visible, ignored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800346 }
347
348 public void addSetter(AnnotatedMethod a, String ename, boolean visible, boolean ignored) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800349 _setters = new Linked<AnnotatedMethod>(a, _setters, ename, visible, ignored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800350 }
351
352 /**
353 * Method for adding all property members from specified collector into
354 * this collector.
355 */
356 public void addAll(POJOPropertyBuilder src)
357 {
358 _fields = merge(_fields, src._fields);
359 _ctorParameters = merge(_ctorParameters, src._ctorParameters);
360 _getters= merge(_getters, src._getters);
361 _setters = merge(_setters, src._setters);
362 }
363
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800364 private static <T> Linked<T> merge(Linked<T> chain1, Linked<T> chain2)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800365 {
366 if (chain1 == null) {
367 return chain2;
368 }
369 if (chain2 == null) {
370 return chain1;
371 }
372 return chain1.append(chain2);
373 }
374
375 /*
376 /**********************************************************
377 /* Modifications
378 /**********************************************************
379 */
380
381 /**
382 * Method called to remove all entries that are marked as
383 * ignored.
384 */
385 public void removeIgnored()
386 {
387 _fields = _removeIgnored(_fields);
388 _getters = _removeIgnored(_getters);
389 _setters = _removeIgnored(_setters);
390 _ctorParameters = _removeIgnored(_ctorParameters);
391 }
392
393 public void removeNonVisible()
394 {
395 /* 21-Aug-2011, tatu: This is tricky part -- if and when allow
396 * non-visible property elements to be "pulled in" by visible
397 * counterparts?
398 * For now, we will only do this to pull in setter or field used
399 * as setter, if an explicit getter is found.
400 */
401 _getters = _removeNonVisible(_getters);
402 _ctorParameters = _removeNonVisible(_ctorParameters);
403
404 if (_getters == null) {
405 _fields = _removeNonVisible(_fields);
406 _setters = _removeNonVisible(_setters);
407 }
408 }
409
410 /**
411 * Method called to trim unnecessary entries, such as implicit
412 * getter if there is an explict one available. This is important
413 * for later stages, to avoid unnecessary conflicts.
414 */
415 public void trimByVisibility()
416 {
417 _fields = _trimByVisibility(_fields);
418 _getters = _trimByVisibility(_getters);
419 _setters = _trimByVisibility(_setters);
420 _ctorParameters = _trimByVisibility(_ctorParameters);
421 }
422
423 @SuppressWarnings("unchecked")
424 public void mergeAnnotations(boolean forSerialization)
425 {
426 if (forSerialization) {
427 if (_getters != null) {
428 AnnotationMap ann = _mergeAnnotations(0, _getters, _fields, _ctorParameters, _setters);
429 _getters = _getters.withValue(_getters.value.withAnnotations(ann));
430 } else if (_fields != null) {
431 AnnotationMap ann = _mergeAnnotations(0, _fields, _ctorParameters, _setters);
432 _fields = _fields.withValue(_fields.value.withAnnotations(ann));
433 }
434 } else {
435 if (_ctorParameters != null) {
436 AnnotationMap ann = _mergeAnnotations(0, _ctorParameters, _setters, _fields, _getters);
437 _ctorParameters = _ctorParameters.withValue(_ctorParameters.value.withAnnotations(ann));
438 } else if (_setters != null) {
439 AnnotationMap ann = _mergeAnnotations(0, _setters, _fields, _getters);
440 _setters = _setters.withValue(_setters.value.withAnnotations(ann));
441 } else if (_fields != null) {
442 AnnotationMap ann = _mergeAnnotations(0, _fields, _getters);
443 _fields = _fields.withValue(_fields.value.withAnnotations(ann));
444 }
445 }
446 }
447
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800448 private AnnotationMap _mergeAnnotations(int index, Linked<? extends AnnotatedMember>... nodes)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800449 {
450 AnnotationMap ann = nodes[index].value.getAllAnnotations();
451 ++index;
452 for (; index < nodes.length; ++index) {
453 if (nodes[index] != null) {
454 return AnnotationMap.merge(ann, _mergeAnnotations(index, nodes));
455 }
456 }
457 return ann;
458 }
459
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800460 private <T> Linked<T> _removeIgnored(Linked<T> node)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800461 {
462 if (node == null) {
463 return node;
464 }
465 return node.withoutIgnored();
466 }
467
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800468 private <T> Linked<T> _removeNonVisible(Linked<T> node)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800469 {
470 if (node == null) {
471 return node;
472 }
473 return node.withoutNonVisible();
474 }
475
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800476 private <T> Linked<T> _trimByVisibility(Linked<T> node)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800477 {
478 if (node == null) {
479 return node;
480 }
481 return node.trimByVisibility();
482 }
483
484 /*
485 /**********************************************************
486 /* Accessors for aggregate information
487 /**********************************************************
488 */
489
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800490 private <T> boolean _anyExplicitNames(Linked<T> n)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800491 {
492 for (; n != null; n = n.next) {
493 if (n.explicitName != null && n.explicitName.length() > 0) {
494 return true;
495 }
496 }
497 return false;
498 }
499
500 public boolean anyVisible() {
501 return _anyVisible(_fields)
502 || _anyVisible(_getters)
503 || _anyVisible(_setters)
504 || _anyVisible(_ctorParameters)
505 ;
506 }
507
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800508 private <T> boolean _anyVisible(Linked<T> n)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800509 {
510 for (; n != null; n = n.next) {
511 if (n.isVisible) {
512 return true;
513 }
514 }
515 return false;
516 }
517
518 public boolean anyIgnorals() {
519 return _anyIgnorals(_fields)
520 || _anyIgnorals(_getters)
521 || _anyIgnorals(_setters)
522 || _anyIgnorals(_ctorParameters)
523 ;
524 }
525
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800526 private <T> boolean _anyIgnorals(Linked<T> n)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800527 {
528 for (; n != null; n = n.next) {
529 if (n.isMarkedIgnored) {
530 return true;
531 }
532 }
533 return false;
534 }
535
536 /**
537 * Method called to check whether property represented by this collector
538 * should be renamed from the implicit name; and also verify that there
539 * are no conflicting rename definitions.
540 */
541 public String findNewName()
542 {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800543 Linked<? extends AnnotatedMember> renamed = null;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800544 renamed = findRenamed(_fields, renamed);
545 renamed = findRenamed(_getters, renamed);
546 renamed = findRenamed(_setters, renamed);
547 renamed = findRenamed(_ctorParameters, renamed);
548 return (renamed == null) ? null : renamed.explicitName;
549 }
550
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800551 private Linked<? extends AnnotatedMember> findRenamed(Linked<? extends AnnotatedMember> node,
552 Linked<? extends AnnotatedMember> renamed)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800553 {
554 for (; node != null; node = node.next) {
555 String explName = node.explicitName;
556 if (explName == null) {
557 continue;
558 }
559 // different from default name?
560 if (explName.equals(_name)) { // nope, skip
561 continue;
562 }
563 if (renamed == null) {
564 renamed = node;
565 } else {
566 // different from an earlier renaming? problem
567 if (!explName.equals(renamed.explicitName)) {
568 throw new IllegalStateException("Conflicting property name definitions: '"
569 +renamed.explicitName+"' (for "+renamed.value+") vs '"
570 +node.explicitName+"' (for "+node.value+")");
571 }
572 }
573 }
574 return renamed;
575 }
576
577 // For trouble-shooting
578 @Override
579 public String toString()
580 {
581 StringBuilder sb = new StringBuilder();
582 sb.append("[Property '").append(_name)
583 .append("'; ctors: ").append(_ctorParameters)
584 .append(", field(s): ").append(_fields)
585 .append(", getter(s): ").append(_getters)
586 .append(", setter(s): ").append(_setters)
587 ;
588 sb.append("]");
589 return sb.toString();
590 }
591
592 /*
593 /**********************************************************
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800594 /* Helper methods
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800595 /**********************************************************
596 */
597
598 /**
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800599 * Helper method used for finding annotation values
600 */
601 protected <T> T fromMemberAnnotation(WithMember<T> func)
602 {
603 T result = null;
604 if (_annotationIntrospector != null) {
605 if (_forSerialization) {
606 if (_getters != null) {
607 result = func.withMember(_getters.value);
608 }
609 } else {
610 if (_ctorParameters != null) {
611 result = func.withMember(_ctorParameters.value);
612 }
613 if (result == null && _setters != null) {
614 result = func.withMember(_setters.value);
615 }
616 }
617 if (result == null && _fields != null) {
618 result = func.withMember(_fields.value);
619 }
620 }
621 return result;
622 }
623
624 /*
625 /**********************************************************
626 /* Helper classes
627 /**********************************************************
628 */
629
630 private interface WithMember<T>
631 {
632 public T withMember(AnnotatedMember member);
633 }
634
635 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800636 * Node used for creating simple linked lists to efficiently store small sets
637 * of things.
638 */
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800639 private final static class Linked<T>
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800640 {
641 public final T value;
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800642 public final Linked<T> next;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800643
644 public final String explicitName;
645 public final boolean isVisible;
646 public final boolean isMarkedIgnored;
647
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800648 public Linked(T v, Linked<T> n,
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800649 String explName, boolean visible, boolean ignored)
650 {
651 value = v;
652 next = n;
653 // ensure that we'll never have missing names
654 if (explName == null) {
655 explicitName = null;
656 } else {
657 explicitName = (explName.length() == 0) ? null : explName;
658 }
659 isVisible = visible;
660 isMarkedIgnored = ignored;
661 }
662
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800663 public Linked<T> withValue(T newValue)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800664 {
665 if (newValue == value) {
666 return this;
667 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800668 return new Linked<T>(newValue, next, explicitName, isVisible, isMarkedIgnored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800669 }
670
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800671 public Linked<T> withNext(Linked<T> newNext) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800672 if (newNext == next) {
673 return this;
674 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800675 return new Linked<T>(value, newNext, explicitName, isVisible, isMarkedIgnored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800676 }
677
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800678 public Linked<T> withoutIgnored()
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800679 {
680 if (isMarkedIgnored) {
681 return (next == null) ? null : next.withoutIgnored();
682 }
683 if (next != null) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800684 Linked<T> newNext = next.withoutIgnored();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800685 if (newNext != next) {
686 return withNext(newNext);
687 }
688 }
689 return this;
690 }
691
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800692 public Linked<T> withoutNonVisible()
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800693 {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800694 Linked<T> newNext = (next == null) ? null : next.withoutNonVisible();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800695 return isVisible ? withNext(newNext) : newNext;
696 }
697
698 /**
699 * Method called to append given node(s) at the end of this
700 * node chain.
701 */
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800702 private Linked<T> append(Linked<T> appendable)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800703 {
704 if (next == null) {
705 return withNext(appendable);
706 }
707 return withNext(next.append(appendable));
708 }
709
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800710 public Linked<T> trimByVisibility()
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800711 {
712 if (next == null) {
713 return this;
714 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800715 Linked<T> newNext = next.trimByVisibility();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800716 if (explicitName != null) { // this already has highest; how about next one?
717 if (newNext.explicitName == null) { // next one not, drop it
718 return withNext(null);
719 }
720 // both have it, keep
721 return withNext(newNext);
722 }
723 if (newNext.explicitName != null) { // next one has higher, return it...
724 return newNext;
725 }
726 // neither has explicit name; how about visibility?
727 if (isVisible == newNext.isVisible) { // same; keep both in current order
728 return withNext(newNext);
729 }
730 return isVisible ? withNext(null) : newNext;
731 }
732
733 @Override
734 public String toString() {
735 String msg = value.toString()+"[visible="+isVisible+"]";
736 if (next != null) {
737 msg = msg + ", "+next.toString();
738 }
739 return msg;
740 }
741 }
742}