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.marshall; 018 019import static org.apache.juneau.commons.reflect.ReflectionUtils.*; 020import static org.apache.juneau.commons.utils.CollectionUtils.*; 021import static org.apache.juneau.commons.utils.Shorts.*; 022import static org.apache.juneau.commons.utils.SystemUtils.*; 023import static org.apache.juneau.commons.utils.ThrowableUtils.*; 024 025import java.lang.annotation.*; 026import java.lang.reflect.*; 027import java.util.*; 028import java.util.function.*; 029 030import org.apache.juneau.commons.bean.*; 031import org.apache.juneau.commons.collections.*; 032import org.apache.juneau.commons.reflect.*; 033import org.apache.juneau.commons.svl.*; 034import org.apache.juneau.commons.utils.*; 035import org.apache.juneau.marshall.bson.*; 036import org.apache.juneau.marshall.cbor.*; 037import org.apache.juneau.marshall.csv.*; 038import org.apache.juneau.marshall.hjson.*; 039import org.apache.juneau.marshall.hocon.*; 040import org.apache.juneau.marshall.html.*; 041import org.apache.juneau.marshall.ini.*; 042import org.apache.juneau.marshall.jcs.*; 043import org.apache.juneau.marshall.json.*; 044import org.apache.juneau.marshall.jsonl.*; 045import org.apache.juneau.marshall.jsonschema.*; 046import org.apache.juneau.marshall.markdown.*; 047import org.apache.juneau.marshall.msgpack.*; 048import org.apache.juneau.marshall.oapi.*; 049import org.apache.juneau.marshall.parquet.*; 050import org.apache.juneau.marshall.parser.*; 051import org.apache.juneau.marshall.plaintext.*; 052import org.apache.juneau.marshall.prototext.*; 053import org.apache.juneau.marshall.serializer.*; 054import org.apache.juneau.marshall.soap.*; 055import org.apache.juneau.marshall.toml.*; 056import org.apache.juneau.marshall.uon.*; 057import org.apache.juneau.marshall.urlencoding.*; 058import org.apache.juneau.marshall.xml.*; 059import org.apache.juneau.marshall.yaml.*; 060 061/** 062 * Base class for all Context beans. 063 * 064 * <p> 065 * Context beans follow the convention of having the following parts: 066 * <ul> 067 * <li>A {@link Builder} class for configuring the context bean. 068 * <ul> 069 * <li>This bean is non-thread-safe and meant for one-time use. 070 * </ul> 071 * <li>A {@link Context#Context(Builder)} constructor that takes in a builder object. 072 * <ul> 073 * <li>This bean is thread-safe and cacheable/reusable. 074 * </ul> 075 * <li>A {@link ContextSession} class for doing work. 076 * <ul> 077 * <li>This bean is non-thread-safe and meant for one-time use. 078 * </ul> 079 * 080 * <h5 class='section'>Notes:</h5><ul> 081 * <li class='note'>This class is thread safe and reusable. 082 * </ul> 083 * 084 */ 085@SuppressWarnings({ 086 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 087 "java:S1452", // Builder<?> is returned by copyOrNull() because callers only need the base builder and the concrete SELF type is unknown. 088 "java:S3740", // Raw Builder types in reflection-based context creation; parameterization is not possible at call sites 089 "rawtypes", // Raw Builder is used by createBuilder(), the Context(Builder) constructor, copy() and the constructor cache because the builder subtype is only known reflectively. 090 "unchecked" // Casts of the reflectively-resolved Class to Class<? extends Context> and of innerBuild() to T are guaranteed by the builder/context type pairing. 091}) 092public abstract class Context { 093 094 /** 095 * Builder class. 096 */ 097 @SuppressWarnings({ 098 "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name. 099 }) 100 public abstract static class Builder<SELF extends Builder<SELF>> { 101 102 /** 103 * Returns this object cast to the self (CRTP) type. 104 * 105 * @return This object. 106 */ 107 protected final SELF self() { 108 return (SELF)this; 109 } 110 111 112 private boolean debug; 113 private final AnnotationWorkList applied = AnnotationWorkList.create(); 114 private Cache<HashKey,? extends Context> cache; 115 private Class<? extends Context> type; 116 private Context impl; 117 private final List<Annotation> annotations; 118 private final List<Object> builders = list(); 119 120 /** 121 * Constructor. 122 * Default settings. 123 */ 124 protected Builder() { 125 debug = env("Context.debug", false); 126 annotations = list(); 127 registerBuilders(this); 128 129 // By default, the type being created should be the class declaring the builder. 130 var dc = getClass().getDeclaringClass(); 131 if (Context.class.isAssignableFrom(dc)) 132 type((Class<? extends Context>)dc); 133 } 134 135 /** 136 * Copy constructor. 137 * 138 * @param copyFrom The builder to copy from. 139 * <br>Cannot be <jk>null</jk>. 140 */ 141 protected Builder(Builder<?> copyFrom) { 142 reqnn("copyFrom", copyFrom); 143 annotations = cp(copyFrom.annotations); 144 debug = copyFrom.debug; 145 type = copyFrom.type; 146 // Intentionally not copied: a prebuilt impl would bypass changes made to the copy, and the cache is per-builder. 147 cache = null; 148 impl = null; 149 registerBuilders(this); 150 } 151 152 /** 153 * Copy constructor. 154 * 155 * @param copyFrom The bean to copy from. 156 * <br>Cannot be <jk>null</jk>. 157 */ 158 protected Builder(Context copyFrom) { 159 reqnn("copyFrom", copyFrom); 160 annotations = cp(copyFrom.annotations); 161 debug = copyFrom.debug; 162 type = copyFrom.getClass(); 163 // Intentionally not copied: a prebuilt impl would bypass changes made to the copy, and the cache is per-builder. 164 cache = null; 165 impl = null; 166 registerBuilders(this); 167 } 168 169 /** 170 * Defines annotations to apply to specific classes and methods. 171 * 172 * <p> 173 * Allows you to dynamically apply Juneau annotations typically applied directly to classes and methods. 174 * Useful in cases where you want to use the functionality of the annotation on beans and bean properties but 175 * do not have access to the code to do so. 176 * 177 * <p> 178 * As a rule, any Juneau annotation with an <l>on()</l> method can be used with this setting. 179 * 180 * <p> 181 * The following example shows the equivalent methods for applying the {@link Marshalled @Marshalled} annotation: 182 * <p class='bjava'> 183 * <jc>// Class with explicit annotation.</jc> 184 * <ja>@Marshalled</ja>(properties=<js>"street,city,state"</js>) 185 * <jk>public class</jk> A {...} 186 * 187 * <jc>// Class with annotation applied via @MarshalledConfig</jc> 188 * <jk>public class</jk> B {...} 189 * 190 * <jc>// Java REST method with @MarshalledConfig annotation.</jc> 191 * <ja>@RestGet</ja>(...) 192 * <ja>@Marshalled</ja>(on=<js>"B"</js>, properties=<js>"street,city,state"</js>) 193 * <jk>public void</jk> doFoo() {...} 194 * </p> 195 * 196 * <p> 197 * In general, the underlying framework uses this method when it finds dynamically applied annotations on 198 * config annotations. However, concrete implementations of annotations are also provided that can be passed 199 * directly into builder classes like so: 200 * <p class='bjava'> 201 * <jc>// Create a concrete @Marshalled annotation.</jc> 202 * <ja>Marshalled</ja> <jv>annotation</jv> = MarshalledAnnotation.<jsm>create</jsm>(B.<jk>class</jk>).properties(<js>"street,city,state"</js>).build(); 203 * 204 * <jc>// Apply it to a serializer.</jc> 205 * WriterSerializer <jv>serializer</jv> = JsonSerializer.<jsm>create</jsm>().annotations(<jv>annotation</jv>).build(); 206 * 207 * <jc>// Serialize a bean with the dynamically applied annotation.</jc> 208 * String <jv>json</jv> = <jv>serializer</jv>.write(<jk>new</jk> B()); 209 * </p> 210 * 211 * <p> 212 * The following is the list of annotations builders provided that can be constructed 213 * and passed into the builder class: 214 * <ul class='javatreec'> 215 * <li class='ja'>{@link MarshalledAnnotation} 216 * <li class='ja'>{@link BeanCtorAnnotation} 217 * <li class='ja'>{@link BeanIgnoreAnnotation} 218 * <li class='ja'>{@link MarshalledIgnoreAnnotation} 219 * <li class='ja'>{@link BeanPropAnnotation} 220 * <li class='ja'>{@link MarshalledPropAnnotation} 221 * <li class='ja'>{@link ExampleAnnotation} 222 * <li class='ja'>{@link NamePropertyAnnotation} 223 * <li class='ja'>{@link ParentPropertyAnnotation} 224 * <li class='ja'>{@link SwapAnnotation} 225 * <li class='ja'>{@link UriAnnotation} 226 * <li class='ja'>{@link CsvAnnotation} 227 * <li class='ja'>{@link HtmlAnnotation} 228 * <li class='ja'>{@link JsonAnnotation} 229 * <li class='ja'>{@link SchemaAnnotation} 230 * <li class='ja'>{@link MsgPackAnnotation} 231 * <li class='ja'>{@link OpenApiAnnotation} 232 * <li class='ja'>{@link PlainTextAnnotation} 233 * <li class='ja'>{@link SoapXmlAnnotation} 234 * <li class='ja'>{@link UonAnnotation} 235 * <li class='ja'>{@link UrlEncodingAnnotation} 236 * <li class='ja'>{@link XmlAnnotation} 237 * </ul> 238 * 239 * <p> 240 * The syntax for the <l>on()</l> pattern match parameter depends on whether it applies to a class, method, field, or constructor. 241 * The valid pattern matches are: 242 * <ul class='spaced-list'> 243 * <li>Classes: 244 * <ul> 245 * <li>Fully qualified: 246 * <ul> 247 * <li><js>"com.foo.MyClass"</js> 248 * </ul> 249 * <li>Fully qualified inner class: 250 * <ul> 251 * <li><js>"com.foo.MyClass$Inner1$Inner2"</js> 252 * </ul> 253 * <li>Simple: 254 * <ul> 255 * <li><js>"MyClass"</js> 256 * </ul> 257 * <li>Simple inner: 258 * <ul> 259 * <li><js>"MyClass$Inner1$Inner2"</js> 260 * <li><js>"Inner1$Inner2"</js> 261 * <li><js>"Inner2"</js> 262 * </ul> 263 * </ul> 264 * <li>Methods: 265 * <ul> 266 * <li>Fully qualified with args: 267 * <ul> 268 * <li><js>"com.foo.MyClass.myMethod(String,int)"</js> 269 * <li><js>"com.foo.MyClass.myMethod(java.lang.String,int)"</js> 270 * <li><js>"com.foo.MyClass.myMethod()"</js> 271 * </ul> 272 * <li>Fully qualified: 273 * <ul> 274 * <li><js>"com.foo.MyClass.myMethod"</js> 275 * </ul> 276 * <li>Simple with args: 277 * <ul> 278 * <li><js>"MyClass.myMethod(String,int)"</js> 279 * <li><js>"MyClass.myMethod(java.lang.String,int)"</js> 280 * <li><js>"MyClass.myMethod()"</js> 281 * </ul> 282 * <li>Simple: 283 * <ul> 284 * <li><js>"MyClass.myMethod"</js> 285 * </ul> 286 * <li>Simple inner class: 287 * <ul> 288 * <li><js>"MyClass$Inner1$Inner2.myMethod"</js> 289 * <li><js>"Inner1$Inner2.myMethod"</js> 290 * <li><js>"Inner2.myMethod"</js> 291 * </ul> 292 * </ul> 293 * <li>Fields: 294 * <ul> 295 * <li>Fully qualified: 296 * <ul> 297 * <li><js>"com.foo.MyClass.myField"</js> 298 * </ul> 299 * <li>Simple: 300 * <ul> 301 * <li><js>"MyClass.myField"</js> 302 * </ul> 303 * <li>Simple inner class: 304 * <ul> 305 * <li><js>"MyClass$Inner1$Inner2.myField"</js> 306 * <li><js>"Inner1$Inner2.myField"</js> 307 * <li><js>"Inner2.myField"</js> 308 * </ul> 309 * </ul> 310 * <li>Constructors: 311 * <ul> 312 * <li>Fully qualified with args: 313 * <ul> 314 * <li><js>"com.foo.MyClass(String,int)"</js> 315 * <li><js>"com.foo.MyClass(java.lang.String,int)"</js> 316 * <li><js>"com.foo.MyClass()"</js> 317 * </ul> 318 * <li>Simple with args: 319 * <ul> 320 * <li><js>"MyClass(String,int)"</js> 321 * <li><js>"MyClass(java.lang.String,int)"</js> 322 * <li><js>"MyClass()"</js> 323 * </ul> 324 * <li>Simple inner class: 325 * <ul> 326 * <li><js>"MyClass$Inner1$Inner2()"</js> 327 * <li><js>"Inner1$Inner2()"</js> 328 * <li><js>"Inner2()"</js> 329 * </ul> 330 * </ul> 331 * <li>A comma-delimited list of anything on this list. 332 * </ul> 333 * 334 * <h5 class='section'>See Also:</h5><ul> 335 * <li class='ja'>{@link MarshalledConfig} 336 * </ul> 337 * 338 * @param values 339 * The annotations to register with the context. 340 * <br>Cannot contain <jk>null</jk> values. 341 * @return This object. 342 */ 343 public SELF annotations(Annotation...values) { 344 reqnns("values", values); 345 annotations(l(values)); 346 return self(); 347 } 348 349 /** 350 * Same as {@link #annotations(Annotation...)} but uses a list as input. 351 * 352 * @param values 353 * The annotations to register with the context. 354 * <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values. 355 * @return This object. 356 */ 357 public SELF annotations(List<Annotation> values) { 358 annotations.addAll(reqnns("values", values)); 359 return self(); 360 } 361 362 /** 363 * Applies a set of applied to this builder. 364 * 365 * <p> 366 * An {@link AnnotationWork} consists of a single pair of {@link AnnotationInfo} that represents an annotation instance, 367 * and {@link AnnotationApplier} which represents the code used to apply the values in that annotation to a specific builder. 368 * 369 * <h5 class='section'>Example:</h5> 370 * <p class='bjava'> 371 * <jc>// A class annotated with a config annotation.</jc> 372 * <ja>@MarshalledConfig</ja>(unsortedProperties=<js>"$S{unsortedProperties,false}"</js>) 373 * <jk>public class</jk> MyClass {...} 374 * 375 * <jc>// Find all annotations that themselves are annotated with @ContextPropertiesApply.</jc> 376 * Stream<AnnotationInfo<?>> <jv>annotations</jv> = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>).getAnnotations().stream().filter(<jsf>CONTEXT_APPLY_FILTER</jsf>); 377 * VarResolverSession <jv>vrs</jv> = VarResolver.<jsf>DEFAULT</jsf>.createSession(); 378 * AnnotationWorkList <jv>work</jv> = AnnotationWorkList.of(<jv>vrs</jv>, <jv>annotations</jv>); 379 * 380 * <jc>// Apply any settings found on the annotations.</jc> 381 * WriterSerializer <jv>serializer</jv> = JsonSerializer 382 * .<jsm>create</jsm>() 383 * .apply(<jv>work</jv>) 384 * .build(); 385 * </p> 386 * 387 * @param work The list of annotations and appliers to apply to this builder. 388 * <br>Cannot be <jk>null</jk>. 389 * @return This object. 390 */ 391 public SELF apply(AnnotationWorkList work) { 392 reqnn("work", work); 393 applied.addAll(work); 394 work.forEach(x -> builders.forEach(x::apply)); 395 return self(); 396 } 397 398 /** 399 * Same as {@link #applyAnnotations(Object...)} but explicitly specifies a class varargs to avoid compilation warnings. 400 * 401 * @param from The classes or methods on which the annotations are defined. 402 * <br>Cannot contain <jk>null</jk> values. 403 * @return This object. 404 */ 405 public SELF applyAnnotations(Class<?>...from) { 406 reqnns("from", from); 407 return applyAnnotations((Object[])from); 408 } 409 410 /** 411 * Applies any of the various <ja>@XConfig</ja> annotations on the specified classes or methods to this context. 412 * 413 * <p> 414 * Any annotations found that themselves are annotated with {@link ContextApply} will be resolved and 415 * applied as properties to this builder. These annotations include: 416 * <ul class='javatreec'> 417 * <li class='ja'>{@link MarshalledConfig} 418 * <li class='ja'>{@link BsonConfig} 419 * <li class='ja'>{@link CborConfig} 420 * <li class='ja'>{@link CsvConfig} 421 * <li class='ja'>{@link HtmlConfig} 422 * <li class='ja'>{@link HtmlDocConfig} 423 * <li class='ja'>{@link HjsonConfig} 424 * <li class='ja'>{@link HoconConfig} 425 * <li class='ja'>{@link IniConfig} 426 * <li class='ja'>{@link JsonConfig} 427 * <li class='ja'>{@link JsonlConfig} 428 * <li class='ja'>{@link JsonSchemaConfig} 429 * <li class='ja'>{@link JcsConfig} 430 * <li class='ja'>{@link MarkdownConfig} 431 * <li class='ja'>{@link MsgPackConfig} 432 * <li class='ja'>{@link OpenApiConfig} 433 * <li class='ja'>{@link ParserConfig} 434 * <li class='ja'>{@link ParquetConfig} 435 * <li class='ja'>{@link PrototextConfig} 436 * <li class='ja'>{@link PlainTextConfig} 437 * <li class='ja'>{@link SerializerConfig} 438 * <li class='ja'>{@link SoapXmlConfig} 439 * <li class='ja'>{@link TomlConfig} 440 * <li class='ja'>{@link UonConfig} 441 * <li class='ja'>{@link UrlEncodingConfig} 442 * <li class='ja'>{@link XmlConfig} 443 * <li class='ja'>{@link YamlConfig} 444 * <li class='ja'><c>RdfConfig</c> 445 * </ul> 446 * 447 * <p> 448 * Annotations on classes are appended in the following order: 449 * <ol> 450 * <li>On the package of this class. 451 * <li>On interfaces ordered parent-to-child. 452 * <li>On parent classes ordered parent-to-child. 453 * <li>On this class. 454 * </ol> 455 * 456 * <p> 457 * Annotations on methods are appended in the following order: 458 * <ol> 459 * <li>On the package of the method class. 460 * <li>On interfaces ordered parent-to-child. 461 * <li>On parent classes ordered parent-to-child. 462 * <li>On the method class. 463 * <li>On this method and matching methods ordered parent-to-child. 464 * </ol> 465 * 466 * <p> 467 * The default var resolver {@link VarResolver#DEFAULT} is used to resolve any variables in annotation field values. 468 * 469 * <h5 class='section'>Example:</h5> 470 * <p class='bjava'> 471 * <jc>// A class annotated with a config annotation.</jc> 472 * <ja>@MarshalledConfig</ja>(unsortedProperties=<js>"$S{unsortedProperties,false}"</js>) 473 * <jk>public class</jk> MyClass {...} 474 * 475 * <jc>// Apply any settings found on the annotations.</jc> 476 * WriterSerializer <jv>serializer</jv> = JsonSerializer 477 * .<jsm>create</jsm>() 478 * .applyAnnotations(MyClass.<jk>class</jk>) 479 * .build(); 480 * 481 * <jc>// A method annotated with a config annotation.</jc> 482 * <jk>public class</jk> MyClass { 483 * <ja>@MarshalledConfig</ja>(unsortedProperties=<js>"$S{unsortedProperties,false}"</js>) 484 * <jk>public void</jk> myMethod() {...} 485 * } 486 * 487 * <jc>// Apply any settings found on the annotations.</jc> 488 * WriterSerializer <jv>serializer</jv> = JsonSerializer 489 * .<jsm>create</jsm>() 490 * .applyAnnotations(MyClass.<jk>class</jk>.getMethod(<js>"myMethod"</js>)) 491 * .build(); 492 * </p> 493 * 494 * @param from The classes or methods on which the annotations are defined. 495 * Can be any of the following types: 496 * <ul> 497 * <li>{@link Class} 498 * <li>{@link ClassInfo} 499 * <li>{@link Method} 500 * <li>{@link MethodInfo} 501 * <li>A collection/stream/array of anything on this list. 502 * <br>Cannot contain <jk>null</jk> values. 503 * @return This object. 504 */ 505 public SELF applyAnnotations(Object...from) { 506 reqnns("from", from); 507 var work = AnnotationWorkList.create(); 508 Arrays.stream(from).forEach(x -> traverse(work, x)); 509 return apply(work); 510 } 511 512 /** 513 * Traverses the specified object and adds applicable annotations to the work list. 514 * 515 * @param work The annotation work list to add to. 516 * @param x The object to traverse (Class, ClassInfo, Method, or MethodInfo). 517 * @return The work list. 518 */ 519 private static AnnotationWorkList traverse(AnnotationWorkList work, Object x) { 520 var ap = AP; 521 CollectionUtils.traverse(x, y -> { 522 if (x instanceof Class<?> x2) 523 work.add(rstream(ap.find(info(x2))).filter(CONTEXT_APPLY_FILTER)); 524 else if (x instanceof ClassInfo x2) 525 work.add(rstream(ap.find(x2)).filter(CONTEXT_APPLY_FILTER)); 526 else if (x instanceof Method x2) 527 work.add(rstream(ap.find(info(x2))).filter(CONTEXT_APPLY_FILTER)); 528 else if (x instanceof MethodInfo x2) 529 work.add(rstream(ap.find(x2)).filter(CONTEXT_APPLY_FILTER)); 530 else 531 iaex("Invalid type passed to applyAnnotations: %s", cn(x)); 532 }); 533 return work; 534 } 535 536 /** 537 * Returns this builder cast to the specified subtype if it is an instance of that type. 538 * 539 * <p> 540 * This is a type-safe way to check if this builder is an instance of a specific builder subtype 541 * and cast it accordingly. Returns an empty {@link Optional} if this builder is not an instance 542 * of the specified subtype. 543 * 544 * <h5 class='section'>Example:</h5> 545 * <p class='bjava'> 546 * Builder <jv>b</jv> = JsonSerializer.<jsm>create</jsm>(); 547 * Optional<JsonSerializer.Builder<?>> <jv>jsonBuilder</jv> = <jv>b</jv>.asSubtype(JsonSerializer.Builder.<jk>class</jk>); 548 * <jk>if</jk> (<jv>jsonBuilder</jv>.isPresent()) { 549 * <jc>// Use JsonSerializer.Builder<?>-specific methods</jc> 550 * <jv>jsonBuilder</jv>.get().pretty(); 551 * } 552 * </p> 553 * 554 * @param <T> The builder subtype. 555 * @param subtype The builder subtype class to cast to. 556 * <br>Cannot be <jk>null</jk>. 557 * @return An {@link Optional} containing this builder cast to the subtype, or empty if not an instance. 558 */ 559 public <T extends Builder<?>> Optional<T> asSubtype(Class<T> subtype) { 560 return o(reqnn("subtype", subtype).isInstance(this) ? subtype.cast(this) : null); 561 } 562 563 /** 564 * Build the object. 565 * 566 * @return The built object. 567 */ 568 public Context build() { 569 return innerBuild(); 570 } 571 572 /** 573 * Convenience method for calling {@link #build()} while avoiding a cast. 574 * 575 * @param <T> The type to cast the built object to. 576 * @param c The type to cast the built object to. 577 * <br>Cannot be <jk>null</jk>. 578 * @return The built context bean. 579 */ 580 public final <T extends Context> T build(Class<T> c) { 581 if (type == null || ! reqnn("c", c).isAssignableFrom(type)) 582 type = c; 583 return (T)innerBuild(); 584 } 585 586 /** 587 * Specifies a cache to use for hashkey-based caching. 588 * 589 * <p> 590 * When a cache is specified, contexts with the same hash key will be reused from the cache 591 * instead of creating new instances. This improves performance when building multiple contexts 592 * with identical configurations. 593 * 594 * <p> 595 * If <jk>null</jk> is specified, caching is disabled and each call to {@link #build()} will 596 * create a new context instance. 597 * 598 * @param value The cache. 599 * <br>Can be <jk>null</jk> (disables caching, each build creates a new instance). 600 * @return This object. 601 */ 602 public SELF cache(Cache<HashKey,? extends Context> value) { 603 cache = value; 604 return self(); 605 } 606 607 /** 608 * Returns <jk>true</jk> if any of the annotations/appliers can be applied to this builder. 609 * 610 * @param work The work to check. 611 * <br>Cannot be <jk>null</jk>. 612 * @return <jk>true</jk> if any of the annotations/appliers can be applied to this builder. 613 */ 614 public boolean canApply(AnnotationWorkList work) { 615 return reqnn("work", work).stream().anyMatch(x -> builders.stream().anyMatch(x::canApply)); 616 } 617 618 /** 619 * Copy creator. 620 * 621 * @return A new mutable copy of this builder. 622 */ 623 public abstract SELF copy(); 624 625 /** 626 * Null-safe copy: returns a deep copy of the specified value, or <jk>null</jk> if the value is <jk>null</jk>. 627 * 628 * @param value The value to copy. Can be <jk>null</jk> (returns <jk>null</jk>). 629 * @return A copy of the value, or <jk>null</jk> if the value was <jk>null</jk>. 630 */ 631 public static Builder<?> copyOrNull(Builder<?> value) { 632 return value == null ? null : value.copy(); 633 } 634 635 /** 636 * <i><l>Context</l> configuration property: </i> Debug mode. 637 * 638 * <p> 639 * Enables the following additional information during serialization: 640 * <ul class='spaced-list'> 641 * <li> 642 * When bean getters throws exceptions, the exception includes the object stack information 643 * in order to determine how that method was invoked. 644 * <li> 645 * Enables {@link MarshallingTraverseContext.Builder#detectRecursions()}. 646 * </ul> 647 * 648 * <p> 649 * Enables the following additional information during parsing: 650 * <ul class='spaced-list'> 651 * <li> 652 * When bean setters throws exceptions, the exception includes the object stack information 653 * in order to determine how that method was invoked. 654 * </ul> 655 * 656 * <h5 class='section'>Example:</h5> 657 * <p class='bjava'> 658 * <jc>// Create a serializer with debug enabled.</jc> 659 * WriterSerializer <jv>serializer</jv> = JsonSerializer 660 * .<jsm>create</jsm>() 661 * .debug() 662 * .build(); 663 * 664 * <jc>// Create a POJO model with a recursive loop.</jc> 665 * <jk>public class</jk> MyBean { 666 * <jk>public</jk> Object <jf>f</jf>; 667 * } 668 * MyBean <jv>bean</jv> = <jk>new</jk> MyBean(); 669 * <jv>bean</jv>.<jf>f</jf> = <jv>bean</jv>; 670 * 671 * <jc>// Throws a SerializeException and not a StackOverflowError</jc> 672 * String <jv>json</jv> = <jv>serializer</jv>.write(<jv>bean</jv>); 673 * </p> 674 * 675 * <h5 class='section'>See Also:</h5><ul> 676 * <li class='ja'>{@link MarshalledConfig#debug()} 677 * <li class='jm'>{@link ContextSession.Builder#debug(Boolean)} 678 * </ul> 679 * 680 * @return This object. 681 */ 682 public SELF debug() { 683 return debug(true); 684 } 685 686 /** 687 * Same as {@link #debug()} but allows you to explicitly specify the value. 688 * 689 * @param value The value for this setting. 690 * @return This object. 691 */ 692 public SELF debug(boolean value) { 693 debug = value; 694 return self(); 695 } 696 697 /** 698 * Returns all the annotations that have been applied to this builder. 699 * 700 * @return All the annotations that have been applied to this builder. 701 */ 702 public AnnotationWorkList getApplied() { return applied; } 703 704 /** 705 * Returns the context class that this builder should create. 706 * 707 * @return The context class if it was specified. 708 */ 709 public Optional<Class<?>> getType() { return o(type); } 710 711 /** 712 * Returns the hashkey of this builder. 713 * 714 * <p> 715 * Used to return previously instantiated context beans that have matching hashkeys. 716 * The {@link HashKey} object is suitable for use as a hashmap key of a map of context beans. 717 * A context bean is considered equivalent if the {@link HashKey#equals(Object)} method is the same. 718 * 719 * @return The hashkey of this builder. 720 */ 721 public HashKey hashKey() { 722 return HashKey.of(debug, type, annotations); 723 } 724 725 /** 726 * Specifies a pre-instantiated bean for the {@link #build()} method to return. 727 * 728 * <p> 729 * If a non-null value is provided and it's an instance of the context type, {@link #build()} will return 730 * that instance instead of creating a new one. If <jk>null</jk>, the normal build process continues. 731 * 732 * @param value The value for this setting. 733 * <br>Can be <jk>null</jk> (normal build process will continue). 734 * @return This object. 735 */ 736 public SELF impl(Context value) { 737 impl = value; 738 return self(); 739 } 740 741 /** 742 * Returns <jk>true</jk> if debug is enabled. 743 * 744 * @return <jk>true</jk> if debug is enabled. 745 */ 746 public boolean isDebug() { return debug; } 747 748 /** 749 * Associates a context class with this builder. 750 * 751 * <p> 752 * This is the type of object that this builder creates when the {@link #build()} method is called. 753 * 754 * <p> 755 * By default, it's the outer class of where the builder class is defined. 756 * 757 * <p> 758 * If <jk>null</jk> is set, {@link #build()} will throw an exception. The default constructor automatically 759 * sets this to the outer class, so <jk>null</jk> should only be set explicitly if you want to override the default. 760 * 761 * @param value The context class that this builder should create. 762 * <br>Can be <jk>null</jk> (will cause {@link #build()} to throw an exception). 763 * @return This object. 764 */ 765 public SELF type(Class<? extends Context> value) { 766 type = value; 767 return self(); 768 } 769 770 /** 771 * Registers the specified secondary builders with this context builder. 772 * 773 * <p> 774 * When {@link #apply(AnnotationWorkList)} is called, it gets called on all registered builders. 775 * 776 * @param values The builders to add to the list of builders. 777 * <br>Cannot contain <jk>null</jk> values. 778 */ 779 protected void registerBuilders(Object...values) { 780 reqnns("values", values); 781 for (var b : values) { 782 if (b == this) 783 builders.add(b); 784 else if (b instanceof Builder b2) 785 builders.addAll(b2.builders); 786 else 787 builders.add(b); 788 } 789 } 790 791 private ConstructorInfo getContextConstructor() { 792 return CONTEXT_CONSTRUCTORS.get(type, getClass()); 793 } 794 795 private Context innerBuild() { 796 if (type == null) 797 throw rex("Type not specified for context builder %s", cn(getClass())); 798 if (nn(impl) && type.isInstance(impl)) 799 return type.cast(impl); 800 if (nn(cache)) 801 return cache.get(hashKey(), () -> getContextConstructor().newInstance(this)); 802 return getContextConstructor().newInstance(this); 803 } 804 } 805 806 /** 807 * Cache of static <c>create</c> methods that return builder instances for context classes. 808 * 809 * <p> 810 * This cache stores {@link MethodInfo} objects for public static methods named <c>create</c> that return 811 * builder objects. The methods are discovered by: 812 * <ol> 813 * <li>Finding public constructors that take a single parameter (the builder type) 814 * <li>Looking for no-arg static <c>create</c> methods whose return type is assignable to one of those builder types 815 * <li>Choosing the one declared closest to the context class (so a subclass's own <c>create</c> wins over an 816 * inherited parent <c>create</c>) 817 * <li>Caching the result for future lookups 818 * </ol> 819 * 820 * <p> 821 * Used by {@link #createBuilder(Class)} to efficiently locate and invoke builder creation methods. 822 * 823 * @see #createBuilder(Class) 824 */ 825 private static final Cache<Class<?>,MethodInfo> BUILDER_CREATE_METHODS = Cache.<Class<?>,MethodInfo>create() 826 .supplier(type -> { 827 var c = info(type); 828 // @formatter:off 829 var builderTypes = c.getPublicConstructors().stream() 830 .filter(ci -> ci.hasNumParameters(1) && ! ci.getParameter(0).getParameterType().is(type)) 831 .map(ci -> ci.getParameter(0).getParameterType()) 832 .toList(); 833 // A subclass's constructor can take a parent builder type (for example Json5Parser(JsonParser.Builder) 834 // or HtmlSchemaDocSerializer(HtmlDocSerializer.Builder)), so both the subclass's own create() (whose 835 // builder is assignable to that type) and the inherited parent create() match. Prefer the create() 836 // declared closest to the type itself so the subclass's own builder defaults win. 837 return c.getPublicMethods().stream() 838 .filter(x -> x.isStatic() 839 && x.isNotDeprecated() 840 && x.hasName("create") 841 && x.hasNumParameters(0) 842 && builderTypes.stream().anyMatch(bt -> x.getReturnType().isAssignableTo(bt))) 843 .reduce((a, b) -> b.getDeclaringClass().isChildOf(a.getDeclaringClass()) ? b : a) 844 .orElseThrow(() -> rex("Could not find builder create method on class %s", cn(type))); 845 // @formatter:on 846 }) 847 .build(); 848 849 850 /** 851 * Cache of public constructors on context classes that accept builder instances. 852 * 853 * <p> 854 * This cache stores {@link ConstructorInfo} objects for public constructors on context classes that take 855 * a single parameter of the builder type. The constructor is discovered by: 856 * <ol> 857 * <li>Finding public constructors on the context type that take exactly one parameter 858 * <li>Matching constructors where the parameter type is a parent of (or equal to) the builder type 859 * <li>Caching the result for future lookups 860 * </ol> 861 * 862 * <p> 863 * Used by {@link Builder#getContextConstructor()} to efficiently locate and invoke context constructors 864 * when building context instances from builders. 865 * 866 * @see Builder#getContextConstructor() 867 * @see Builder#innerBuild() 868 */ 869 private static final Cache2<Class<? extends Context>,Class<? extends Builder>,ConstructorInfo> CONTEXT_CONSTRUCTORS = Cache2.<Class<? extends Context>,Class<? extends Builder>,ConstructorInfo>create() 870 .supplier((cacheType, builderType) -> { 871 var ct = info(cacheType); 872 var bt = info(builderType); 873 return ct 874 .getPublicConstructor(x -> x.hasNumParameters(1) && x.getParameter(0).getParameterType().isAssignableFrom(builderType)) 875 .orElseThrow(() -> rex("Public constructor not found: %s(%s)", ct.getName(), bt.getName())); 876 }) 877 .build(); 878 879 /** 880 * Default annotation provider instance for finding annotations on classes, methods, fields, and constructors. 881 * 882 * <p> 883 * This is a static reference to {@link AnnotationProvider#INSTANCE}, used by the {@link Builder#traverse(AnnotationWorkList, Object)} 884 * method to discover annotations that can be applied to context builders. 885 * 886 * <p> 887 * The annotation provider supports: 888 * <ul> 889 * <li>Finding annotations on classes, methods, fields, and constructors 890 * <li>Traversing class hierarchies (parent-to-child or child-to-parent order) 891 * <li>Supporting runtime annotations (annotations added programmatically) 892 * <li>Caching results for performance 893 * </ul> 894 * 895 * @see AnnotationProvider 896 * @see Builder#traverse(AnnotationWorkList, Object) 897 */ 898 private static final AnnotationProvider AP = AnnotationProvider.INSTANCE; 899 900 /** 901 * Predicate for annotations that themselves are annotated with {@link ContextApply}. 902 * 903 * <p> 904 * Also matches {@link BeanConfig} from {@code juneau-commons}, which intentionally lacks a 905 * {@link ContextApply @ContextApply} meta-annotation because {@code juneau-commons} cannot reference 906 * marshall-layer types. {@link AnnotationWorkList} routes {@link BeanConfig} to the 907 * {@link BeanConfigAnnotation} applier via an explicit special case. 908 */ 909 public static final Predicate<AnnotationInfo<?>> CONTEXT_APPLY_FILTER = x -> x.hasAnnotation(ContextApply.class) || x.annotationType() == BeanConfig.class; 910 911 /** 912 * Instantiates a builder of the specified context class. 913 * 914 * <p> 915 * Looks for a public static method called <c>create</c> that returns an object that can be passed into a public 916 * or protected constructor of the class. 917 * 918 * @param type The builder to create. 919 * <br>Cannot be <jk>null</jk>. 920 * @return A new builder. 921 */ 922 public static Builder createBuilder(Class<? extends Context> type) { 923 reqnn("type", type); 924 try { 925 return ((Builder)BUILDER_CREATE_METHODS.get(type).invoke(null)).type(type); 926 } catch (ExecutableException e) { 927 throw toRex(e); 928 } 929 } 930 931 932 private final AnnotationProvider annotationProvider; 933 private final boolean debug; 934 private final List<Annotation> annotations; 935 936 /** 937 * Constructor for this class. 938 * 939 * @param builder The builder for this class. 940 * <br>Cannot be <jk>null</jk>. 941 */ 942 protected Context(Builder builder) { 943 reqnn("builder", builder); 944 init(builder); 945 annotations = cp(builder.annotations); 946 annotationProvider = AnnotationProvider.create().addRuntimeAnnotations(annotations).build(); 947 debug = builder.debug; 948 } 949 950 /** 951 * Copy constructor. 952 * 953 * @param copyFrom The context to copy from. 954 * <br>Cannot be <jk>null</jk>. 955 */ 956 protected Context(Context copyFrom) { 957 reqnn("copyFrom", copyFrom); 958 annotationProvider = copyFrom.annotationProvider; 959 annotations = cp(copyFrom.annotations); 960 debug = copyFrom.debug; 961 } 962 963 /** 964 * Creates a builder from this context object. 965 * 966 * <p> 967 * Builders are used to define new contexts (e.g. serializers, parsers) based on existing configurations. 968 * 969 * @return A new Builder object. 970 */ 971 public Builder copy() { 972 throw uoex(); 973 } 974 975 /** 976 * Create a session builder based on the properties defined on this context. 977 * 978 * <p> 979 * Use this method for creating sessions where you want to override basic settings. 980 * Otherwise, use {@link #getSession()} directly. 981 * 982 * @return A new session builder. 983 */ 984 public ContextSession.Builder createSession() { 985 throw uoex(); 986 } 987 988 /** 989 * Returns the annotation provider for this context. 990 * 991 * @return The annotation provider for this context. 992 */ 993 public AnnotationProvider getAnnotationProvider() { return annotationProvider; } 994 995 /** 996 * Returns a session to use for this context. 997 * 998 * <p> 999 * Note that subclasses may opt to return a reusable non-modifiable session. 1000 * 1001 * @return A new session object. 1002 */ 1003 public ContextSession getSession() { return createSession().build(); } 1004 1005 /** 1006 * Debug mode. 1007 * 1008 * @see Context.Builder#debug() 1009 * @return 1010 * <jk>true</jk> if debug mode is enabled. 1011 */ 1012 public boolean isDebug() { return debug; } 1013 1014 @Override /* Overridden from Object */ 1015 public String toString() { 1016 return r(properties()); 1017 } 1018 1019 /** 1020 * Perform optional initialization on builder before it is used. 1021 * 1022 * <p> 1023 * Default behavior is a no-op. 1024 * 1025 * @param builder The builder to initialize. 1026 */ 1027 protected void init(Builder builder) {} 1028 1029 /** 1030 * Returns the properties on this bean as a map for debugging. 1031 * 1032 * @return The properties on this bean as a map for debugging. 1033 */ 1034 protected FluentMap<String,Object> properties() { 1035 return filteredBeanPropertyMap() 1036 .a("annotations", annotations) 1037 .a("debug", debug); 1038 } 1039}