001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau; 018 019import static org.apache.juneau.collections.JsonMap.*; 020import static org.apache.juneau.common.utils.ThrowableUtils.*; 021import static org.apache.juneau.common.utils.Utils.*; 022import static org.apache.juneau.internal.ClassUtils.*; 023import static org.apache.juneau.internal.CollectionUtils.*; 024import static org.apache.juneau.internal.ConsumerUtils.*; 025 026import java.lang.annotation.*; 027import java.lang.reflect.*; 028import java.util.*; 029import java.util.concurrent.*; 030import java.util.function.*; 031 032import org.apache.juneau.annotation.*; 033import org.apache.juneau.collections.*; 034import org.apache.juneau.common.utils.*; 035import org.apache.juneau.csv.annotation.*; 036import org.apache.juneau.html.annotation.*; 037import org.apache.juneau.internal.*; 038import org.apache.juneau.json.annotation.*; 039import org.apache.juneau.jsonschema.annotation.*; 040import org.apache.juneau.msgpack.annotation.*; 041import org.apache.juneau.oapi.annotation.*; 042import org.apache.juneau.parser.annotation.*; 043import org.apache.juneau.plaintext.annotation.*; 044import org.apache.juneau.reflect.*; 045import org.apache.juneau.serializer.annotation.*; 046import org.apache.juneau.soap.annotation.*; 047import org.apache.juneau.svl.*; 048import org.apache.juneau.uon.annotation.*; 049import org.apache.juneau.urlencoding.annotation.*; 050import org.apache.juneau.utils.*; 051import org.apache.juneau.xml.annotation.*; 052 053/** 054 * Base class for all Context beans. 055 * 056 * <p> 057 * Context beans follow the convention of havinTg the following parts: 058 * <ul> 059 * <li>A {@link Builder} class for configuring the context bean. 060 * <ul> 061 * <li>This bean is non-thread-safe and meant for one-time use. 062 * </ul> 063 * <li>A {@link Context#Context(Builder)} constructor that takes in a builder object. 064 * <ul> 065 * <li>This bean is thread-safe and cacheable/reusable. 066 * </ul> 067 * <li>A {@link ContextSession} class for doing work. 068 * <ul> 069 * <li>This bean is non-thread-safe and meant for one-time use. 070 * </ul> 071 * 072 * <h5 class='section'>Notes:</h5><ul> 073 * <li class='note'>This class is thread safe and reusable. 074 * </ul> 075 * 076 * <h5 class='section'>See Also:</h5><ul> 077 * </ul> 078 */ 079public abstract class Context implements AnnotationProvider { 080 081 //----------------------------------------------------------------------------------------------------------------- 082 // Static 083 //----------------------------------------------------------------------------------------------------------------- 084 085 private static final Map<Class<?>,MethodInfo> BUILDER_CREATE_METHODS = new ConcurrentHashMap<>(); 086 087 /** 088 * Predicate for annotations that themselves are annotated with {@link ContextApply}. 089 */ 090 public static final Predicate<AnnotationInfo<?>> CONTEXT_APPLY_FILTER = x -> x.hasAnnotation(ContextApply.class); 091 092 /** 093 * Instantiates a builder of the specified context class. 094 * 095 * <p> 096 * Looks for a public static method called <c>create</c> that returns an object that can be passed into a public 097 * or protected constructor of the class. 098 * 099 * @param type The builder to create. 100 * @return A new builder. 101 */ 102 public static Builder createBuilder(Class<? extends Context> type) { 103 try { 104 MethodInfo mi = BUILDER_CREATE_METHODS.get(type); 105 if (mi == null) { 106 ClassInfo c = ClassInfo.of(type); 107 for (ConstructorInfo ci : c.getPublicConstructors()) { 108 if (ci.matches(x -> x.hasNumParams(1) && ! x.getParam(0).getParameterType().is(type))) { 109 mi = c.getPublicMethod( 110 x -> x.isStatic() 111 && x.isNotDeprecated() 112 && x.hasName("create") 113 && x.hasReturnType(ci.getParam(0).getParameterType()) 114 ); 115 if (mi != null) 116 break; 117 } 118 } 119 if (mi == null) 120 throw new BasicRuntimeException("Could not find builder create method on class {0}", type); 121 BUILDER_CREATE_METHODS.put(type, mi); 122 } 123 Builder b = (Builder)mi.invoke(null); 124 b.type(type); 125 return b; 126 } catch (ExecutableException e) { 127 throw asRuntimeException(e); 128 } 129 } 130 131 //----------------------------------------------------------------------------------------------------------------- 132 // Builder 133 //----------------------------------------------------------------------------------------------------------------- 134 135 /** 136 * Builder class. 137 */ 138 public abstract static class Builder { 139 140 private static final Map<Class<?>,ConstructorInfo> CONTEXT_CONSTRUCTORS = new ConcurrentHashMap<>(); 141 142 boolean debug; 143 Class<? extends Context> type; 144 Context impl; 145 List<Annotation> annotations; 146 Cache<HashKey,? extends Context> cache; 147 148 private final List<Object> builders = Utils.list(); 149 private final AnnotationWorkList applied = AnnotationWorkList.create(); 150 151 /** 152 * Constructor. 153 * Default settings. 154 */ 155 @SuppressWarnings("unchecked") 156 protected Builder() { 157 debug = env("Context.debug", false); 158 annotations = null; 159 registerBuilders(this); 160 161 // By default, the type being created should be the class declaring the builder. 162 Class<?> dc = getClass().getDeclaringClass(); 163 if (Context.class.isAssignableFrom(dc)) 164 type((Class<? extends Context>)dc); 165 } 166 167 /** 168 * Copy constructor. 169 * 170 * @param copyFrom The bean to copy from. 171 */ 172 protected Builder(Context copyFrom) { 173 debug = copyFrom.debug; 174 type = copyFrom.getClass(); 175 annotations = listFrom(copyFrom.annotations, true); 176 registerBuilders(this); 177 } 178 179 /** 180 * Copy constructor. 181 * 182 * @param copyFrom The builder to copy from. 183 */ 184 protected Builder(Builder copyFrom) { 185 debug = copyFrom.debug; 186 type = copyFrom.type; 187 annotations = listFrom(copyFrom.annotations, true); 188 registerBuilders(this); 189 } 190 191 private Context innerBuild() { 192 if (type == null) 193 throw new BasicRuntimeException("Type not specified for context builder {0}", getClass().getName()); 194 if (impl != null && type.isInstance(impl)) 195 return type.cast(impl); 196 if (cache != null) 197 return cache.get(hashKey(), ()->getContextConstructor().invoke(this)); 198 return getContextConstructor().invoke(this); 199 } 200 201 private ConstructorInfo getContextConstructor() { 202 ConstructorInfo cci = CONTEXT_CONSTRUCTORS.get(type); 203 if (cci == null) { 204 cci = ClassInfo.of(type).getPublicConstructor( 205 x -> x.hasNumParams(1) 206 && x.getParam(0).canAccept(this) 207 ); 208 if (cci == null) 209 throw new BasicRuntimeException("Public constructor not found: {0}({1})", className(type), className(this)); 210 CONTEXT_CONSTRUCTORS.put(type, cci); 211 } 212 return cci; 213 } 214 215 /** 216 * Copy creator. 217 * 218 * @return A new mutable copy of this builder. 219 */ 220 public abstract Builder copy(); 221 222 /** 223 * Build the object. 224 * 225 * @return The built object. 226 */ 227 public Context build() { 228 return innerBuild(); 229 } 230 231 /** 232 * Returns the hashkey of this builder. 233 * 234 * <p> 235 * Used to return previously instantiated context beans that have matching hashkeys. 236 * The {@link HashKey} object is suitable for use as a hashmap key of a map of context beans. 237 * A context bean is considered equivalent if the {@link HashKey#equals(Object)} method is the same. 238 * 239 * @return The hashkey of this builder. 240 */ 241 public HashKey hashKey() { 242 return HashKey.of(debug, type, annotations); 243 } 244 245 /** 246 * Specifies a cache to use for hashkey-based caching. 247 * 248 * @param value The cache. 249 * @return This object. 250 */ 251 public Builder cache(Cache<HashKey,? extends Context> value) { 252 this.cache = value; 253 return this; 254 } 255 256 /** 257 * Convenience method for calling {@link #build()} while avoiding a cast. 258 * 259 * @param <T> The type to cast the built object to. 260 * @param c The type to cast the built object to. 261 * @return The built context bean. 262 */ 263 @SuppressWarnings("unchecked") 264 public final <T extends Context> T build(Class<T> c) { 265 if (type == null || ! c.isAssignableFrom(type)) 266 type = c; 267 return (T)innerBuild(); 268 } 269 270 /** 271 * Apply a consumer to this builder. 272 * 273 * @param <T> The builder subtype that this consumer can be applied to. 274 * @param subtype The builder subtype that this consumer can be applied to. 275 * @param consumer The consumer. 276 * @return This object. 277 */ 278 public <T extends Builder> Builder apply(Class<T> subtype, Consumer<T> consumer) { 279 if (subtype.isInstance(this)) 280 consumer.accept(subtype.cast(this)); 281 return this; 282 } 283 284 /** 285 * Associates a context class with this builder. 286 * 287 * <p> 288 * This is the type of object that this builder creates when the {@link #build()} method is called. 289 * 290 * <p> 291 * By default, it's the outer class of where the builder class is defined. 292 * 293 * @param value The context class that this builder should create. 294 * @return This object. 295 */ 296 public Builder type(Class<? extends Context> value) { 297 this.type = value; 298 return this; 299 } 300 301 /** 302 * Returns the context class that this builder should create. 303 * 304 * @return The context class if it was specified. 305 */ 306 public Optional<Class<?>> getType() { 307 return Utils.opt(type); 308 } 309 310 /** 311 * Specifies a pre-instantiated bean for the {@link #build()} method to return. 312 * 313 * @param value The value for this setting. 314 * @return This object. 315 */ 316 public Builder impl(Context value) { 317 impl = value; 318 return this; 319 } 320 321 /** 322 * Returns <jk>true</jk> if any of the annotations/appliers can be applied to this builder. 323 * 324 * @param work The work to check. 325 * @return <jk>true</jk> if any of the annotations/appliers can be applied to this builder. 326 */ 327 public boolean canApply(AnnotationWorkList work) { 328 Flag f = Flag.create(); 329 work.forEach(x -> builders.forEach(b -> f.setIf(x.canApply(b)))); 330 return f.isSet(); 331 } 332 333 /** 334 * Applies a set of applied to this builder. 335 * 336 * <p> 337 * An {@link AnnotationWork} consists of a single pair of {@link AnnotationInfo} that represents an annotation instance, 338 * and {@link AnnotationApplier} which represents the code used to apply the values in that annotation to a specific builder. 339 * 340 * <h5 class='section'>Example:</h5> 341 * <p class='bjava'> 342 * <jc>// A class annotated with a config annotation.</jc> 343 * <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>) 344 * <jk>public class</jk> MyClass {...} 345 * 346 * <jc>// Find all annotations that themselves are annotated with @ContextPropertiesApply.</jc> 347 * AnnotationList <jv>annotations</jv> = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>).getAnnotationList(<jsf>CONTEXT_APPLY_FILTER</jsf>); 348 * VarResolverSession <jv>vrs</jv> = VarResolver.<jsf>DEFAULT</jsf>.createSession(); 349 * AnnotationWorkList <jv>work</jv> = AnnotationWorkList.of(<jv>vrs</jv>, <jv>annotations</jv>); 350 * 351 * <jc>// Apply any settings found on the annotations.</jc> 352 * WriterSerializer <jv>serializer</jv> = JsonSerializer 353 * .<jsm>create</jsm>() 354 * .apply(<jv>work</jv>) 355 * .build(); 356 * </p> 357 * 358 * @param work The list of annotations and appliers to apply to this builder. 359 * @return This object. 360 */ 361 public Builder apply(AnnotationWorkList work) { 362 applied.addAll(work); 363 work.forEach(x -> builders.forEach(x::apply)); 364 return this; 365 } 366 367 /** 368 * Returns all the annotations that have been applied to this builder. 369 * 370 * @return All the annotations that have been applied to this builder. 371 */ 372 public AnnotationWorkList getApplied() { 373 return applied; 374 } 375 376 /** 377 * Registers the specified secondary builders with this context builder. 378 * 379 * <p> 380 * When {@link #apply(AnnotationWorkList)} is called, it gets called on all registered builders. 381 * 382 * @param builders The builders to add to the list of builders. 383 */ 384 protected void registerBuilders(Object...builders) { 385 for (Object b : builders) { 386 if (b == this) 387 this.builders.add(b); 388 else if (b instanceof Builder b2) 389 this.builders.addAll(b2.builders); 390 else 391 this.builders.add(b); 392 } 393 } 394 395 /** 396 * Applies any of the various <ja>@XConfig</ja> annotations on the specified classes or methods to this context. 397 * 398 * <p> 399 * Any annotations found that themselves are annotated with {@link ContextApply} will be resolved and 400 * applied as properties to this builder. These annotations include: 401 * <ul class='javatreec'> 402 * <li class ='ja'>{@link BeanConfig} 403 * <li class ='ja'>{@link CsvConfig} 404 * <li class ='ja'>{@link HtmlConfig} 405 * <li class ='ja'>{@link HtmlDocConfig} 406 * <li class ='ja'>{@link JsonConfig} 407 * <li class ='ja'>{@link JsonSchemaConfig} 408 * <li class ='ja'>{@link MsgPackConfig} 409 * <li class ='ja'>{@link OpenApiConfig} 410 * <li class ='ja'>{@link ParserConfig} 411 * <li class ='ja'>{@link PlainTextConfig} 412 * <li class ='ja'>{@link SerializerConfig} 413 * <li class ='ja'>{@link SoapXmlConfig} 414 * <li class ='ja'>{@link UonConfig} 415 * <li class ='ja'>{@link UrlEncodingConfig} 416 * <li class ='ja'>{@link XmlConfig} 417 * <li class ='ja'><c>RdfConfig</c> 418 * </ul> 419 * 420 * <p> 421 * Annotations on classes are appended in the following order: 422 * <ol> 423 * <li>On the package of this class. 424 * <li>On interfaces ordered parent-to-child. 425 * <li>On parent classes ordered parent-to-child. 426 * <li>On this class. 427 * </ol> 428 * 429 * <p> 430 * Annotations on methods are appended in the following order: 431 * <ol> 432 * <li>On the package of the method class. 433 * <li>On interfaces ordered parent-to-child. 434 * <li>On parent classes ordered parent-to-child. 435 * <li>On the method class. 436 * <li>On this method and matching methods ordered parent-to-child. 437 * </ol> 438 * 439 * <p> 440 * The default var resolver {@link VarResolver#DEFAULT} is used to resolve any variables in annotation field values. 441 * 442 * <h5 class='section'>Example:</h5> 443 * <p class='bjava'> 444 * <jc>// A class annotated with a config annotation.</jc> 445 * <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>) 446 * <jk>public class</jk> MyClass {...} 447 * 448 * <jc>// Apply any settings found on the annotations.</jc> 449 * WriterSerializer <jv>serializer</jv> = JsonSerializer 450 * .<jsm>create</jsm>() 451 * .applyAnnotations(MyClass.<jk>class</jk>) 452 * .build(); 453 * 454 * <jc>// A method annotated with a config annotation.</jc> 455 * <jk>public class</jk> MyClass { 456 * <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>) 457 * <jk>public void</jk> myMethod() {...} 458 * } 459 * 460 * <jc>// Apply any settings found on the annotations.</jc> 461 * WriterSerializer <jv>serializer</jv> = JsonSerializer 462 * .<jsm>create</jsm>() 463 * .applyAnnotations(MyClass.<jk>class</jk>.getMethod(<js>"myMethod"</js>)) 464 * .build(); 465 * </p> 466 * 467 * @param from The classes or methods on which the annotations are defined. 468 * Can be any of the following types: 469 * <ul> 470 * <li>{@link Class} 471 * <li>{@link ClassInfo} 472 * <li>{@link Method} 473 * <li>{@link MethodInfo} 474 * <li>A collection/stream/array of anything on this list. 475 * @return This object. 476 */ 477 public Builder applyAnnotations(Object...from) { 478 var work = AnnotationWorkList.create(); 479 Arrays.stream(from).forEach(x -> traverse(work, x)); 480 return apply(work); 481 } 482 483 private AnnotationWorkList traverse(AnnotationWorkList work, Object x) { 484 Utils.traverse(x, y -> { 485 if (x instanceof Class<?> x2) 486 work.add(ClassInfo.of(x2).getAnnotationList(CONTEXT_APPLY_FILTER)); 487 else if (x instanceof ClassInfo x2) 488 work.add(x2.getAnnotationList(CONTEXT_APPLY_FILTER)); 489 else if (x instanceof Method x2) 490 work.add(MethodInfo.of(x2).getAnnotationList(CONTEXT_APPLY_FILTER)); 491 else if (x instanceof MethodInfo x2) 492 work.add(x2.getAnnotationList(CONTEXT_APPLY_FILTER)); 493 else 494 throw illegalArg("Invalid type passed to applyAnnotations: {0}", x.getClass().getName()); 495 }); 496 return work; 497 } 498 499 /** 500 * Same as {@link #applyAnnotations(Object...)} but explicitly specifies a class varargs to avoid compilation warnings. 501 * 502 * @param from The classes or methods on which the annotations are defined. 503 * @return This object. 504 */ 505 public Builder applyAnnotations(Class<?>...from) { 506 return applyAnnotations((Object[])from); 507 } 508 509 //----------------------------------------------------------------------------------------------------------------- 510 // Properties 511 //----------------------------------------------------------------------------------------------------------------- 512 513 /** 514 * Defines annotations to apply to specific classes and methods. 515 * 516 * <p> 517 * Allows you to dynamically apply Juneau annotations typically applied directly to classes and methods. 518 * Useful in cases where you want to use the functionality of the annotation on beans and bean properties but 519 * do not have access to the code to do so. 520 * 521 * <p> 522 * As a rule, any Juneau annotation with an <l>on()</l> method can be used with this setting. 523 * 524 * <p> 525 * The following example shows the equivalent methods for applying the {@link Bean @Bean} annotation: 526 * <p class='bjava'> 527 * <jc>// Class with explicit annotation.</jc> 528 * <ja>@Bean</ja>(properties=<js>"street,city,state"</js>) 529 * <jk>public class</jk> A {...} 530 * 531 * <jc>// Class with annotation applied via @BeanConfig</jc> 532 * <jk>public class</jk> B {...} 533 * 534 * <jc>// Java REST method with @BeanConfig annotation.</jc> 535 * <ja>@RestGet</ja>(...) 536 * <ja>@Bean</ja>(on=<js>"B"</js>, properties=<js>"street,city,state"</js>) 537 * <jk>public void</jk> doFoo() {...} 538 * </p> 539 * 540 * <p> 541 * In general, the underlying framework uses this method when it finds dynamically applied annotations on 542 * config annotations. However, concrete implementations of annotations are also provided that can be passed 543 * directly into builder classes like so: 544 * <p class='bjava'> 545 * <jc>// Create a concrete @Bean annotation.</jc> 546 * <ja>Bean</ja> <jv>annotation</jv> = BeanAnnotation.<jsm>create</jsm>(B.<jk>class</jk>).properties(<js>"street,city,state"</js>).build(); 547 * 548 * <jc>// Apply it to a serializer.</jc> 549 * WriterSerializer <jv>serializer</jv> = JsonSerializer.<jsm>create</jsm>().annotations(<jv>annotation</jv>).build(); 550 * 551 * <jc>// Serialize a bean with the dynamically applied annotation.</jc> 552 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> B()); 553 * </p> 554 * 555 * <p> 556 * The following is the list of annotations builders provided that can be constructed 557 * and passed into the builder class: 558 * <ul class='javatreec'> 559 * <li class='ja'>{@link org.apache.juneau.annotation.BeanAnnotation} 560 * <li class='ja'>{@link org.apache.juneau.annotation.BeancAnnotation} 561 * <li class='ja'>{@link org.apache.juneau.annotation.BeanIgnoreAnnotation} 562 * <li class='ja'>{@link org.apache.juneau.annotation.BeanpAnnotation} 563 * <li class='ja'>{@link org.apache.juneau.annotation.ExampleAnnotation} 564 * <li class='ja'>{@link org.apache.juneau.annotation.NamePropertyAnnotation} 565 * <li class='ja'>{@link org.apache.juneau.annotation.ParentPropertyAnnotation} 566 * <li class='ja'>{@link org.apache.juneau.annotation.SwapAnnotation} 567 * <li class='ja'>{@link org.apache.juneau.annotation.UriAnnotation} 568 * <li class='ja'>{@link org.apache.juneau.csv.annotation.CsvAnnotation} 569 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlAnnotation} 570 * <li class='ja'>{@link org.apache.juneau.json.annotation.JsonAnnotation} 571 * <li class='ja'>{@link org.apache.juneau.annotation.SchemaAnnotation} 572 * <li class='ja'>{@link org.apache.juneau.msgpack.annotation.MsgPackAnnotation} 573 * <li class='ja'>{@link org.apache.juneau.oapi.annotation.OpenApiAnnotation} 574 * <li class='ja'>{@link org.apache.juneau.plaintext.annotation.PlainTextAnnotation} 575 * <li class='ja'>{@link org.apache.juneau.soap.annotation.SoapXmlAnnotation} 576 * <li class='ja'>{@link org.apache.juneau.uon.annotation.UonAnnotation} 577 * <li class='ja'>{@link org.apache.juneau.urlencoding.annotation.UrlEncodingAnnotation} 578 * <li class='ja'>{@link org.apache.juneau.xml.annotation.XmlAnnotation} 579 * </ul> 580 * 581 * <p> 582 * The syntax for the <l>on()</l> pattern match parameter depends on whether it applies to a class, method, field, or constructor. 583 * The valid pattern matches are: 584 * <ul class='spaced-list'> 585 * <li>Classes: 586 * <ul> 587 * <li>Fully qualified: 588 * <ul> 589 * <li><js>"com.foo.MyClass"</js> 590 * </ul> 591 * <li>Fully qualified inner class: 592 * <ul> 593 * <li><js>"com.foo.MyClass$Inner1$Inner2"</js> 594 * </ul> 595 * <li>Simple: 596 * <ul> 597 * <li><js>"MyClass"</js> 598 * </ul> 599 * <li>Simple inner: 600 * <ul> 601 * <li><js>"MyClass$Inner1$Inner2"</js> 602 * <li><js>"Inner1$Inner2"</js> 603 * <li><js>"Inner2"</js> 604 * </ul> 605 * </ul> 606 * <li>Methods: 607 * <ul> 608 * <li>Fully qualified with args: 609 * <ul> 610 * <li><js>"com.foo.MyClass.myMethod(String,int)"</js> 611 * <li><js>"com.foo.MyClass.myMethod(java.lang.String,int)"</js> 612 * <li><js>"com.foo.MyClass.myMethod()"</js> 613 * </ul> 614 * <li>Fully qualified: 615 * <ul> 616 * <li><js>"com.foo.MyClass.myMethod"</js> 617 * </ul> 618 * <li>Simple with args: 619 * <ul> 620 * <li><js>"MyClass.myMethod(String,int)"</js> 621 * <li><js>"MyClass.myMethod(java.lang.String,int)"</js> 622 * <li><js>"MyClass.myMethod()"</js> 623 * </ul> 624 * <li>Simple: 625 * <ul> 626 * <li><js>"MyClass.myMethod"</js> 627 * </ul> 628 * <li>Simple inner class: 629 * <ul> 630 * <li><js>"MyClass$Inner1$Inner2.myMethod"</js> 631 * <li><js>"Inner1$Inner2.myMethod"</js> 632 * <li><js>"Inner2.myMethod"</js> 633 * </ul> 634 * </ul> 635 * <li>Fields: 636 * <ul> 637 * <li>Fully qualified: 638 * <ul> 639 * <li><js>"com.foo.MyClass.myField"</js> 640 * </ul> 641 * <li>Simple: 642 * <ul> 643 * <li><js>"MyClass.myField"</js> 644 * </ul> 645 * <li>Simple inner class: 646 * <ul> 647 * <li><js>"MyClass$Inner1$Inner2.myField"</js> 648 * <li><js>"Inner1$Inner2.myField"</js> 649 * <li><js>"Inner2.myField"</js> 650 * </ul> 651 * </ul> 652 * <li>Constructors: 653 * <ul> 654 * <li>Fully qualified with args: 655 * <ul> 656 * <li><js>"com.foo.MyClass(String,int)"</js> 657 * <li><js>"com.foo.MyClass(java.lang.String,int)"</js> 658 * <li><js>"com.foo.MyClass()"</js> 659 * </ul> 660 * <li>Simple with args: 661 * <ul> 662 * <li><js>"MyClass(String,int)"</js> 663 * <li><js>"MyClass(java.lang.String,int)"</js> 664 * <li><js>"MyClass()"</js> 665 * </ul> 666 * <li>Simple inner class: 667 * <ul> 668 * <li><js>"MyClass$Inner1$Inner2()"</js> 669 * <li><js>"Inner1$Inner2()"</js> 670 * <li><js>"Inner2()"</js> 671 * </ul> 672 * </ul> 673 * <li>A comma-delimited list of anything on this list. 674 * </ul> 675 * 676 * <h5 class='section'>See Also:</h5><ul> 677 * <li class='ja'>{@link BeanConfig} 678 * </ul> 679 * 680 * @param values 681 * The annotations to register with the context. 682 * @return This object. 683 */ 684 public Builder annotations(Annotation...values) { 685 annotations = addAll(annotations, values); 686 return this; 687 } 688 689 /** 690 * Same as {@link #annotations(Annotation...)} but uses a list as input. 691 * 692 * @param values 693 * The annotations to register with the context. 694 * @return This object. 695 */ 696 public Builder annotations(List<Annotation> values) { 697 annotations = addAll(annotations, values); 698 return this; 699 } 700 701 /** 702 * <i><l>Context</l> configuration property: </i> Debug mode. 703 * 704 * <p> 705 * Enables the following additional information during serialization: 706 * <ul class='spaced-list'> 707 * <li> 708 * When bean getters throws exceptions, the exception includes the object stack information 709 * in order to determine how that method was invoked. 710 * <li> 711 * Enables {@link BeanTraverseContext.Builder#detectRecursions()}. 712 * </ul> 713 * 714 * <p> 715 * Enables the following additional information during parsing: 716 * <ul class='spaced-list'> 717 * <li> 718 * When bean setters throws exceptions, the exception includes the object stack information 719 * in order to determine how that method was invoked. 720 * </ul> 721 * 722 * <h5 class='section'>Example:</h5> 723 * <p class='bjava'> 724 * <jc>// Create a serializer with debug enabled.</jc> 725 * WriterSerializer <jv>serializer</jv> = JsonSerializer 726 * .<jsm>create</jsm>() 727 * .debug() 728 * .build(); 729 * 730 * <jc>// Create a POJO model with a recursive loop.</jc> 731 * <jk>public class</jk> MyBean { 732 * <jk>public</jk> Object <jf>f</jf>; 733 * } 734 * MyBean <jv>bean</jv> = <jk>new</jk> MyBean(); 735 * <jv>bean</jv>.<jf>f</jf> = <jv>bean</jv>; 736 * 737 * <jc>// Throws a SerializeException and not a StackOverflowError</jc> 738 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>bean</jv>); 739 * </p> 740 * 741 * <h5 class='section'>See Also:</h5><ul> 742 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#debug()} 743 * <li class='jm'>{@link org.apache.juneau.ContextSession.Builder#debug(Boolean)} 744 * </ul> 745 * 746 * @return This object. 747 */ 748 public Builder debug() { 749 return debug(true); 750 } 751 752 /** 753 * Same as {@link #debug()} but allows you to explicitly specify the value. 754 * 755 * @param value The value for this setting. 756 * @return This object. 757 */ 758 public Builder debug(boolean value) { 759 debug = value; 760 return this; 761 } 762 763 /** 764 * Returns <jk>true</jk> if debug is enabled. 765 * 766 * @return <jk>true</jk> if debug is enabled. 767 */ 768 public boolean isDebug() { 769 return debug; 770 } 771 } 772 773 //----------------------------------------------------------------------------------------------------------------- 774 // Instance 775 //----------------------------------------------------------------------------------------------------------------- 776 777 final List<Annotation> annotations; 778 final boolean debug; 779 780 private final ReflectionMap<Annotation> annotationMap; 781 private final TwoKeyConcurrentCache<Class<?>,Class<? extends Annotation>,Annotation[]> classAnnotationCache; 782 private final TwoKeyConcurrentCache<Class<?>,Class<? extends Annotation>,Annotation[]> declaredClassAnnotationCache; 783 private final TwoKeyConcurrentCache<Method,Class<? extends Annotation>,Annotation[]> methodAnnotationCache; 784 private final TwoKeyConcurrentCache<Field,Class<? extends Annotation>,Annotation[]> fieldAnnotationCache; 785 private final TwoKeyConcurrentCache<Constructor<?>,Class<? extends Annotation>,Annotation[]> constructorAnnotationCache; 786 787 /** 788 * Copy constructor. 789 * 790 * @param copyFrom The context to copy from. 791 */ 792 protected Context(Context copyFrom) { 793 annotationMap = copyFrom.annotationMap; 794 annotations = copyFrom.annotations; 795 debug = copyFrom.debug; 796 classAnnotationCache = copyFrom.classAnnotationCache; 797 declaredClassAnnotationCache = copyFrom.declaredClassAnnotationCache; 798 methodAnnotationCache = copyFrom.methodAnnotationCache; 799 fieldAnnotationCache = copyFrom.fieldAnnotationCache; 800 constructorAnnotationCache = copyFrom.constructorAnnotationCache; 801 } 802 803 /** 804 * Constructor for this class. 805 * 806 * @param builder The builder for this class. 807 */ 808 protected Context(Builder builder) { 809 init(builder); 810 debug = builder.debug; 811 annotations = Utils.opt(builder.annotations).orElseGet(Collections::emptyList); 812 813 ReflectionMap.Builder<Annotation> rmb = ReflectionMap.create(Annotation.class); 814 815 annotations.forEach(a -> { 816 try { 817 ClassInfo ci = ClassInfo.of(a.getClass()); 818 819 MethodInfo mi = ci.getPublicMethod(x -> x.hasName("onClass")); 820 if (mi != null) { 821 if (! mi.getReturnType().is(Class[].class)) 822 throw new ConfigException("Invalid annotation @{0} used in BEAN_annotations property. Annotation must define an onClass() method that returns a Class array.", a.getClass().getSimpleName()); 823 for (Class<?> c : (Class<?>[])mi.accessible().invoke(a)) 824 rmb.append(c.getName(), a); 825 } 826 827 mi = ci.getPublicMethod(x -> x.hasName("on")); 828 if (mi != null) { 829 if (! mi.getReturnType().is(String[].class)) 830 throw new ConfigException("Invalid annotation @{0} used in BEAN_annotations property. Annotation must define an on() method that returns a String array.", a.getClass().getSimpleName()); 831 for (String s : (String[])mi.accessible().invoke(a)) 832 rmb.append(s, a); 833 } 834 835 } catch (Exception e) { 836 throw new ConfigException(e, "Invalid annotation @{0} used in BEAN_annotations property.", className(a)); 837 } 838 }); 839 this.annotationMap = rmb.build(); 840 boolean disabled = Boolean.getBoolean("juneau.disableAnnotationCaching"); 841 classAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2))); 842 declaredClassAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getDeclaredAnnotationsByType(k2))); 843 methodAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2))); 844 fieldAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2))); 845 constructorAnnotationCache = new TwoKeyConcurrentCache<>(disabled, (k1,k2) -> annotationMap.appendAll(k1, k2, k1.getAnnotationsByType(k2))); 846 } 847 848 /** 849 * Perform optional initialization on builder before it is used. 850 * 851 * <p> 852 * Default behavior is a no-op. 853 * 854 * @param builder The builder to initialize. 855 */ 856 protected void init(Builder builder) {} 857 858 /** 859 * Creates a builder from this context object. 860 * 861 * <p> 862 * Builders are used to define new contexts (e.g. serializers, parsers) based on existing configurations. 863 * 864 * @return A new Builder object. 865 */ 866 public Builder copy() { 867 throw new UnsupportedOperationException("Not implemented."); 868 } 869 870 /** 871 * Create a session builder based on the properties defined on this context. 872 * 873 * <p> 874 * Use this method for creating sessions where you want to override basic settings. 875 * Otherwise, use {@link #getSession()} directly. 876 * 877 * @return A new session builder. 878 */ 879 public ContextSession.Builder createSession() { 880 throw new UnsupportedOperationException("Not implemented."); 881 } 882 883 /** 884 * Returns a session to use for this context. 885 * 886 * <p> 887 * Note that subclasses may opt to return a reusable non-modifiable session. 888 * 889 * @return A new session object. 890 */ 891 public ContextSession getSession() { 892 return createSession().build(); 893 } 894 895 //----------------------------------------------------------------------------------------------------------------- 896 // Properties 897 //----------------------------------------------------------------------------------------------------------------- 898 899 /** 900 * Debug mode. 901 * 902 * @see Context.Builder#debug() 903 * @return 904 * <jk>true</jk> if debug mode is enabled. 905 */ 906 public boolean isDebug() { 907 return debug; 908 } 909 910 //----------------------------------------------------------------------------------------------------------------- 911 // MetaProvider methods 912 //----------------------------------------------------------------------------------------------------------------- 913 914 @Override /* MetaProvider */ 915 public <A extends Annotation> void forEachAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter, Consumer<A> action) { 916 if (type != null && onClass != null) 917 for (A a : annotations(type, onClass)) 918 consume(filter, action, a); 919 } 920 921 @Override /* MetaProvider */ 922 public <A extends Annotation> A firstAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) { 923 if (type != null && onClass != null) 924 for (A a : annotations(type, onClass)) 925 if (test(filter, a)) 926 return a; 927 return null; 928 } 929 930 @Override /* MetaProvider */ 931 public <A extends Annotation> A lastAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) { 932 A x = null; 933 if (type != null && onClass != null) 934 for (A a : annotations(type, onClass)) 935 if (test(filter, a)) 936 x = a; 937 return x; 938 } 939 940 @Override /* MetaProvider */ 941 public <A extends Annotation> void forEachDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter, Consumer<A> action) { 942 if (type != null && onClass != null) 943 for (A a : declaredAnnotations(type, onClass)) 944 consume(filter, action, a); 945 } 946 947 @Override /* MetaProvider */ 948 public <A extends Annotation> A firstDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) { 949 if (type != null && onClass != null) 950 for (A a : declaredAnnotations(type, onClass)) 951 if (test(filter, a)) 952 return a; 953 return null; 954 } 955 956 @Override /* MetaProvider */ 957 public <A extends Annotation> A lastDeclaredAnnotation(Class<A> type, Class<?> onClass, Predicate<A> filter) { 958 A x = null; 959 if (type != null && onClass != null) 960 for (A a : declaredAnnotations(type, onClass)) 961 if (test(filter, a)) 962 x = a; 963 return x; 964 } 965 966 @Override /* MetaProvider */ 967 public <A extends Annotation> void forEachAnnotation(Class<A> type, Method onMethod, Predicate<A> filter, Consumer<A> action) { 968 if (type != null && onMethod != null) 969 for (A a : annotations(type, onMethod)) 970 consume(filter, action, a); 971 } 972 973 @Override /* MetaProvider */ 974 public <A extends Annotation> A firstAnnotation(Class<A> type, Method onMethod, Predicate<A> filter) { 975 if (type != null && onMethod != null) 976 for (A a : annotations(type, onMethod)) 977 if (test(filter, a)) 978 return a; 979 return null; 980 } 981 982 @Override /* MetaProvider */ 983 public <A extends Annotation> A lastAnnotation(Class<A> type, Method onMethod, Predicate<A> filter) { 984 A x = null; 985 if (type != null && onMethod != null) 986 for (A a : annotations(type, onMethod)) 987 if (test(filter, a)) 988 x = a; 989 return x; 990 } 991 992 @Override /* MetaProvider */ 993 public <A extends Annotation> void forEachAnnotation(Class<A> type, Field onField, Predicate<A> filter, Consumer<A> action) { 994 if (type != null && onField != null) 995 for (A a : annotations(type, onField)) 996 consume(filter, action, a); 997 } 998 999 @Override /* MetaProvider */ 1000 public <A extends Annotation> A firstAnnotation(Class<A> type, Field onField, Predicate<A> filter) { 1001 if (type != null && onField != null) 1002 for (A a : annotations(type, onField)) 1003 if (test(filter, a)) 1004 return a; 1005 return null; 1006 } 1007 1008 @Override /* MetaProvider */ 1009 public <A extends Annotation> A lastAnnotation(Class<A> type, Field onField, Predicate<A> filter) { 1010 A x = null; 1011 if (type != null && onField != null) 1012 for (A a : annotations(type, onField)) 1013 if (test(filter, a)) 1014 x = a; 1015 return x; 1016 } 1017 1018 @Override /* MetaProvider */ 1019 public <A extends Annotation> void forEachAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter, Consumer<A> action) { 1020 if (type != null && onConstructor != null) 1021 for (A a : annotations(type, onConstructor)) 1022 consume(filter, action, a); 1023 } 1024 1025 @Override /* MetaProvider */ 1026 public <A extends Annotation> A firstAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter) { 1027 if (type != null && onConstructor != null) 1028 for (A a : annotations(type, onConstructor)) 1029 if (test(filter, a)) 1030 return a; 1031 return null; 1032 } 1033 1034 @Override /* MetaProvider */ 1035 public <A extends Annotation> A lastAnnotation(Class<A> type, Constructor<?> onConstructor, Predicate<A> filter) { 1036 A x = null; 1037 if (type != null && onConstructor != null) 1038 for (A a : annotations(type, onConstructor)) 1039 if (test(filter, a)) 1040 x = a; 1041 return x; 1042 } 1043 1044 /** 1045 * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value. 1046 * 1047 * @param <A> The annotation being checked for. 1048 * @param type The annotation being checked for. 1049 * @param onClass The class being checked on. 1050 * @return <jk>true</jk> if the annotation exists on the specified class. 1051 */ 1052 public <A extends Annotation> boolean hasAnnotation(Class<A> type, Class<?> onClass) { 1053 return annotations(type, onClass).length > 0; 1054 } 1055 1056 /** 1057 * Returns <jk>true</jk> if <c>getAnnotation(a,m)</c> returns a non-null value. 1058 * 1059 * @param <A> The annotation being checked for. 1060 * @param type The annotation being checked for. 1061 * @param onMethod The method being checked on. 1062 * @return <jk>true</jk> if the annotation exists on the specified method. 1063 */ 1064 public <A extends Annotation> boolean hasAnnotation(Class<A> type, Method onMethod) { 1065 return annotations(type, onMethod).length > 0; 1066 } 1067 1068 /** 1069 * Returns <jk>true</jk> if <c>getAnnotation(a,f)</c> returns a non-null value. 1070 * 1071 * @param <A> The annotation being checked for. 1072 * @param type The annotation being checked for. 1073 * @param onField The field being checked on. 1074 * @return <jk>true</jk> if the annotation exists on the specified field. 1075 */ 1076 public <A extends Annotation> boolean hasAnnotation(Class<A> type, Field onField) { 1077 return annotations(type, onField).length > 0; 1078 } 1079 1080 /** 1081 * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value. 1082 * 1083 * @param <A> The annotation being checked for. 1084 * @param type The annotation being checked for. 1085 * @param onConstructor The constructor being checked on. 1086 * @return <jk>true</jk> if the annotation exists on the specified field. 1087 */ 1088 public <A extends Annotation> boolean hasAnnotation(Class<A> type, Constructor<?> onConstructor) { 1089 return annotations(type, onConstructor).length > 0; 1090 } 1091 1092 @SuppressWarnings("unchecked") 1093 private <A extends Annotation> A[] annotations(Class<A> type, Class<?> onClass) { 1094 return (A[])classAnnotationCache.get(onClass, type); 1095 } 1096 1097 @SuppressWarnings("unchecked") 1098 private <A extends Annotation> A[] declaredAnnotations(Class<A> type, Class<?> onClass) { 1099 return (A[])declaredClassAnnotationCache.get(onClass, type); 1100 } 1101 1102 @SuppressWarnings("unchecked") 1103 private <A extends Annotation> A[] annotations(Class<A> type, Method onMethod) { 1104 return (A[])methodAnnotationCache.get(onMethod, type); 1105 } 1106 1107 @SuppressWarnings("unchecked") 1108 private <A extends Annotation> A[] annotations(Class<A> type, Field onField) { 1109 return (A[])fieldAnnotationCache.get(onField, type); 1110 } 1111 1112 @SuppressWarnings("unchecked") 1113 private <A extends Annotation> A[] annotations(Class<A> type, Constructor<?> onConstructor) { 1114 return (A[])constructorAnnotationCache.get(onConstructor, type); 1115 } 1116 1117 //----------------------------------------------------------------------------------------------------------------- 1118 // Other methods 1119 //----------------------------------------------------------------------------------------------------------------- 1120 1121 /** 1122 * Returns the properties on this bean as a map for debugging. 1123 * 1124 * @return The properties on this bean as a map for debugging. 1125 */ 1126 protected JsonMap properties() { 1127 return filteredMap("annotations", annotations, "debug", debug); 1128 } 1129 1130 @Override /* Object */ 1131 public String toString() { 1132 return Utils2.toPropertyMap(this).asReadableString(); 1133 } 1134}