Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 1 | package com.fasterxml.jackson.databind.introspect; |
| 2 | |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 3 | import com.fasterxml.jackson.databind.AnnotationIntrospector; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 4 | |
| 5 | /** |
| 6 | * Helper class used for aggregating information about a single |
| 7 | * potential POJO property. |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 8 | */ |
| 9 | public class POJOPropertyBuilder |
| 10 | extends BeanPropertyDefinition |
| 11 | implements Comparable<POJOPropertyBuilder> |
| 12 | { |
| 13 | /** |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 14 | * 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 Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 22 | * 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 34 | protected Linked<AnnotatedField> _fields; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 35 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 36 | protected Linked<AnnotatedParameter> _ctorParameters; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 37 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 38 | protected Linked<AnnotatedMethod> _getters; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 39 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 40 | protected Linked<AnnotatedMethod> _setters; |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 41 | |
Tatu Saloranta | 2fd4ffd | 2012-02-17 22:40:13 -0800 | [diff] [blame] | 42 | public POJOPropertyBuilder(String internalName, |
| 43 | AnnotationIntrospector annotationIntrospector, boolean forSerialization) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 44 | { |
| 45 | _internalName = internalName; |
| 46 | _name = internalName; |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 47 | _annotationIntrospector = annotationIntrospector; |
| 48 | _forSerialization = forSerialization; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | public POJOPropertyBuilder(POJOPropertyBuilder src, String newName) |
| 52 | { |
| 53 | _internalName = src._internalName; |
| 54 | _name = newName; |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 55 | _annotationIntrospector = src._annotationIntrospector; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 56 | _fields = src._fields; |
| 57 | _ctorParameters = src._ctorParameters; |
| 58 | _getters = src._getters; |
| 59 | _setters = src._setters; |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 60 | _forSerialization = src._forSerialization; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 61 | } |
Tatu Saloranta | fbd795b | 2012-01-26 22:02:30 -0800 | [diff] [blame] | 62 | |
| 63 | /* |
| 64 | /********************************************************** |
| 65 | /* Fluent factory methods |
| 66 | /********************************************************** |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 67 | */ |
Tatu Saloranta | fbd795b | 2012-01-26 22:02:30 -0800 | [diff] [blame] | 68 | |
| 69 | @Override |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 70 | 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 Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 124 | 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 136 | Linked<AnnotatedMethod> next = _getters.next; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 137 | 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 168 | Linked<AnnotatedMethod> next = _setters.next; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 169 | 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 200 | Linked<AnnotatedField> next = _fields.next; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 201 | 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 234 | Linked<AnnotatedParameter> curr = _ctorParameters; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 235 | 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 Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 244 | @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 | |
Tatu | 9550e09 | 2012-02-03 17:20:13 -0800 | [diff] [blame] | 267 | /* |
| 268 | /***************************************************** |
| 269 | /* Implementations of refinement accessors |
| 270 | /***************************************************** |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 271 | */ |
Tatu | 9550e09 | 2012-02-03 17:20:13 -0800 | [diff] [blame] | 272 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 273 | @Override |
| 274 | public Class<?>[] findViews() { |
| 275 | return fromMemberAnnotation(new WithMember<Class<?>[]>() { |
| 276 | @Override public Class<?>[] withMember(AnnotatedMember member) { |
| 277 | return _annotationIntrospector.findViews(member); |
Tatu Saloranta | 19ab580 | 2012-01-26 22:26:18 -0800 | [diff] [blame] | 278 | } |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 279 | }); |
| 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 Saloranta | 19ab580 | 2012-01-26 22:26:18 -0800 | [diff] [blame] | 287 | } |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 288 | }); |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 289 | } |
Tatu | 9550e09 | 2012-02-03 17:20:13 -0800 | [diff] [blame] | 290 | |
Tatu Saloranta | effb8fd | 2012-02-04 19:20:10 -0800 | [diff] [blame] | 291 | @Override |
Tatu | 9550e09 | 2012-02-03 17:20:13 -0800 | [diff] [blame] | 292 | 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 Saloranta | effb8fd | 2012-02-04 19:20:10 -0800 | [diff] [blame] | 300 | |
| 301 | @Override |
Tatu Saloranta | 2fd4ffd | 2012-02-17 22:40:13 -0800 | [diff] [blame] | 302 | 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 Saloranta | d453182 | 2012-02-06 22:44:40 -0800 | [diff] [blame] | 312 | public ObjectIdInfo findObjectIdInfo() { |
| 313 | return fromMemberAnnotation(new WithMember<ObjectIdInfo>() { |
| 314 | @Override public ObjectIdInfo withMember(AnnotatedMember member) { |
| 315 | return _annotationIntrospector.findObjectIdInfo(member); |
Tatu Saloranta | effb8fd | 2012-02-04 19:20:10 -0800 | [diff] [blame] | 316 | } |
| 317 | }); |
Tatu Saloranta | effb8fd | 2012-02-04 19:20:10 -0800 | [diff] [blame] | 318 | } |
Tatu Saloranta | e40a769 | 2012-01-25 17:36:36 -0800 | [diff] [blame] | 319 | |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 320 | /* |
| 321 | /********************************************************** |
| 322 | /* Data aggregation |
| 323 | /********************************************************** |
| 324 | */ |
| 325 | |
| 326 | public void addField(AnnotatedField a, String ename, boolean visible, boolean ignored) { |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 327 | _fields = new Linked<AnnotatedField>(a, _fields, ename, visible, ignored); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 328 | } |
| 329 | |
| 330 | public void addCtor(AnnotatedParameter a, String ename, boolean visible, boolean ignored) { |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 331 | _ctorParameters = new Linked<AnnotatedParameter>(a, _ctorParameters, ename, visible, ignored); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | public void addGetter(AnnotatedMethod a, String ename, boolean visible, boolean ignored) { |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 335 | _getters = new Linked<AnnotatedMethod>(a, _getters, ename, visible, ignored); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 336 | } |
| 337 | |
| 338 | public void addSetter(AnnotatedMethod a, String ename, boolean visible, boolean ignored) { |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 339 | _setters = new Linked<AnnotatedMethod>(a, _setters, ename, visible, ignored); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 340 | } |
| 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 354 | private static <T> Linked<T> merge(Linked<T> chain1, Linked<T> chain2) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 355 | { |
| 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 438 | private AnnotationMap _mergeAnnotations(int index, Linked<? extends AnnotatedMember>... nodes) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 439 | { |
| 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 450 | private <T> Linked<T> _removeIgnored(Linked<T> node) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 451 | { |
| 452 | if (node == null) { |
| 453 | return node; |
| 454 | } |
| 455 | return node.withoutIgnored(); |
| 456 | } |
| 457 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 458 | private <T> Linked<T> _removeNonVisible(Linked<T> node) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 459 | { |
| 460 | if (node == null) { |
| 461 | return node; |
| 462 | } |
| 463 | return node.withoutNonVisible(); |
| 464 | } |
| 465 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 466 | private <T> Linked<T> _trimByVisibility(Linked<T> node) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 467 | { |
| 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 488 | private <T> boolean _anyExplicitNames(Linked<T> n) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 489 | { |
| 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 506 | private <T> boolean _anyVisible(Linked<T> n) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 507 | { |
| 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 524 | private <T> boolean _anyIgnorals(Linked<T> n) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 525 | { |
| 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 541 | Linked<? extends AnnotatedMember> renamed = null; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 542 | 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 549 | private Linked<? extends AnnotatedMember> findRenamed(Linked<? extends AnnotatedMember> node, |
| 550 | Linked<? extends AnnotatedMember> renamed) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 551 | { |
| 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 592 | /* Helper methods |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 593 | /********************************************************** |
| 594 | */ |
| 595 | |
| 596 | /** |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 597 | * 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 Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 634 | * Node used for creating simple linked lists to efficiently store small sets |
| 635 | * of things. |
| 636 | */ |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 637 | private final static class Linked<T> |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 638 | { |
| 639 | public final T value; |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 640 | public final Linked<T> next; |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 641 | |
| 642 | public final String explicitName; |
| 643 | public final boolean isVisible; |
| 644 | public final boolean isMarkedIgnored; |
| 645 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 646 | public Linked(T v, Linked<T> n, |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 647 | 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 661 | public Linked<T> withValue(T newValue) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 662 | { |
| 663 | if (newValue == value) { |
| 664 | return this; |
| 665 | } |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 666 | return new Linked<T>(newValue, next, explicitName, isVisible, isMarkedIgnored); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 667 | } |
| 668 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 669 | public Linked<T> withNext(Linked<T> newNext) { |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 670 | if (newNext == next) { |
| 671 | return this; |
| 672 | } |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 673 | return new Linked<T>(value, newNext, explicitName, isVisible, isMarkedIgnored); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 674 | } |
| 675 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 676 | public Linked<T> withoutIgnored() |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 677 | { |
| 678 | if (isMarkedIgnored) { |
| 679 | return (next == null) ? null : next.withoutIgnored(); |
| 680 | } |
| 681 | if (next != null) { |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 682 | Linked<T> newNext = next.withoutIgnored(); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 683 | if (newNext != next) { |
| 684 | return withNext(newNext); |
| 685 | } |
| 686 | } |
| 687 | return this; |
| 688 | } |
| 689 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 690 | public Linked<T> withoutNonVisible() |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 691 | { |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 692 | Linked<T> newNext = (next == null) ? null : next.withoutNonVisible(); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 693 | 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 Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 700 | private Linked<T> append(Linked<T> appendable) |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 701 | { |
| 702 | if (next == null) { |
| 703 | return withNext(appendable); |
| 704 | } |
| 705 | return withNext(next.append(appendable)); |
| 706 | } |
| 707 | |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 708 | public Linked<T> trimByVisibility() |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 709 | { |
| 710 | if (next == null) { |
| 711 | return this; |
| 712 | } |
Tatu Saloranta | 65c410c | 2012-01-27 20:44:45 -0800 | [diff] [blame] | 713 | Linked<T> newNext = next.trimByVisibility(); |
Tatu Saloranta | e4f23bb | 2011-12-23 00:31:35 -0800 | [diff] [blame] | 714 | 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 | } |