blob: 5244eb870e693e56c25d8883cfa13c2f759cd98d [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
82 @Override
83 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; }
110
111 @Override
112 public boolean hasGetter() { return _getters != null; }
113
114 @Override
115 public boolean hasSetter() { return _setters != null; }
116
117 @Override
118 public boolean hasField() { return _fields != null; }
119
120 @Override
121 public boolean hasConstructorParameter() { return _ctorParameters != null; }
122
123 @Override
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800124 public boolean couldSerialize() {
125 return (_getters != null) || (_fields != null);
126 }
127
128 @Override
129 public AnnotatedMethod getGetter()
130 {
131 if (_getters == null) {
132 return null;
133 }
134 // If multiple, verify that they do not conflict...
135 AnnotatedMethod getter = _getters.value;
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800136 Linked<AnnotatedMethod> next = _getters.next;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800137 for (; next != null; next = next.next) {
138 /* [JACKSON-255] Allow masking, i.e. report exception only if
139 * declarations in same class, or there's no inheritance relationship
140 * (sibling interfaces etc)
141 */
142 AnnotatedMethod nextGetter = next.value;
143 Class<?> getterClass = getter.getDeclaringClass();
144 Class<?> nextClass = nextGetter.getDeclaringClass();
145 if (getterClass != nextClass) {
146 if (getterClass.isAssignableFrom(nextClass)) { // next is more specific
147 getter = nextGetter;
148 continue;
149 }
150 if (nextClass.isAssignableFrom(getterClass)) { // getter more specific
151 continue;
152 }
153 }
154 throw new IllegalArgumentException("Conflicting getter definitions for property \""+getName()+"\": "
155 +getter.getFullName()+" vs "+nextGetter.getFullName());
156 }
157 return getter;
158 }
159
160 @Override
161 public AnnotatedMethod getSetter()
162 {
163 if (_setters == null) {
164 return null;
165 }
166 // If multiple, verify that they do not conflict...
167 AnnotatedMethod setter = _setters.value;
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800168 Linked<AnnotatedMethod> next = _setters.next;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800169 for (; next != null; next = next.next) {
170 /* [JACKSON-255] Allow masking, i.e. report exception only if
171 * declarations in same class, or there's no inheritance relationship
172 * (sibling interfaces etc)
173 */
174 AnnotatedMethod nextSetter = next.value;
175 Class<?> setterClass = setter.getDeclaringClass();
176 Class<?> nextClass = nextSetter.getDeclaringClass();
177 if (setterClass != nextClass) {
178 if (setterClass.isAssignableFrom(nextClass)) { // next is more specific
179 setter = nextSetter;
180 continue;
181 }
182 if (nextClass.isAssignableFrom(setterClass)) { // getter more specific
183 continue;
184 }
185 }
186 throw new IllegalArgumentException("Conflicting setter definitions for property \""+getName()+"\": "
187 +setter.getFullName()+" vs "+nextSetter.getFullName());
188 }
189 return setter;
190 }
191
192 @Override
193 public AnnotatedField getField()
194 {
195 if (_fields == null) {
196 return null;
197 }
198 // If multiple, verify that they do not conflict...
199 AnnotatedField field = _fields.value;
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800200 Linked<AnnotatedField> next = _fields.next;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800201 for (; next != null; next = next.next) {
202 AnnotatedField nextField = next.value;
203 Class<?> fieldClass = field.getDeclaringClass();
204 Class<?> nextClass = nextField.getDeclaringClass();
205 if (fieldClass != nextClass) {
206 if (fieldClass.isAssignableFrom(nextClass)) { // next is more specific
207 field = nextField;
208 continue;
209 }
210 if (nextClass.isAssignableFrom(fieldClass)) { // getter more specific
211 continue;
212 }
213 }
214 throw new IllegalArgumentException("Multiple fields representing property \""+getName()+"\": "
215 +field.getFullName()+" vs "+nextField.getFullName());
216 }
217 return field;
218 }
219
220 @Override
221 public AnnotatedParameter getConstructorParameter()
222 {
223 if (_ctorParameters == null) {
224 return null;
225 }
226 /* Hmmh. Checking for constructor parameters is trickier; for one,
227 * we must allow creator and factory method annotations.
228 * If this is the case, constructor parameter has the precedence.
229 *
230 * So, for now, just try finding the first constructor parameter;
231 * if none, first factory method. And don't check for dups, if we must,
232 * can start checking for them later on.
233 */
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800234 Linked<AnnotatedParameter> curr = _ctorParameters;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800235 do {
236 if (curr.value.getOwner() instanceof AnnotatedConstructor) {
237 return curr.value;
238 }
239 curr = curr.next;
240 } while (curr != null);
241 return _ctorParameters.value;
242 }
243
Tatu Salorantae40a7692012-01-25 17:36:36 -0800244 @Override
245 public AnnotatedMember getAccessor()
246 {
247 AnnotatedMember m = getGetter();
248 if (m == null) {
249 m = getField();
250 }
251 return m;
252 }
253
254 @Override
255 public AnnotatedMember getMutator()
256 {
257 AnnotatedMember m = getConstructorParameter();
258 if (m == null) {
259 m = getSetter();
260 if (m == null) {
261 m = getField();
262 }
263 }
264 return m;
265 }
266
Tatu9550e092012-02-03 17:20:13 -0800267 /*
268 /*****************************************************
269 /* Implementations of refinement accessors
270 /*****************************************************
Tatu Salorantae40a7692012-01-25 17:36:36 -0800271 */
Tatu9550e092012-02-03 17:20:13 -0800272
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800273 @Override
274 public Class<?>[] findViews() {
275 return fromMemberAnnotation(new WithMember<Class<?>[]>() {
276 @Override public Class<?>[] withMember(AnnotatedMember member) {
277 return _annotationIntrospector.findViews(member);
Tatu Saloranta19ab5802012-01-26 22:26:18 -0800278 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800279 });
280 }
281
282 @Override
283 public AnnotationIntrospector.ReferenceProperty findReferenceType() {
284 return fromMemberAnnotation(new WithMember<AnnotationIntrospector.ReferenceProperty>() {
285 @Override public AnnotationIntrospector.ReferenceProperty withMember(AnnotatedMember member) {
286 return _annotationIntrospector.findReferenceType(member);
Tatu Saloranta19ab5802012-01-26 22:26:18 -0800287 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800288 });
Tatu Salorantae40a7692012-01-25 17:36:36 -0800289 }
Tatu9550e092012-02-03 17:20:13 -0800290
Tatu Salorantaeffb8fd2012-02-04 19:20:10 -0800291 @Override
Tatu9550e092012-02-03 17:20:13 -0800292 public boolean isTypeId() {
293 Boolean b = fromMemberAnnotation(new WithMember<Boolean>() {
294 @Override public Boolean withMember(AnnotatedMember member) {
295 return _annotationIntrospector.isTypeId(member);
296 }
297 });
298 return (b != null) && b.booleanValue();
299 }
Tatu Salorantaeffb8fd2012-02-04 19:20:10 -0800300
301 @Override
Tatu Saloranta2fd4ffd2012-02-17 22:40:13 -0800302 public boolean isRequired() {
303 Boolean b = fromMemberAnnotation(new WithMember<Boolean>() {
304 @Override public Boolean withMember(AnnotatedMember member) {
305 return _annotationIntrospector.hasRequiredMarker(member);
306 }
307 });
308 return (b != null) && b.booleanValue();
309 }
310
311 @Override
Tatu Salorantad4531822012-02-06 22:44:40 -0800312 public ObjectIdInfo findObjectIdInfo() {
313 return fromMemberAnnotation(new WithMember<ObjectIdInfo>() {
314 @Override public ObjectIdInfo withMember(AnnotatedMember member) {
315 return _annotationIntrospector.findObjectIdInfo(member);
Tatu Salorantaeffb8fd2012-02-04 19:20:10 -0800316 }
317 });
Tatu Salorantaeffb8fd2012-02-04 19:20:10 -0800318 }
Tatu Salorantae40a7692012-01-25 17:36:36 -0800319
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800320 /*
321 /**********************************************************
322 /* Data aggregation
323 /**********************************************************
324 */
325
326 public void addField(AnnotatedField a, String ename, boolean visible, boolean ignored) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800327 _fields = new Linked<AnnotatedField>(a, _fields, ename, visible, ignored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800328 }
329
330 public void addCtor(AnnotatedParameter a, String ename, boolean visible, boolean ignored) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800331 _ctorParameters = new Linked<AnnotatedParameter>(a, _ctorParameters, ename, visible, ignored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800332 }
333
334 public void addGetter(AnnotatedMethod a, String ename, boolean visible, boolean ignored) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800335 _getters = new Linked<AnnotatedMethod>(a, _getters, ename, visible, ignored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800336 }
337
338 public void addSetter(AnnotatedMethod a, String ename, boolean visible, boolean ignored) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800339 _setters = new Linked<AnnotatedMethod>(a, _setters, ename, visible, ignored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800340 }
341
342 /**
343 * Method for adding all property members from specified collector into
344 * this collector.
345 */
346 public void addAll(POJOPropertyBuilder src)
347 {
348 _fields = merge(_fields, src._fields);
349 _ctorParameters = merge(_ctorParameters, src._ctorParameters);
350 _getters= merge(_getters, src._getters);
351 _setters = merge(_setters, src._setters);
352 }
353
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800354 private static <T> Linked<T> merge(Linked<T> chain1, Linked<T> chain2)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800355 {
356 if (chain1 == null) {
357 return chain2;
358 }
359 if (chain2 == null) {
360 return chain1;
361 }
362 return chain1.append(chain2);
363 }
364
365 /*
366 /**********************************************************
367 /* Modifications
368 /**********************************************************
369 */
370
371 /**
372 * Method called to remove all entries that are marked as
373 * ignored.
374 */
375 public void removeIgnored()
376 {
377 _fields = _removeIgnored(_fields);
378 _getters = _removeIgnored(_getters);
379 _setters = _removeIgnored(_setters);
380 _ctorParameters = _removeIgnored(_ctorParameters);
381 }
382
383 public void removeNonVisible()
384 {
385 /* 21-Aug-2011, tatu: This is tricky part -- if and when allow
386 * non-visible property elements to be "pulled in" by visible
387 * counterparts?
388 * For now, we will only do this to pull in setter or field used
389 * as setter, if an explicit getter is found.
390 */
391 _getters = _removeNonVisible(_getters);
392 _ctorParameters = _removeNonVisible(_ctorParameters);
393
394 if (_getters == null) {
395 _fields = _removeNonVisible(_fields);
396 _setters = _removeNonVisible(_setters);
397 }
398 }
399
400 /**
401 * Method called to trim unnecessary entries, such as implicit
402 * getter if there is an explict one available. This is important
403 * for later stages, to avoid unnecessary conflicts.
404 */
405 public void trimByVisibility()
406 {
407 _fields = _trimByVisibility(_fields);
408 _getters = _trimByVisibility(_getters);
409 _setters = _trimByVisibility(_setters);
410 _ctorParameters = _trimByVisibility(_ctorParameters);
411 }
412
413 @SuppressWarnings("unchecked")
414 public void mergeAnnotations(boolean forSerialization)
415 {
416 if (forSerialization) {
417 if (_getters != null) {
418 AnnotationMap ann = _mergeAnnotations(0, _getters, _fields, _ctorParameters, _setters);
419 _getters = _getters.withValue(_getters.value.withAnnotations(ann));
420 } else if (_fields != null) {
421 AnnotationMap ann = _mergeAnnotations(0, _fields, _ctorParameters, _setters);
422 _fields = _fields.withValue(_fields.value.withAnnotations(ann));
423 }
424 } else {
425 if (_ctorParameters != null) {
426 AnnotationMap ann = _mergeAnnotations(0, _ctorParameters, _setters, _fields, _getters);
427 _ctorParameters = _ctorParameters.withValue(_ctorParameters.value.withAnnotations(ann));
428 } else if (_setters != null) {
429 AnnotationMap ann = _mergeAnnotations(0, _setters, _fields, _getters);
430 _setters = _setters.withValue(_setters.value.withAnnotations(ann));
431 } else if (_fields != null) {
432 AnnotationMap ann = _mergeAnnotations(0, _fields, _getters);
433 _fields = _fields.withValue(_fields.value.withAnnotations(ann));
434 }
435 }
436 }
437
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800438 private AnnotationMap _mergeAnnotations(int index, Linked<? extends AnnotatedMember>... nodes)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800439 {
440 AnnotationMap ann = nodes[index].value.getAllAnnotations();
441 ++index;
442 for (; index < nodes.length; ++index) {
443 if (nodes[index] != null) {
444 return AnnotationMap.merge(ann, _mergeAnnotations(index, nodes));
445 }
446 }
447 return ann;
448 }
449
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800450 private <T> Linked<T> _removeIgnored(Linked<T> node)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800451 {
452 if (node == null) {
453 return node;
454 }
455 return node.withoutIgnored();
456 }
457
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800458 private <T> Linked<T> _removeNonVisible(Linked<T> node)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800459 {
460 if (node == null) {
461 return node;
462 }
463 return node.withoutNonVisible();
464 }
465
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800466 private <T> Linked<T> _trimByVisibility(Linked<T> node)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800467 {
468 if (node == null) {
469 return node;
470 }
471 return node.trimByVisibility();
472 }
473
474 /*
475 /**********************************************************
476 /* Accessors for aggregate information
477 /**********************************************************
478 */
479
480 public boolean anyExplicitNames() {
481 return _anyExplicitNames(_fields)
482 || _anyExplicitNames(_getters)
483 || _anyExplicitNames(_setters)
484 || _anyExplicitNames(_ctorParameters)
485 ;
486 }
487
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800488 private <T> boolean _anyExplicitNames(Linked<T> n)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800489 {
490 for (; n != null; n = n.next) {
491 if (n.explicitName != null && n.explicitName.length() > 0) {
492 return true;
493 }
494 }
495 return false;
496 }
497
498 public boolean anyVisible() {
499 return _anyVisible(_fields)
500 || _anyVisible(_getters)
501 || _anyVisible(_setters)
502 || _anyVisible(_ctorParameters)
503 ;
504 }
505
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800506 private <T> boolean _anyVisible(Linked<T> n)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800507 {
508 for (; n != null; n = n.next) {
509 if (n.isVisible) {
510 return true;
511 }
512 }
513 return false;
514 }
515
516 public boolean anyIgnorals() {
517 return _anyIgnorals(_fields)
518 || _anyIgnorals(_getters)
519 || _anyIgnorals(_setters)
520 || _anyIgnorals(_ctorParameters)
521 ;
522 }
523
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800524 private <T> boolean _anyIgnorals(Linked<T> n)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800525 {
526 for (; n != null; n = n.next) {
527 if (n.isMarkedIgnored) {
528 return true;
529 }
530 }
531 return false;
532 }
533
534 /**
535 * Method called to check whether property represented by this collector
536 * should be renamed from the implicit name; and also verify that there
537 * are no conflicting rename definitions.
538 */
539 public String findNewName()
540 {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800541 Linked<? extends AnnotatedMember> renamed = null;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800542 renamed = findRenamed(_fields, renamed);
543 renamed = findRenamed(_getters, renamed);
544 renamed = findRenamed(_setters, renamed);
545 renamed = findRenamed(_ctorParameters, renamed);
546 return (renamed == null) ? null : renamed.explicitName;
547 }
548
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800549 private Linked<? extends AnnotatedMember> findRenamed(Linked<? extends AnnotatedMember> node,
550 Linked<? extends AnnotatedMember> renamed)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800551 {
552 for (; node != null; node = node.next) {
553 String explName = node.explicitName;
554 if (explName == null) {
555 continue;
556 }
557 // different from default name?
558 if (explName.equals(_name)) { // nope, skip
559 continue;
560 }
561 if (renamed == null) {
562 renamed = node;
563 } else {
564 // different from an earlier renaming? problem
565 if (!explName.equals(renamed.explicitName)) {
566 throw new IllegalStateException("Conflicting property name definitions: '"
567 +renamed.explicitName+"' (for "+renamed.value+") vs '"
568 +node.explicitName+"' (for "+node.value+")");
569 }
570 }
571 }
572 return renamed;
573 }
574
575 // For trouble-shooting
576 @Override
577 public String toString()
578 {
579 StringBuilder sb = new StringBuilder();
580 sb.append("[Property '").append(_name)
581 .append("'; ctors: ").append(_ctorParameters)
582 .append(", field(s): ").append(_fields)
583 .append(", getter(s): ").append(_getters)
584 .append(", setter(s): ").append(_setters)
585 ;
586 sb.append("]");
587 return sb.toString();
588 }
589
590 /*
591 /**********************************************************
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800592 /* Helper methods
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800593 /**********************************************************
594 */
595
596 /**
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800597 * Helper method used for finding annotation values
598 */
599 protected <T> T fromMemberAnnotation(WithMember<T> func)
600 {
601 T result = null;
602 if (_annotationIntrospector != null) {
603 if (_forSerialization) {
604 if (_getters != null) {
605 result = func.withMember(_getters.value);
606 }
607 } else {
608 if (_ctorParameters != null) {
609 result = func.withMember(_ctorParameters.value);
610 }
611 if (result == null && _setters != null) {
612 result = func.withMember(_setters.value);
613 }
614 }
615 if (result == null && _fields != null) {
616 result = func.withMember(_fields.value);
617 }
618 }
619 return result;
620 }
621
622 /*
623 /**********************************************************
624 /* Helper classes
625 /**********************************************************
626 */
627
628 private interface WithMember<T>
629 {
630 public T withMember(AnnotatedMember member);
631 }
632
633 /**
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800634 * Node used for creating simple linked lists to efficiently store small sets
635 * of things.
636 */
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800637 private final static class Linked<T>
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800638 {
639 public final T value;
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800640 public final Linked<T> next;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800641
642 public final String explicitName;
643 public final boolean isVisible;
644 public final boolean isMarkedIgnored;
645
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800646 public Linked(T v, Linked<T> n,
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800647 String explName, boolean visible, boolean ignored)
648 {
649 value = v;
650 next = n;
651 // ensure that we'll never have missing names
652 if (explName == null) {
653 explicitName = null;
654 } else {
655 explicitName = (explName.length() == 0) ? null : explName;
656 }
657 isVisible = visible;
658 isMarkedIgnored = ignored;
659 }
660
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800661 public Linked<T> withValue(T newValue)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800662 {
663 if (newValue == value) {
664 return this;
665 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800666 return new Linked<T>(newValue, next, explicitName, isVisible, isMarkedIgnored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800667 }
668
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800669 public Linked<T> withNext(Linked<T> newNext) {
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800670 if (newNext == next) {
671 return this;
672 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800673 return new Linked<T>(value, newNext, explicitName, isVisible, isMarkedIgnored);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800674 }
675
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800676 public Linked<T> withoutIgnored()
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800677 {
678 if (isMarkedIgnored) {
679 return (next == null) ? null : next.withoutIgnored();
680 }
681 if (next != null) {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800682 Linked<T> newNext = next.withoutIgnored();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800683 if (newNext != next) {
684 return withNext(newNext);
685 }
686 }
687 return this;
688 }
689
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800690 public Linked<T> withoutNonVisible()
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800691 {
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800692 Linked<T> newNext = (next == null) ? null : next.withoutNonVisible();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800693 return isVisible ? withNext(newNext) : newNext;
694 }
695
696 /**
697 * Method called to append given node(s) at the end of this
698 * node chain.
699 */
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800700 private Linked<T> append(Linked<T> appendable)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800701 {
702 if (next == null) {
703 return withNext(appendable);
704 }
705 return withNext(next.append(appendable));
706 }
707
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800708 public Linked<T> trimByVisibility()
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800709 {
710 if (next == null) {
711 return this;
712 }
Tatu Saloranta65c410c2012-01-27 20:44:45 -0800713 Linked<T> newNext = next.trimByVisibility();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800714 if (explicitName != null) { // this already has highest; how about next one?
715 if (newNext.explicitName == null) { // next one not, drop it
716 return withNext(null);
717 }
718 // both have it, keep
719 return withNext(newNext);
720 }
721 if (newNext.explicitName != null) { // next one has higher, return it...
722 return newNext;
723 }
724 // neither has explicit name; how about visibility?
725 if (isVisible == newNext.isVisible) { // same; keep both in current order
726 return withNext(newNext);
727 }
728 return isVisible ? withNext(null) : newNext;
729 }
730
731 @Override
732 public String toString() {
733 String msg = value.toString()+"[visible="+isVisible+"]";
734 if (next != null) {
735 msg = msg + ", "+next.toString();
736 }
737 return msg;
738 }
739 }
740}