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.commons.reflect.ReflectionUtils.*; 020import static org.apache.juneau.commons.reflect.Visibility.*; 021import static org.apache.juneau.commons.utils.AssertionUtils.*; 022import static org.apache.juneau.commons.utils.ClassUtils.*; 023import static org.apache.juneau.commons.utils.CollectionUtils.*; 024import static org.apache.juneau.commons.utils.ThrowableUtils.*; 025import static org.apache.juneau.commons.utils.Utils.*; 026 027import java.beans.*; 028import java.io.*; 029import java.lang.annotation.*; 030import java.lang.reflect.*; 031import java.util.*; 032import java.util.stream.*; 033 034import org.apache.juneau.annotation.*; 035import org.apache.juneau.commons.collections.*; 036import org.apache.juneau.commons.function.*; 037import org.apache.juneau.commons.reflect.*; 038import org.apache.juneau.commons.reflect.Visibility; 039import org.apache.juneau.cp.*; 040import org.apache.juneau.json.*; 041import org.apache.juneau.marshaller.*; 042import org.apache.juneau.serializer.*; 043import org.apache.juneau.swap.*; 044 045/** 046 * Bean context. 047 * 048 * <p> 049 * This class servers multiple purposes: 050 * <ul class='spaced-list'> 051 * <li> 052 * Provides the ability to wrap beans inside {@link Map} interfaces. 053 * <li> 054 * Serves as a repository for metadata on POJOs, such as associated {@link Bean @Bean} annotations, 055 * {@link PropertyNamer PropertyNamers}, etc... which are used to tailor how POJOs are serialized and parsed. 056 * </ul> 057 * 058 * <p> 059 * All serializers and parsers use this context so that they can handle POJOs using a common framework. 060 * 061 * <h5 class='topic'>Bean Contexts</h5> 062 * 063 * <p> 064 * Bean contexts are created through the {@link BeanContext#create() BeanContext.create()} and {@link Builder#build()} methods. 065 * <br>These context objects are read-only, reusable, and thread-safe. 066 * 067 * <p> 068 * Each bean context maintains a cache of {@link ClassMeta} objects that describe information about classes encountered. 069 * These <c>ClassMeta</c> objects are time-consuming to construct. 070 * Therefore, instances of {@link BeanContext} that share the same <js>"BeanContext.*"</js> property values share 071 * the same cache. This allows for efficient reuse of <c>ClassMeta</c> objects so that the information about 072 * classes only needs to be calculated once. 073 * Because of this, many of the properties defined on the {@link BeanContext} class cannot be overridden on the session. 074 * 075 * <h5 class='topic'>Bean Sessions</h5> 076 * 077 * <p> 078 * Whereas <c>BeanContext</c> objects are permanent, unchangeable, cached, and thread-safe, 079 * {@link BeanSession} objects are ephemeral and not thread-safe. 080 * They are meant to be used as quickly-constructed scratchpads for creating bean maps. 081 * {@link BeanMap} objects can only be created through the session. 082 * 083 * <h5 class='topic'>BeanContext configuration properties</h5> 084 * 085 * <p> 086 * <c>BeanContexts</c> have several configuration properties that can be used to tweak behavior on how beans are 087 * handled. These are denoted as the static <jsf>BEAN_*</jsf> fields on this class. 088 * 089 * <p> 090 * Some settings (e.g. {@link Builder#beansRequireDefaultConstructor()}) are used to differentiate between bean 091 * and non-bean classes. 092 * Attempting to create a bean map around one of these objects will throw a {@link BeanRuntimeException}. 093 * The purpose for this behavior is so that the serializers can identify these non-bean classes and convert them to 094 * plain strings using the {@link Object#toString()} method. 095 * 096 * <p> 097 * Some settings (e.g. {@link Builder#beanFieldVisibility(Visibility)}) are used to determine what kinds of properties are 098 * detected on beans. 099 * 100 * <p> 101 * Some settings (e.g. {@link Builder#beanMapPutReturnsOldValue()}) change the runtime behavior of bean maps. 102 * 103 * <h5 class='section'>Example:</h5> 104 * 105 * <p class='bjava'> 106 * <jc>// Construct a context from scratch.</jc> 107 * BeanContext <jv>beanContext</jv> = BeanContext 108 * .<jsm>create</jsm>() 109 * .beansRequireDefaultConstructor() 110 * .notBeanClasses(Foo.<jk>class</jk>) 111 * .build(); 112 * </p> 113 * 114 * <h5 class='topic'>Bean Maps</h5> 115 * 116 * <p> 117 * {@link BeanMap BeanMaps} are wrappers around Java beans that allow properties to be retrieved and 118 * set using the common {@link Map#put(Object,Object)} and {@link Map#get(Object)} methods. 119 * 120 * <p> 121 * Bean maps are created in two ways... 122 * <ol> 123 * <li>{@link BeanSession#toBeanMap(Object) BeanSession.toBeanMap()} - Wraps an existing bean inside a {@code Map} 124 * wrapper. 125 * <li>{@link BeanSession#newBeanMap(Class) BeanSession.newBeanMap()} - Create a new bean instance wrapped in a 126 * {@code Map} wrapper. 127 * </ol> 128 * 129 * <h5 class='section'>Example:</h5> 130 * 131 * <p class='bjava'> 132 * <jc>// A sample bean class</jc> 133 * <jk>public class</jk> Person { 134 * <jk>public</jk> String getName(); 135 * <jk>public void</jk> setName(String <jv>name</jv>); 136 * <jk>public int</jk> getAge(); 137 * <jk>public void</jk> setAge(<jk>int</jk> <jv>age</jv>); 138 * } 139 * 140 * <jc>// Create a new bean session</jc> 141 * BeanSession <jv>session</jv> = BeanContext.<jsf>DEFAULT</jsf>.createSession(); 142 * 143 * <jc>// Wrap an existing bean in a new bean map</jc> 144 * BeanMap<Person> <jv>map1</jv> = <jv>session</jv>.toBeanMap(<jk>new</jk> Person()); 145 * <jv>map1</jv>.put(<js>"name"</js>, <js>"John Smith"</js>); 146 * <jv>map1</jv>.put(<js>"age"</js>, 45); 147 * 148 * <jc>// Create a new bean instance wrapped in a new bean map</jc> 149 * BeanMap<Person> <jv>map2</jv> = <jv>session</jv>.newBeanMap(Person.<jk>class</jk>); 150 * <jv>map2</jv>.put(<js>"name"</js>, <js>"John Smith"</js>); 151 * <jv>map2</jv>.put(<js>"age"</js>, 45); 152 * Person <jv>person</jv> = <jv>map2</jv>.getBean(); <jc>// Get the bean instance that was created.</jc> 153 * </p> 154 * 155 * <h5 class='section'>Notes:</h5><ul> 156 * <li class='note'>This class is thread safe and reusable. 157 * </ul> 158 * 159 * <h5 class='section'>See Also:</h5><ul> 160 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/BeanContextBasics">Bean Context Basics</a> 161 * </ul> 162 */ 163@SuppressWarnings({ "unchecked", "rawtypes" }) 164public class BeanContext extends Context { 165 166 /** 167 * Builder class. 168 */ 169 public static class Builder extends Context.Builder { 170 171 private static final Cache<HashKey,BeanContext> CACHE = Cache.of(HashKey.class, BeanContext.class).build(); 172 173 private static int integer(boolean...values) { 174 var n = 0; 175 for (var b : values) 176 n = (n << 1) | (b ? 1 : 0); 177 return n; 178 } 179 private Visibility beanClassVisibility; 180 private Visibility beanConstructorVisibility; 181 private Visibility beanMethodVisibility; 182 private Visibility beanFieldVisibility; 183 private boolean disableBeansRequireSomeProperties; 184 private boolean beanMapPutReturnsOldValue; 185 private boolean beansRequireDefaultConstructor; 186 private boolean beansRequireSerializable; 187 private boolean beansRequireSettersForGetters; 188 private boolean disableIgnoreTransientFields; 189 private boolean disableIgnoreUnknownNullBeanProperties; 190 private boolean disableIgnoreMissingSetters; 191 private boolean disableInterfaceProxies; 192 private boolean findFluentSetters; 193 private boolean ignoreInvocationExceptionsOnGetters; 194 private boolean ignoreInvocationExceptionsOnSetters; 195 private boolean ignoreUnknownBeanProperties; 196 private boolean ignoreUnknownEnumValues; 197 private boolean sortProperties; 198 private boolean useEnumNames; 199 private boolean useJavaBeanIntrospector; 200 private String typePropertyName; 201 private MediaType mediaType; 202 private Locale locale; 203 private TimeZone timeZone; 204 private Class<? extends PropertyNamer> propertyNamer; 205 private List<ClassInfo> beanDictionary; 206 private List<Object> swaps; 207 private Set<ClassInfo> notBeanClasses; 208 209 private Set<String> notBeanPackages; 210 211 /** 212 * Constructor. 213 * 214 * All default settings. 215 */ 216 protected Builder() { 217 beanClassVisibility = env("BeanContext.beanClassVisibility", PUBLIC); 218 beanConstructorVisibility = env("BeanContext.beanConstructorVisibility", PUBLIC); 219 beanDictionary = list(); 220 beanFieldVisibility = env("BeanContext.beanFieldVisibility", PUBLIC); 221 beanMapPutReturnsOldValue = env("BeanContext.beanMapPutReturnsOldValue", false); 222 beanMethodVisibility = env("BeanContext.beanMethodVisibility", PUBLIC); 223 beansRequireDefaultConstructor = env("BeanContext.beansRequireDefaultConstructor", false); 224 beansRequireSerializable = env("BeanContext.beansRequireSerializable", false); 225 beansRequireSettersForGetters = env("BeanContext.beansRequireSettersForGetters", false); 226 disableBeansRequireSomeProperties = env("BeanContext.disableBeansRequireSomeProperties", false); 227 disableIgnoreMissingSetters = env("BeanContext.disableIgnoreMissingSetters", false); 228 disableIgnoreTransientFields = env("BeanContext.disableIgnoreTransientFields", false); 229 disableIgnoreUnknownNullBeanProperties = env("BeanContext.disableIgnoreUnknownNullBeanProperties", false); 230 disableInterfaceProxies = env("BeanContext.disableInterfaceProxies", false); 231 findFluentSetters = env("BeanContext.findFluentSetters", false); 232 ignoreInvocationExceptionsOnGetters = env("BeanContext.ignoreInvocationExceptionsOnGetters", false); 233 ignoreInvocationExceptionsOnSetters = env("BeanContext.ignoreInvocationExceptionsOnSetters", false); 234 ignoreUnknownBeanProperties = env("BeanContext.ignoreUnknownBeanProperties", false); 235 ignoreUnknownEnumValues = env("BeanContext.ignoreUnknownEnumValues", false); 236 locale = env("BeanContext.locale").map(x -> Locale.forLanguageTag(x)).orElse(Locale.getDefault()); 237 mediaType = env("BeanContext.mediaType").map(x -> MediaType.of(x)).orElse(null); 238 notBeanClasses = new TreeSet<>(); 239 notBeanPackages = new TreeSet<>(); 240 propertyNamer = null; 241 sortProperties = env("BeanContext.sortProperties", false); 242 swaps = list(); 243 timeZone = env("BeanContext.timeZone").map(x -> TimeZone.getTimeZone(x)).orElse(null); 244 typePropertyName = env("BeanContext.typePropertyName", "_type"); 245 useEnumNames = env("BeanContext.useEnumNames", false); 246 useJavaBeanIntrospector = env("BeanContext.useJavaBeanIntrospector", false); 247 } 248 249 /** 250 * Copy constructor. 251 * 252 * @param copyFrom The bean to copy from. 253 */ 254 protected Builder(BeanContext copyFrom) { 255 super(copyFrom); 256 beanClassVisibility = copyFrom.beanClassVisibility; 257 beanConstructorVisibility = copyFrom.beanConstructorVisibility; 258 beanDictionary = copyOf(copyFrom.beanDictionary); 259 beanFieldVisibility = copyFrom.beanFieldVisibility; 260 beanMapPutReturnsOldValue = copyFrom.beanMapPutReturnsOldValue; 261 beanMethodVisibility = copyFrom.beanMethodVisibility; 262 beansRequireDefaultConstructor = copyFrom.beansRequireDefaultConstructor; 263 beansRequireSerializable = copyFrom.beansRequireSerializable; 264 beansRequireSettersForGetters = copyFrom.beansRequireSettersForGetters; 265 disableBeansRequireSomeProperties = ! copyFrom.beansRequireSomeProperties; 266 disableIgnoreMissingSetters = ! copyFrom.ignoreMissingSetters; 267 disableIgnoreTransientFields = ! copyFrom.ignoreTransientFields; 268 disableIgnoreUnknownNullBeanProperties = ! copyFrom.ignoreUnknownNullBeanProperties; 269 disableInterfaceProxies = ! copyFrom.useInterfaceProxies; 270 findFluentSetters = copyFrom.findFluentSetters; 271 ignoreInvocationExceptionsOnGetters = copyFrom.ignoreInvocationExceptionsOnGetters; 272 ignoreInvocationExceptionsOnSetters = copyFrom.ignoreInvocationExceptionsOnSetters; 273 ignoreUnknownBeanProperties = copyFrom.ignoreUnknownBeanProperties; 274 ignoreUnknownEnumValues = copyFrom.ignoreUnknownEnumValues; 275 locale = copyFrom.locale; 276 mediaType = copyFrom.mediaType; 277 notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses); 278 notBeanPackages = toSortedSet(copyFrom.notBeanPackages, false); 279 propertyNamer = copyFrom.propertyNamer; 280 sortProperties = copyFrom.sortProperties; 281 swaps = copyOf(copyFrom.swaps); 282 timeZone = copyFrom.timeZone; 283 typePropertyName = copyFrom.typePropertyName; 284 useEnumNames = copyFrom.useEnumNames; 285 useJavaBeanIntrospector = copyFrom.useJavaBeanIntrospector; 286 } 287 288 /** 289 * Copy constructor. 290 * 291 * @param copyFrom The builder to copy from. 292 */ 293 protected Builder(Builder copyFrom) { 294 super(copyFrom); 295 beanClassVisibility = copyFrom.beanClassVisibility; 296 beanConstructorVisibility = copyFrom.beanConstructorVisibility; 297 beanDictionary = copyOf(copyFrom.beanDictionary); 298 beanFieldVisibility = copyFrom.beanFieldVisibility; 299 beanMapPutReturnsOldValue = copyFrom.beanMapPutReturnsOldValue; 300 beanMethodVisibility = copyFrom.beanMethodVisibility; 301 beansRequireDefaultConstructor = copyFrom.beansRequireDefaultConstructor; 302 beansRequireSerializable = copyFrom.beansRequireSerializable; 303 beansRequireSettersForGetters = copyFrom.beansRequireSettersForGetters; 304 disableBeansRequireSomeProperties = copyFrom.disableBeansRequireSomeProperties; 305 disableIgnoreMissingSetters = copyFrom.disableIgnoreMissingSetters; 306 disableIgnoreTransientFields = copyFrom.disableIgnoreTransientFields; 307 disableIgnoreUnknownNullBeanProperties = copyFrom.disableIgnoreUnknownNullBeanProperties; 308 disableInterfaceProxies = copyFrom.disableInterfaceProxies; 309 findFluentSetters = copyFrom.findFluentSetters; 310 ignoreInvocationExceptionsOnGetters = copyFrom.ignoreInvocationExceptionsOnGetters; 311 ignoreInvocationExceptionsOnSetters = copyFrom.ignoreInvocationExceptionsOnSetters; 312 ignoreUnknownBeanProperties = copyFrom.ignoreUnknownBeanProperties; 313 ignoreUnknownEnumValues = copyFrom.ignoreUnknownEnumValues; 314 locale = copyFrom.locale; 315 mediaType = copyFrom.mediaType; 316 notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses); 317 notBeanPackages = toSortedSet(copyFrom.notBeanPackages); 318 propertyNamer = copyFrom.propertyNamer; 319 sortProperties = copyFrom.sortProperties; 320 swaps = copyOf(copyFrom.swaps); 321 timeZone = copyFrom.timeZone; 322 typePropertyName = copyFrom.typePropertyName; 323 useEnumNames = copyFrom.useEnumNames; 324 useJavaBeanIntrospector = copyFrom.useJavaBeanIntrospector; 325 } 326 327 @Override /* Overridden from Builder */ 328 public Builder annotations(Annotation...values) { 329 super.annotations(values); 330 return this; 331 } 332 333 @Override /* Overridden from Builder */ 334 public Builder apply(AnnotationWorkList work) { 335 super.apply(work); 336 return this; 337 } 338 339 @Override /* Overridden from Builder */ 340 public Builder applyAnnotations(Class<?>...from) { 341 super.applyAnnotations(from); 342 return this; 343 } 344 345 @Override /* Overridden from Builder */ 346 public Builder applyAnnotations(Object...from) { 347 super.applyAnnotations(from); 348 return this; 349 } 350 351 /** 352 * Minimum bean class visibility. 353 * 354 * <p> 355 * Classes are not considered beans unless they meet the minimum visibility requirements. 356 * For example, if the visibility is <jsf>PUBLIC</jsf> and the bean class is <jk>protected</jk>, then the class 357 * will not be interpreted as a bean class and be serialized as a string. 358 * Use this setting to reduce the visibility requirement. 359 * 360 * <h5 class='section'>Example:</h5> 361 * <p class='bjava'> 362 * <jc>// A bean with a protected class and one field.</jc> 363 * <jk>protected class</jk> MyBean { 364 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 365 * } 366 * 367 * <jc>// Create a serializer that's capable of serializing the class.</jc> 368 * WriterSerializer <jv>serializer</jv> = JsonSerializer 369 * .<jsm>create</jsm>() 370 * .beanClassVisibility(<jsf>PROTECTED</jsf>) 371 * .build(); 372 * 373 * <jc>// Produces: {"foo","bar"}</jc> 374 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 375 * </p> 376 * 377 * <h5 class='section'>Notes:</h5><ul> 378 * <li class='note'>The {@link Bean @Bean} annotation can be used on a non-public bean class to override this setting. 379 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean class to ignore it as a bean. 380 * </ul> 381 * 382 * <h5 class='section'>See Also:</h5><ul> 383 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanClassVisibility()} 384 * </ul> 385 * 386 * @param value 387 * The new value for this setting. 388 * <br>The default is {@link Visibility#PUBLIC}. 389 * <br>Cannot be <jk>null</jk>. 390 * @return This object. 391 */ 392 public Builder beanClassVisibility(Visibility value) { 393 beanClassVisibility = assertArgNotNull("value", value); 394 return this; 395 } 396 397 /** 398 * Minimum bean constructor visibility. 399 * 400 * <p> 401 * Only look for constructors with the specified minimum visibility. 402 * 403 * <p> 404 * This setting affects the logic for finding no-arg constructors for bean. Normally, only <jk>public</jk> no-arg 405 * constructors are used. Use this setting if you want to reduce the visibility requirement. 406 * 407 * <h5 class='section'>Example:</h5> 408 * <p class='bjava'> 409 * <jc>// A bean with a protected constructor and one field.</jc> 410 * <jk>public class</jk> MyBean { 411 * <jk>public</jk> String <jf>foo</jf>; 412 * 413 * <jk>protected</jk> MyBean() {} 414 * } 415 * 416 * <jc>// Create a parser capable of calling the protected constructor.</jc> 417 * ReaderParser <jv>parser</jv> = ReaderParser 418 * .<jsm>create</jsm>() 419 * .beanConstructorVisibility(<jsf>PROTECTED</jsf>) 420 * .build(); 421 * 422 * <jc>// Use it.</jc> 423 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>); 424 * </p> 425 * 426 * <h5 class='section'>Notes:</h5><ul> 427 * <li class='note'>The {@link Beanc @Beanc} annotation can also be used to expose a non-public constructor. 428 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean constructor to ignore it. 429 * </ul> 430 * 431 * <h5 class='section'>See Also:</h5><ul> 432 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanConstructorVisibility()} 433 * </ul> 434 * 435 * @param value 436 * The new value for this setting. 437 * <br>The default is {@link Visibility#PUBLIC}. 438 * <br>Cannot be <jk>null</jk>. 439 * @return This object. 440 */ 441 public Builder beanConstructorVisibility(Visibility value) { 442 beanConstructorVisibility = assertArgNotNull("value", value); 443 return this; 444 } 445 446 /** 447 * Returns the bean dictionary list. 448 * 449 * <p> 450 * Gives access to the inner list if you need to make more than simple additions via {@link #beanDictionary(Class...)}. 451 * 452 * @return The bean dictionary list. 453 * @see #beanDictionary(Class...) 454 */ 455 public List<ClassInfo> beanDictionary() { 456 return beanDictionary; 457 } 458 459 /** 460 * Convenience method for {@link #beanDictionary(ClassInfo...)} that accepts {@link Class} objects. 461 * 462 * @param values 463 * The values to add to this setting. 464 * <br>Cannot contain <jk>null</jk> values. 465 * @return This object. 466 * @see #beanDictionary(ClassInfo...) 467 */ 468 public Builder beanDictionary(Class<?>...values) { 469 assertArgNoNulls("values", values); 470 return beanDictionary(Stream.of(values).map(ReflectionUtils::info).toArray(ClassInfo[]::new)); 471 } 472 473 /** 474 * Bean dictionary. 475 * 476 * <p> 477 * The list of classes that make up the bean dictionary in this bean context. 478 * 479 * <p> 480 * Values are prepended to the list so that later calls can override classes of earlier calls. 481 * 482 * <p> 483 * A dictionary is a name/class mapping used to find class types during parsing when they cannot be inferred 484 * through reflection. The names are defined through the {@link Bean#typeName() @Bean(typeName)} annotation defined 485 * on the bean class. For example, if a class <c>Foo</c> has a type-name of <js>"myfoo"</js>, then it would end up 486 * serialized as <js>"{_type:'myfoo',...}"</js> in JSON 487 * or <js>"<myfoo>...</myfoo>"</js> in XML. 488 * 489 * <p> 490 * This setting tells the parsers which classes to look for when resolving <js>"_type"</js> attributes. 491 * 492 * <p> 493 * Values can consist of any of the following types: 494 * <ul> 495 * <li>Any bean class that specifies a value for {@link Bean#typeName() @Bean(typeName)}. 496 * <li>Any subclass of {@link BeanDictionaryList} containing a collection of bean classes with type name annotations. 497 * <li>Any subclass of {@link BeanDictionaryMap} containing a mapping of type names to classes without type name annotations. 498 * <li>Any array or collection of the objects above. 499 * </ul> 500 * 501 * <h5 class='section'>Example:</h5> 502 * <p class='bjava'> 503 * <jc>// POJOs with @Bean(name) annotations.</jc> 504 * <ja>@Bean</ja>(typeName=<js>"foo"</js>) 505 * <jk>public class</jk> Foo {...} 506 * <ja>@Bean</ja>(typeName=<js>"bar"</js>) 507 * <jk>public class</jk> Bar {...} 508 * 509 * <jc>// Create a parser and tell it which classes to try to resolve.</jc> 510 * ReaderParser <jv>parser</jv> = JsonParser 511 * .<jsm>create</jsm>() 512 * .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>) 513 * .addBeanTypes() 514 * .build(); 515 * 516 * <jc>// A bean with a field with an indeterminate type.</jc> 517 * <jk>public class</jk> MyBean { 518 * <jk>public</jk> Object <jf>mySimpleField</jf>; 519 * } 520 * 521 * <jc>// Parse bean.</jc> 522 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{mySimpleField:{_type:'foo',...}}"</js>, MyBean.<jk>class</jk>); 523 * </p> 524 * 525 * <p> 526 * Another option is to use the {@link Bean#dictionary()} annotation on the POJO class itself: 527 * 528 * <p class='bjava'> 529 * <jc>// Instead of by parser, define a bean dictionary on a class through an annotation.</jc> 530 * <jc>// This applies to all properties on this class and all subclasses.</jc> 531 * <ja>@Bean</ja>(dictionary={Foo.<jk>class</jk>,Bar.<jk>class</jk>}) 532 * <jk>public class</jk> MyBean { 533 * <jk>public</jk> Object <jf>mySimpleField</jf>; <jc>// May contain Foo or Bar object.</jc> 534 * <jk>public</jk> Map<String,Object> <jf>myMapField</jf>; <jc>// May contain Foo or Bar objects.</jc> 535 * } 536 * </p> 537 * 538 * <p> 539 * A typical usage is to allow for HTML documents to be parsed back into HTML beans: 540 * <p class='bjava'> 541 * <jc>// Use the predefined HTML5 bean dictionary which is a BeanDictionaryList.</jc> 542 * ReaderParser <jv>parser</jv> = HtmlParser 543 * .<jsm>create</jsm>() 544 * .dictionary(HtmlBeanDictionary.<jk>class</jk>) 545 * .build(); 546 * 547 * <jc>// Parse an HTML body into HTML beans.</jc> 548 * Body <jv>body</jv> = <jv>parser</jv>.parse(<js>"<body><ul><li>foo</li><li>bar</li></ul>"</js>, Body.<jk>class</jk>); 549 * </p> 550 * 551 * <h5 class='section'>See Also:</h5><ul> 552 * <li class='ja'>{@link org.apache.juneau.annotation.Bean#dictionary()} 553 * <li class='ja'>{@link org.apache.juneau.annotation.Beanp#dictionary()} 554 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#dictionary()} 555 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#dictionary_replace()} 556 * <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#beanDictionary(ClassInfo...)} 557 * </ul> 558 * 559 * @param values 560 * The values to add to this setting. 561 * <br>Cannot contain <jk>null</jk> values. 562 * @return This object. 563 */ 564 public Builder beanDictionary(ClassInfo...values) { 565 assertArgNoNulls("values", values); 566 return beanDictionary(l(values)); 567 } 568 569 /** 570 * Same as {@link #beanDictionary(ClassInfo...)} but allows you to pass in a collection of class info objects. 571 * 572 * @param values 573 * The values to add to this setting. 574 * <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values. 575 * @return This object. 576 * @see #beanDictionary(ClassInfo...) 577 */ 578 public Builder beanDictionary(Collection<ClassInfo> values) { 579 assertArgNoNulls("values", values); 580 beanDictionary().addAll(0, values); 581 return this; 582 } 583 584 /** 585 * Minimum bean field visibility. 586 * 587 * <p> 588 * Only look for bean fields with the specified minimum visibility. 589 * 590 * <p> 591 * This affects which fields on a bean class are considered bean properties. Normally only <jk>public</jk> fields are considered. 592 * Use this setting if you want to reduce the visibility requirement. 593 * 594 * <h5 class='section'>Example:</h5> 595 * <p class='bjava'> 596 * <jc>// A bean with a protected field.</jc> 597 * <jk>public class</jk> MyBean { 598 * <jk>protected</jk> String <jf>foo</jf> = <js>"bar"</js>; 599 * } 600 * 601 * <jc>// Create a serializer that recognizes the protected field.</jc> 602 * WriterSerializer <jv>serializer</jv> = JsonSerializer 603 * .<jsm>create</jsm>() 604 * .beanFieldVisibility(<jsf>PROTECTED</jsf>) 605 * .build(); 606 * 607 * <jc>// Produces: {"foo":"bar"}</jc> 608 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 609 * </p> 610 * 611 * <p> 612 * Bean fields can be ignored as properties entirely by setting the value to {@link Visibility#NONE} 613 * 614 * <p class='bjava'> 615 * <jc>// Disable using fields as properties entirely.</jc> 616 * WriterSerializer <jv>serializer</jv> = JsonSerializer 617 * .<jsm>create</jsm>() 618 * .beanFieldVisibility(<jsf>NONE</jsf>) 619 * .build(); 620 * </p> 621 * 622 * <h5 class='section'>Notes:</h5><ul> 623 * <li class='note'>The {@link Beanp @Beanp} annotation can also be used to expose a non-public field. 624 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean field to ignore it as a bean property. 625 * </ul> 626 * 627 * <h5 class='section'>See Also:</h5><ul> 628 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanFieldVisibility()} 629 * </ul> 630 * 631 * @param value 632 * The new value for this setting. 633 * <br>The default is {@link Visibility#PUBLIC}. 634 * <br>Cannot be <jk>null</jk>. 635 * @return This object. 636 */ 637 public Builder beanFieldVisibility(Visibility value) { 638 beanFieldVisibility = assertArgNotNull("value", value); 639 return this; 640 } 641 642 /** 643 * Bean interceptor. 644 * 645 * <p> 646 * Bean interceptors can be used to intercept calls to getters and setters and alter their values in transit. 647 * 648 * <h5 class='section'>Example:</h5> 649 * <p class='bjava'> 650 * <jc>// Interceptor that strips out sensitive information.</jc> 651 * <jk>public class</jk> AddressInterceptor <jk>extends</jk> BeanInterceptor<Address> { 652 * 653 * <jk>public</jk> Object readProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) { 654 * <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>)) 655 * <jk>return</jk> <js>"redacted"</js>; 656 * <jk>return</jk> <jv>value</jv>; 657 * } 658 * 659 * <jk>public</jk> Object writeProperty(Address <jv>bean</jv>, String <jv>name</jv>, Object <jv>value</jv>) { 660 * <jk>if</jk> (<js>"taxInfo"</js>.equals(<jv>name</jv>) && <js>"redacted"</js>.equals(<jv>value</jv>)) 661 * <jk>return</jk> TaxInfoUtils.<jsm>lookup</jsm>(<jv>bean</jv>.getStreet(), <jv>bean</jv>.getCity(), <jv>bean</jv>.getState()); 662 * <jk>return</jk> <jv>value</jv>; 663 * } 664 * } 665 * 666 * <jc>// Our bean class.</jc> 667 * <jk>public class</jk> Address { 668 * <jk>public</jk> String getTaxInfo() {...} 669 * <jk>public void</jk> setTaxInfo(String <jv>value</jv>) {...} 670 * } 671 * 672 * <jc>// Register filter on serializer or parser.</jc> 673 * WriterSerializer <jv>serializer</jv> = JsonSerializer 674 * .<jsm>create</jsm>() 675 * .beanInterceptor(Address.<jk>class</jk>, AddressInterceptor.<jk>class</jk>) 676 * .build(); 677 * 678 * <jc>// Produces: {"taxInfo":"redacted"}</jc> 679 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> Address()); 680 * </p> 681 * 682 * <h5 class='section'>See Also:</h5><ul> 683 * <li class='jc'>{@link BeanInterceptor} 684 * <li class='ja'>{@link Bean#interceptor() Bean(interceptor)} 685 * </ul> 686 * 687 * @param on The bean that the filter applies to. 688 * <br>Cannot be <jk>null</jk>. 689 * @param value 690 * The new value for this setting. 691 * <br>Cannot be <jk>null</jk>. 692 * @return This object. 693 */ 694 public Builder beanInterceptor(Class<?> on, Class<? extends BeanInterceptor<?>> value) { 695 assertArgNotNull("on", on); 696 assertArgNotNull("value", value); 697 return annotations(BeanAnnotation.create(on).interceptor(value).build()); 698 } 699 700 /** 701 * BeanMap.put() returns old property value. 702 * 703 * <p> 704 * When enabled, then the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property 705 * values. Otherwise, it returns <jk>null</jk>. 706 * 707 * <p> 708 * Disabled by default because it introduces a slight performance penalty during serialization. 709 * 710 * <h5 class='section'>Example:</h5> 711 * <p class='bjava'> 712 * <jc>// Create a context that creates BeanMaps with normal put() behavior.</jc> 713 * BeanContext <jv>context</jv> = BeanContext 714 * .<jsm>create</jsm>() 715 * .beanMapPutReturnsOldValue() 716 * .build(); 717 * 718 * BeanMap<MyBean> <jv>myBeanMap</jv> = <jv>context</jv>.createSession().toBeanMap(<jk>new</jk> MyBean()); 719 * <jv>myBeanMap</jv>.put(<js>"foo"</js>, <js>"bar"</js>); 720 * Object <jv>oldValue</jv> = <jv>myBeanMap</jv>.put(<js>"foo"</js>, <js>"baz"</js>); <jc>// oldValue == "bar"</jc> 721 * </p> 722 * 723 * <h5 class='section'>See Also:</h5><ul> 724 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanMapPutReturnsOldValue()} 725 * </ul> 726 * 727 * @return This object. 728 */ 729 public Builder beanMapPutReturnsOldValue() { 730 return beanMapPutReturnsOldValue(true); 731 } 732 733 /** 734 * Same as {@link #beanMapPutReturnsOldValue()} but allows you to explicitly specify the value. 735 * 736 * @param value The value for this setting. 737 * @return This object. 738 */ 739 public Builder beanMapPutReturnsOldValue(boolean value) { 740 beanMapPutReturnsOldValue = value; 741 return this; 742 } 743 744 /** 745 * Minimum bean method visibility. 746 * 747 * <p> 748 * Only look for bean methods with the specified minimum visibility. 749 * 750 * <p> 751 * This affects which methods are detected as getters and setters on a bean class. Normally only <jk>public</jk> getters and setters are considered. 752 * Use this setting if you want to reduce the visibility requirement. 753 * 754 * <h5 class='section'>Example:</h5> 755 * <p class='bjava'> 756 * <jc>// A bean with a protected getter.</jc> 757 * <jk>public class</jk> MyBean { 758 * <jk>public</jk> String getFoo() { <jk>return</jk> <js>"foo"</js>; } 759 * <jk>protected</jk> String getBar() { <jk>return</jk> <js>"bar"</js>; } 760 * } 761 * 762 * <jc>// Create a serializer that looks for protected getters and setters.</jc> 763 * WriterSerializer <jv>serializer</jv> = JsonSerializer 764 * .<jsm>create</jsm>() 765 * .beanMethodVisibility(<jsf>PROTECTED</jsf>) 766 * .build(); 767 * 768 * <jc>// Produces: {"foo":"foo","bar":"bar"}</jc> 769 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 770 * </p> 771 * 772 * <h5 class='section'>Notes:</h5><ul> 773 * <li class='note'>The {@link Beanp @Beanp} annotation can also be used to expose a non-public method. 774 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean getter/setter to ignore it as a bean property. 775 * </ul> 776 * 777 * <h5 class='section'>See Also:</h5><ul> 778 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanMethodVisibility()} 779 * </ul> 780 * 781 * @param value 782 * The new value for this setting. 783 * <br>The default is {@link Visibility#PUBLIC} 784 * @return This object. 785 */ 786 public Builder beanMethodVisibility(Visibility value) { 787 beanMethodVisibility = assertArgNotNull("value", value); 788 return this; 789 } 790 791 /** 792 * Bean property includes. 793 * 794 * <p> 795 * Specifies the set and order of names of properties associated with the bean class. 796 * 797 * <p> 798 * For example, <c>beanProperties(MyBean.<jk>class</jk>, <js>"foo,bar"</js>)</c> means only serialize the <c>foo</c> and 799 * <c>bar</c> properties on the specified bean. Likewise, parsing will ignore any bean properties not specified 800 * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()} 801 * has been called. 802 * 803 * <p> 804 * This value is entirely optional if you simply want to expose all the getters and public fields on 805 * a class as bean properties. However, it's useful if you want certain getters to be ignored or you want the properties to be 806 * serialized in a particular order. Note that on IBM JREs, the property order is the same as the order in the source code, 807 * whereas on Oracle JREs, the order is entirely random. 808 * 809 * <p> 810 * Setting applies to specified class and all subclasses. 811 * 812 * <h5 class='section'>Example:</h5> 813 * <p class='bjava'> 814 * <jc>// A bean with 3 properties.</jc> 815 * <jk>public class</jk> MyBean { 816 * <jk>public</jk> String 817 * <jf>foo</jf> = <js>"foo"</js>, 818 * <jf>bar</jf> = <js>"bar"</js>, 819 * <jf>baz</jf> = <js>"baz"</js>; 820 * } 821 * 822 * <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc> 823 * WriterSerializer <jv>serializer</jv> = JsonSerializer 824 * .<jsm>create</jsm>() 825 * .beanProperties(MyBean.<jk>class</jk>, <js>"foo,bar"</js>) 826 * .build(); 827 * 828 * <jc>// Produces: {"foo":"foo","bar":"bar"}</jc> 829 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 830 * </p> 831 * 832 * <p> 833 * This method is functionally equivalent to the following code: 834 * <p class='bjava'> 835 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).properties(<jv>properties</jv>).build()); 836 * </p> 837 * 838 * <h5 class='section'>See Also:</h5><ul> 839 * <li class='jma'>{@link Bean#properties()}/{@link Bean#p()} - On an annotation on the bean class itself. 840 * </ul> 841 * 842 * @param beanClass The bean class. 843 * <br>Cannot be <jk>null</jk>. 844 * @param properties Comma-delimited list of property names. 845 * <br>Cannot be <jk>null</jk>. 846 * @return This object. 847 */ 848 public Builder beanProperties(Class<?> beanClass, String properties) { 849 assertArgNotNull("beanClass", beanClass); 850 assertArgNotNull("properties", properties); 851 return annotations(BeanAnnotation.create(beanClass).p(properties).build()); 852 } 853 854 /** 855 * Bean property includes. 856 * 857 * <p> 858 * Specifies the set and order of names of properties associated with bean classes. 859 * 860 * <p> 861 * For example, <c>beanProperties(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"foo,bar"</js>))</c> means only serialize the <c>foo</c> and 862 * <c>bar</c> properties on the specified bean. Likewise, parsing will ignore any bean properties not specified 863 * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()} 864 * has been called. 865 * 866 * <p> 867 * This value is entirely optional if you simply want to expose all the getters and public fields on 868 * a class as bean properties. However, it's useful if you want certain getters to be ignored or you want the properties to be 869 * serialized in a particular order. Note that on IBM JREs, the property order is the same as the order in the source code, 870 * whereas on Oracle JREs, the order is entirely random. 871 * 872 * <p> 873 * Setting applies to specified class and all subclasses. 874 * 875 * <h5 class='section'>Example:</h5> 876 * <p class='bjava'> 877 * <jc>// A bean with 3 properties.</jc> 878 * <jk>public class</jk> MyBean { 879 * <jk>public</jk> String 880 * <jf>foo</jf> = <js>"foo"</js>, 881 * <jf>bar</jf> = <js>"bar"</js>, 882 * <jf>baz</jf> = <js>"baz"</js>; 883 * } 884 * 885 * <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc> 886 * WriterSerializer <jv>serializer</jv> = JsonSerializer 887 * .<jsm>create</jsm>() 888 * .beanProperties(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"foo,bar"</js>)) 889 * .build(); 890 * 891 * <jc>// Produces: {"foo":"foo","bar":"bar"}</jc> 892 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 893 * </p> 894 * 895 * <p> 896 * This method is functionally equivalent to the following code for each entry: 897 * <p class='bjava'> 898 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>key</jv>).properties(<jv>value</jv>.toString()).build()); 899 * </p> 900 * 901 * <h5 class='section'>See Also:</h5><ul> 902 * <li class='jma'>{@link Bean#properties()} / {@link Bean#p()}- On an annotation on the bean class itself. 903 * </ul> 904 * 905 * @param values 906 * The values to add to this builder. 907 * <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans. 908 * <br>Values are comma-delimited lists of property names. Non-String objects are first converted to Strings. 909 * <br>Cannot be <jk>null</jk>. 910 * @return This object. 911 */ 912 public Builder beanProperties(Map<String,Object> values) { 913 assertArgNotNull("values", values); 914 values.forEach((k, v) -> annotations(BeanAnnotation.create(k).p(s(v)).build())); 915 return this; 916 } 917 918 /** 919 * Bean property includes. 920 * 921 * <p> 922 * Specifies the set and order of names of properties associated with the bean class. 923 * 924 * <p> 925 * For example, <c>beanProperties(<js>"MyBean"</js>, <js>"foo,bar"</js>)</c> means only serialize the <c>foo</c> and 926 * <c>bar</c> properties on the specified bean. Likewise, parsing will ignore any bean properties not specified 927 * and either throw an exception or silently ignore them depending on whether {@link #ignoreUnknownBeanProperties()} 928 * has been called. 929 * 930 * <p> 931 * This value is entirely optional if you simply want to expose all the getters and public fields on 932 * a class as bean properties. However, it's useful if you want certain getters to be ignored or you want the properties to be 933 * serialized in a particular order. Note that on IBM JREs, the property order is the same as the order in the source code, 934 * whereas on Oracle JREs, the order is entirely random. 935 * 936 * <p> 937 * Setting applies to specified class and all subclasses. 938 * 939 * <h5 class='section'>Example:</h5> 940 * <p class='bjava'> 941 * <jc>// A bean with 3 properties.</jc> 942 * <jk>public class</jk> MyBean { 943 * <jk>public</jk> String 944 * <jf>foo</jf> = <js>"foo"</js>, 945 * <jf>bar</jf> = <js>"bar"</js>, 946 * <jf>baz</jf> = <js>"baz"</js>; 947 * } 948 * 949 * <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc> 950 * WriterSerializer <jv>serializer</jv> = JsonSerializer 951 * .<jsm>create</jsm>() 952 * .beanProperties(<js>"MyBean"</js>, <js>"foo,bar"</js>) 953 * .build(); 954 * 955 * <jc>// Produces: {"foo":"foo","bar":"bar"}</jc> 956 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 957 * </p> 958 * 959 * <p> 960 * This method is functionally equivalent to the following code: 961 * <p class='bjava'> 962 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).properties(<jv>properties</jv>).build()); 963 * </p> 964 * 965 * <h5 class='section'>See Also:</h5><ul> 966 * <li class='jma'>{@link Bean#properties()} / {@link Bean#p()} - On an annotation on the bean class itself. 967 * </ul> 968 * 969 * @param beanClassName 970 * The bean class name. 971 * <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all beans. 972 * @param properties Comma-delimited list of property names. 973 * <br>Cannot be <jk>null</jk>. 974 * @return This object. 975 */ 976 public Builder beanProperties(String beanClassName, String properties) { 977 assertArgNotNull("beanClassName", beanClassName); 978 assertArgNotNull("properties", properties); 979 return annotations(BeanAnnotation.create(beanClassName).p(properties).build()); 980 } 981 982 /** 983 * Bean property excludes. 984 * 985 * <p> 986 * Specifies to exclude the specified list of properties for the specified bean class. 987 * 988 * <p> 989 * Same as {@link #beanProperties(Class, String)} except you specify a list of bean property names that you want to exclude from 990 * serialization. 991 * 992 * <p> 993 * Setting applies to specified class and all subclasses. 994 * 995 * <h5 class='section'>Example:</h5> 996 * <p class='bjava'> 997 * <jc>// A bean with 3 properties.</jc> 998 * <jk>public class</jk> MyBean { 999 * <jk>public</jk> String 1000 * <jf>foo</jf> = <js>"foo"</js>, 1001 * <jf>bar</jf> = <js>"bar"</js>, 1002 * <jf>baz</jf> = <js>"baz"</js>; 1003 * } 1004 * 1005 * <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc> 1006 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1007 * .<jsm>create</jsm>() 1008 * .beanPropertiesExcludes(MyBean.<jk>class</jk>, <js>"bar,baz"</js>) 1009 * .build(); 1010 * 1011 * <jc>// Produces: {"foo":"foo"}</jc> 1012 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1013 * </p> 1014 * 1015 * <p> 1016 * This method is functionally equivalent to the following code: 1017 * <p class='bjava'> 1018 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).excludeProperties(<jv>properties</jv>).build()); 1019 * </p> 1020 * 1021 * <h5 class='section'>See Also:</h5><ul> 1022 * <li class='jma'>{@link Bean#excludeProperties()} / {@link Bean#xp()} 1023 * </ul> 1024 * 1025 * @param beanClass The bean class. 1026 * <br>Cannot be <jk>null</jk>. 1027 * @param properties Comma-delimited list of property names. 1028 * <br>Cannot be <jk>null</jk>. 1029 * @return This object. 1030 */ 1031 public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) { 1032 assertArgNotNull("beanClass", beanClass); 1033 assertArgNotNull("properties", properties); 1034 return annotations(BeanAnnotation.create(beanClass).xp(properties).build()); 1035 } 1036 1037 /** 1038 * Bean property excludes. 1039 * 1040 * <p> 1041 * Specifies to exclude the specified list of properties for the specified bean classes. 1042 * 1043 * <p> 1044 * Same as {@link #beanProperties(Map)} except you specify a list of bean property names that you want to exclude from 1045 * serialization. 1046 * 1047 * <p> 1048 * Setting applies to specified class and all subclasses. 1049 * 1050 * <h5 class='section'>Example:</h5> 1051 * <p class='bjava'> 1052 * <jc>// A bean with 3 properties.</jc> 1053 * <jk>public class</jk> MyBean { 1054 * <jk>public</jk> String 1055 * <jf>foo</jf> = <js>"foo"</js>, 1056 * <jf>bar</jf> = <js>"bar"</js>, 1057 * <jf>baz</jf> = <js>"baz"</js>; 1058 * } 1059 * 1060 * <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc> 1061 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1062 * .<jsm>create</jsm>() 1063 * .beanPropertiesExcludes(AMap.of(<js>"MyBean"</js>, <js>"bar,baz"</js>)) 1064 * .build(); 1065 * 1066 * <jc>// Produces: {"foo":"foo"}</jc> 1067 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1068 * </p> 1069 * 1070 * <p> 1071 * This method is functionally equivalent to the following code for each entry: 1072 * <p class='bjava'> 1073 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>key</jv>).excludeProperties(<jv>value</jv>.toString()).build()); 1074 * </p> 1075 * 1076 * <h5 class='section'>See Also:</h5><ul> 1077 * <li class='jma'>{@link Bean#excludeProperties()} / {@link Bean#xp()} 1078 * </ul> 1079 * 1080 * @param values 1081 * The values to add to this builder. 1082 * <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans. 1083 * <br>Values are comma-delimited lists of property names. Non-String objects are first converted to Strings. 1084 * <br>Cannot be <jk>null</jk>. 1085 * @return This object. 1086 */ 1087 public Builder beanPropertiesExcludes(Map<String,Object> values) { 1088 assertArgNotNull("values", values); 1089 values.forEach((k, v) -> annotations(BeanAnnotation.create(k).xp(s(v)).build())); 1090 return this; 1091 } 1092 1093 /** 1094 * Bean property excludes. 1095 * 1096 * <p> 1097 * Specifies to exclude the specified list of properties for the specified bean class. 1098 * 1099 * <p> 1100 * Same as {@link #beanPropertiesExcludes(String, String)} except you specify a list of bean property names that you want to exclude from 1101 * serialization. 1102 * 1103 * <p> 1104 * Setting applies to specified class and all subclasses. 1105 * 1106 * <h5 class='section'>Example:</h5> 1107 * <p class='bjava'> 1108 * <jc>// A bean with 3 properties.</jc> 1109 * <jk>public class</jk> MyBean { 1110 * <jk>public</jk> String 1111 * <jf>foo</jf> = <js>"foo"</js>, 1112 * <jf>bar</jf> = <js>"bar"</js>, 1113 * <jf>baz</jf> = <js>"baz"</js>; 1114 * } 1115 * 1116 * <jc>// Create a serializer that excludes the "bar" and "baz" properties on the MyBean class.</jc> 1117 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1118 * .<jsm>create</jsm>() 1119 * .beanPropertiesExcludes(<js>"MyBean"</js>, <js>"bar,baz"</js>) 1120 * .build(); 1121 * 1122 * <jc>// Produces: {"foo":"foo"}</jc> 1123 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1124 * </p> 1125 * 1126 * <p> 1127 * This method is functionally equivalent to the following code: 1128 * <p class='bjava'> 1129 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).excludeProperties(<jv>properties</jv>).build()); 1130 * </p> 1131 * 1132 * <h5 class='section'>See Also:</h5><ul> 1133 * <li class='jma'>{@link Bean#excludeProperties()} / {@link Bean#xp()} 1134 * </ul> 1135 * 1136 * @param beanClassName 1137 * The bean class name. 1138 * <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes. 1139 * <br>Cannot be <jk>null</jk>. 1140 * @param properties Comma-delimited list of property names. 1141 * <br>Cannot be <jk>null</jk>. 1142 * @return This object. 1143 */ 1144 public Builder beanPropertiesExcludes(String beanClassName, String properties) { 1145 assertArgNotNull("beanClassName", beanClassName); 1146 assertArgNotNull("properties", properties); 1147 return annotations(BeanAnnotation.create(beanClassName).xp(properties).build()); 1148 } 1149 1150 /** 1151 * Read-only bean properties. 1152 * 1153 * <p> 1154 * Specifies one or more properties on a bean that are read-only despite having valid getters. 1155 * Serializers will serialize such properties as usual, but parsers will silently ignore them. 1156 * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties 1157 * for both serializers and parsers. 1158 * 1159 * <h5 class='section'>Example:</h5> 1160 * <p class='bjava'> 1161 * <jc>// A bean with 3 properties.</jc> 1162 * <jk>public class</jk> MyBean { 1163 * <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>; 1164 * } 1165 * 1166 * <jc>// Create a serializer with read-only property settings.</jc> 1167 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1168 * .<jsm>create</jsm>() 1169 * .beanPropertiesReadOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>) 1170 * .build(); 1171 * 1172 * <jc>// All 3 properties will be serialized.</jc> 1173 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1174 * 1175 * <jc>// Create a parser with read-only property settings.</jc> 1176 * ReaderParser <jv>parser</jv> = JsonParser 1177 * .<jsm>create</jsm>() 1178 * .beanPropertiesReadOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>) 1179 * .ignoreUnknownBeanProperties() 1180 * .build(); 1181 * 1182 * <jc>// Parser ignores bar and baz properties.</jc> 1183 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>); 1184 * </p> 1185 * 1186 * <p> 1187 * This method is functionally equivalent to the following code: 1188 * <p class='bjava'> 1189 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).readOnlyProperties(<jv>properties</jv>).build()); 1190 * </p> 1191 * 1192 * <h5 class='section'>See Also:</h5><ul> 1193 * <li class='jma'>{@link Bean#readOnlyProperties()} / {@link Bean#ro()} 1194 * </ul> 1195 * 1196 * @param beanClass The bean class. 1197 * <br>Cannot be <jk>null</jk>. 1198 * @param properties Comma-delimited list of property names. 1199 * <br>Cannot be <jk>null</jk>. 1200 * @return This object. 1201 */ 1202 public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) { 1203 assertArgNotNull("beanClass", beanClass); 1204 assertArgNotNull("properties", properties); 1205 return annotations(BeanAnnotation.create(beanClass).ro(properties).build()); 1206 } 1207 1208 /** 1209 * Read-only bean properties. 1210 * 1211 * <p> 1212 * Specifies one or more properties on beans that are read-only despite having valid getters. 1213 * Serializers will serialize such properties as usual, but parsers will silently ignore them. 1214 * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties 1215 * for both serializers and parsers. 1216 * 1217 * <h5 class='section'>Example:</h5> 1218 * <p class='bjava'> 1219 * <jc>// A bean with 3 properties.</jc> 1220 * <jk>public class</jk> MyBean { 1221 * <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>; 1222 * } 1223 * 1224 * <jc>// Create a serializer with read-only property settings.</jc> 1225 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1226 * .<jsm>create</jsm>() 1227 * .beanPropertiesReadOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>)) 1228 * .build(); 1229 * 1230 * <jc>// All 3 properties will be serialized.</jc> 1231 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1232 * 1233 * <jc>// Create a parser with read-only property settings.</jc> 1234 * ReaderParser <jv>parser</jv> = JsonParser 1235 * .<jsm>create</jsm>() 1236 * .beanPropertiesReadOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>)) 1237 * .ignoreUnknownBeanProperties() 1238 * .build(); 1239 * 1240 * <jc>// Parser ignores bar and baz properties.</jc> 1241 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>); 1242 * </p> 1243 * 1244 * <p> 1245 * This method is functionally equivalent to the following code for each entry: 1246 * <p class='bjava'> 1247 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>key</jv>).readOnlyProperties(<jv>value</jv>.toString()).build()); 1248 * </p> 1249 * 1250 * <h5 class='section'>See Also:</h5><ul> 1251 * <li class='jma'>{@link Bean#readOnlyProperties()} / {@link Bean#ro()} 1252 * </ul> 1253 * 1254 * @param values 1255 * The values to add to this builder. 1256 * <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans. 1257 * <br>Values are comma-delimited lists of property names. Non-String objects are first converted to Strings. 1258 * <br>Cannot be <jk>null</jk>. 1259 * @return This object. 1260 */ 1261 public Builder beanPropertiesReadOnly(Map<String,Object> values) { 1262 assertArgNotNull("values", values); 1263 values.forEach((k, v) -> annotations(BeanAnnotation.create(k).ro(s(v)).build())); 1264 return this; 1265 } 1266 1267 /** 1268 * Read-only bean properties. 1269 * 1270 * <p> 1271 * Specifies one or more properties on a bean that are read-only despite having valid getters. 1272 * Serializers will serialize such properties as usual, but parsers will silently ignore them. 1273 * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties 1274 * for both serializers and parsers. 1275 * 1276 * <h5 class='section'>Example:</h5> 1277 * <p class='bjava'> 1278 * <jc>// A bean with 3 properties.</jc> 1279 * <jk>public class</jk> MyBean { 1280 * <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>; 1281 * } 1282 * 1283 * <jc>// Create a serializer with read-only property settings.</jc> 1284 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1285 * .<jsm>create</jsm>() 1286 * .beanPropertiesReadOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>) 1287 * .build(); 1288 * 1289 * <jc>// All 3 properties will be serialized.</jc> 1290 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1291 * 1292 * <jc>// Create a parser with read-only property settings.</jc> 1293 * ReaderParser <jv>parser</jv> = JsonParser 1294 * .<jsm>create</jsm>() 1295 * .beanPropertiesReadOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>) 1296 * .ignoreUnknownBeanProperties() 1297 * .build(); 1298 * 1299 * <jc>// Parser ignores bar and baz properties.</jc> 1300 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>); 1301 * </p> 1302 * 1303 * <p> 1304 * This method is functionally equivalent to the following code: 1305 * <p class='bjava'> 1306 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).readOnlyProperties(<jv>properties</jv>).build()); 1307 * </p> 1308 * 1309 * <h5 class='section'>See Also:</h5><ul> 1310 * <li class='jma'>{@link Bean#readOnlyProperties()} / {@link Bean#ro()} 1311 * </ul> 1312 * 1313 * @param beanClassName 1314 * The bean class name. 1315 * <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes. 1316 * @param properties Comma-delimited list of property names. 1317 * @return This object. 1318 */ 1319 public Builder beanPropertiesReadOnly(String beanClassName, String properties) { 1320 assertArgNotNull("beanClassName", beanClassName); 1321 assertArgNotNull("properties", properties); 1322 return annotations(BeanAnnotation.create(beanClassName).ro(properties).build()); 1323 } 1324 1325 /** 1326 * Write-only bean properties. 1327 * 1328 * <p> 1329 * Specifies one or more properties on a bean that are write-only despite having valid setters. 1330 * Parsers will parse such properties as usual, but serializers will silently ignore them. 1331 * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties 1332 * for both serializers and parsers. 1333 * 1334 * <h5 class='section'>Example:</h5> 1335 * <p class='bjava'> 1336 * <jc>// A bean with 3 properties.</jc> 1337 * <jk>public class</jk> MyBean { 1338 * <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>; 1339 * } 1340 * 1341 * <jc>// Create a serializer with write-only property settings.</jc> 1342 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1343 * .<jsm>create</jsm>() 1344 * .beanPropertiesWriteOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>) 1345 * .build(); 1346 * 1347 * <jc>// Only foo will be serialized.</jc> 1348 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1349 * 1350 * <jc>// Create a parser with write-only property settings.</jc> 1351 * ReaderParser <jv>parser</jv> = JsonParser 1352 * .<jsm>create</jsm>() 1353 * .beanPropertiesWriteOnly(MyBean.<jk>class</jk>, <js>"bar,baz"</js>) 1354 * .build(); 1355 * 1356 * <jc>// Parser parses all 3 properties.</jc> 1357 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>); 1358 * </p> 1359 * 1360 * <p> 1361 * This method is functionally equivalent to the following code: 1362 * <p class='bjava'> 1363 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClass</jv>).writeOnlyProperties(<jv>properties</jv>).build()); 1364 * </p> 1365 * 1366 * <h5 class='section'>See Also:</h5><ul> 1367 * <li class='jma'>{@link Bean#writeOnlyProperties()} / {@link Bean#wo()} 1368 * </ul> 1369 * 1370 * @param beanClass The bean class. 1371 * <br>Cannot be <jk>null</jk>. 1372 * @param properties Comma-delimited list of property names. 1373 * <br>Cannot be <jk>null</jk>. 1374 * @return This object. 1375 */ 1376 public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) { 1377 assertArgNotNull("beanClass", beanClass); 1378 assertArgNotNull("properties", properties); 1379 return annotations(BeanAnnotation.create(beanClass).wo(properties).build()); 1380 } 1381 1382 /** 1383 * Write-only bean properties. 1384 * 1385 * <p> 1386 * Specifies one or more properties on a bean that are write-only despite having valid setters. 1387 * Parsers will parse such properties as usual, but serializers will silently ignore them. 1388 * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties 1389 * for both serializers and parsers. 1390 * 1391 * <h5 class='section'>Example:</h5> 1392 * <p class='bjava'> 1393 * <jc>// A bean with 3 properties.</jc> 1394 * <jk>public class</jk> MyBean { 1395 * <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>; 1396 * } 1397 * 1398 * <jc>// Create a serializer with write-only property settings.</jc> 1399 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1400 * .<jsm>create</jsm>() 1401 * .beanPropertiesWriteOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>)) 1402 * .build(); 1403 * 1404 * <jc>// Only foo will be serialized.</jc> 1405 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1406 * 1407 * <jc>// Create a parser with write-only property settings.</jc> 1408 * ReaderParser <jv>parser</jv> = JsonParser 1409 * .<jsm>create</jsm>() 1410 * .beanPropertiesWriteOnly(AMap.<jsm>of</jsm>(<js>"MyBean"</js>, <js>"bar,baz"</js>)) 1411 * .build(); 1412 * 1413 * <jc>// Parser parses all 3 properties.</jc> 1414 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>); 1415 * </p> 1416 * 1417 * <p> 1418 * This method is functionally equivalent to the following code for each entry: 1419 * <p class='bjava'> 1420 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>key</jv>).writeOnlyProperties(<jv>value</jv>.toString()).build()); 1421 * </p> 1422 * 1423 * <h5 class='section'>See Also:</h5><ul> 1424 * <li class='jma'>{@link Bean#writeOnlyProperties()} / {@link Bean#wo()} 1425 * </ul> 1426 * 1427 * @param values 1428 * The values to add to this builder. 1429 * <br>Keys are bean class names which can be a simple name, fully-qualified name, or <js>"*"</js> for all beans. 1430 * <br>Values are comma-delimited lists of property names. Non-String objects are first converted to Strings. 1431 * <br>Cannot be <jk>null</jk>. 1432 * @return This object. 1433 */ 1434 public Builder beanPropertiesWriteOnly(Map<String,Object> values) { 1435 assertArgNotNull("values", values); 1436 values.forEach((k, v) -> annotations(BeanAnnotation.create(k).wo(s(v)).build())); 1437 return this; 1438 } 1439 1440 /** 1441 * Write-only bean properties. 1442 * 1443 * <p> 1444 * Specifies one or more properties on a bean that are write-only despite having valid setters. 1445 * Parsers will parse such properties as usual, but serializers will silently ignore them. 1446 * Note that this is different from the {@link #beanProperties(Class,String) beanProperties}/{@link #beanPropertiesExcludes(Class,String) beanPropertiesExcludes} settings which include or exclude properties 1447 * for both serializers and parsers. 1448 * 1449 * <h5 class='section'>Example:</h5> 1450 * <p class='bjava'> 1451 * <jc>// A bean with 3 properties.</jc> 1452 * <jk>public class</jk> MyBean { 1453 * <jk>public</jk> String <jf>foo</jf>, <jf>bar</jf>, <jf>baz</jf>; 1454 * } 1455 * 1456 * <jc>// Create a serializer with write-only property settings.</jc> 1457 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1458 * .<jsm>create</jsm>() 1459 * .beanPropertiesWriteOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>) 1460 * .build(); 1461 * 1462 * <jc>// Only foo will be serialized.</jc> 1463 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1464 * 1465 * <jc>// Create a parser with write-only property settings.</jc> 1466 * ReaderParser <jv>parser</jv> = JsonParser 1467 * .<jsm>create</jsm>() 1468 * .beanPropertiesWriteOnly(<js>"MyBean"</js>, <js>"bar,baz"</js>) 1469 * .build(); 1470 * 1471 * <jc>// Parser parses all 3 properties.</jc> 1472 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar',baz:'baz'}"</js>, MyBean.<jk>class</jk>); 1473 * </p> 1474 * 1475 * <p> 1476 * This method is functionally equivalent to the following code: 1477 * <p class='bjava'> 1478 * <jv>builder</jv>.annotations(BeanAnnotation.<jsm>create</jsm>(<jv>beanClassName</jv>).writeOnlyProperties(<jv>properties</jv>).build()); 1479 * </p> 1480 * 1481 * <h5 class='section'>See Also:</h5><ul> 1482 * <li class='jma'>{@link Bean#writeOnlyProperties()} / {@link Bean#wo()} 1483 * </ul> 1484 * 1485 * @param beanClassName 1486 * The bean class name. 1487 * <br>Can be a simple name, fully-qualified name, or <js>"*"</js> for all bean classes. 1488 * @param properties Comma-delimited list of property names. 1489 * @return This object. 1490 */ 1491 public Builder beanPropertiesWriteOnly(String beanClassName, String properties) { 1492 assertArgNotNull("beanClassName", beanClassName); 1493 assertArgNotNull("properties", properties); 1494 return annotations(BeanAnnotation.create(beanClassName).wo(properties).build()); 1495 } 1496 1497 /** 1498 * Beans require no-arg constructors. 1499 * 1500 * <p> 1501 * When enabled, a Java class must implement a default no-arg constructor to be considered a bean. 1502 * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 1503 * 1504 * <h5 class='section'>Example:</h5> 1505 * <p class='bjava'> 1506 * <jc>// A bean without a no-arg constructor.</jc> 1507 * <jk>public class</jk> MyBean { 1508 * 1509 * <jc>// A property method.</jc> 1510 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 1511 * 1512 * <jc>// A no-arg constructor</jc> 1513 * <jk>public</jk> MyBean(String <jv>foo</jv>) { 1514 * <jk>this</jk>.<jf>foo</jf> = <jv>foo</jv>; 1515 * } 1516 * 1517 * <ja>@Override</ja> 1518 * <jk>public</jk> String toString() { 1519 * <jk>return</jk> <js>"bar"</js>; 1520 * } 1521 * } 1522 * 1523 * <jc>// Create a serializer that ignores beans without default constructors.</jc> 1524 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1525 * .<jsm>create</jsm>() 1526 * .beansRequireDefaultConstructor() 1527 * .build(); 1528 * 1529 * <jc>// Produces: "bar"</jc> 1530 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1531 * </p> 1532 * 1533 * <h5 class='section'>Notes:</h5><ul> 1534 * <li class='note'>The {@link Bean @Bean} annotation can be used on a bean class to override this setting. 1535 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a class to ignore it as a bean. 1536 * </ul> 1537 * 1538 * <h5 class='section'>See Also:</h5><ul> 1539 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beansRequireDefaultConstructor()} 1540 * </ul> 1541 * 1542 * @return This object. 1543 */ 1544 public Builder beansRequireDefaultConstructor() { 1545 return beansRequireDefaultConstructor(true); 1546 } 1547 1548 /** 1549 * Same as {@link #beansRequireDefaultConstructor()} but allows you to explicitly specify the value. 1550 * 1551 * @param value The value for this setting. 1552 * @return This object. 1553 */ 1554 public Builder beansRequireDefaultConstructor(boolean value) { 1555 beansRequireDefaultConstructor = value; 1556 return this; 1557 } 1558 1559 /** 1560 * Beans require Serializable interface. 1561 * 1562 * <p> 1563 * When enabled, a Java class must implement the {@link Serializable} interface to be considered a bean. 1564 * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 1565 * 1566 * <h5 class='section'>Example:</h5> 1567 * <p class='bjava'> 1568 * <jc>// A bean without a Serializable interface.</jc> 1569 * <jk>public class</jk> MyBean { 1570 * 1571 * <jc>// A property method.</jc> 1572 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 1573 * 1574 * <ja>@Override</ja> 1575 * <jk>public</jk> String toString() { 1576 * <jk>return</jk> <js>"bar"</js>; 1577 * } 1578 * } 1579 * 1580 * <jc>// Create a serializer that ignores beans not implementing Serializable.</jc> 1581 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1582 * .<jsm>create</jsm>() 1583 * .beansRequireSerializable() 1584 * .build(); 1585 * 1586 * <jc>// Produces: "bar"</jc> 1587 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1588 * </p> 1589 * 1590 * <h5 class='section'>Notes:</h5><ul> 1591 * <li class='note'>The {@link Bean @Bean} annotation can be used on a bean class to override this setting. 1592 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a class to ignore it as a bean. 1593 * </ul> 1594 * 1595 * <h5 class='section'>See Also:</h5><ul> 1596 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beansRequireSerializable()} 1597 * </ul> 1598 * 1599 * @return This object. 1600 */ 1601 public Builder beansRequireSerializable() { 1602 return beansRequireSerializable(true); 1603 } 1604 1605 /** 1606 * Same as {@link #beansRequireSerializable()} but allows you to explicitly specify the value. 1607 * 1608 * @param value The value for this setting. 1609 * @return This object. 1610 */ 1611 public Builder beansRequireSerializable(boolean value) { 1612 beansRequireSerializable = value; 1613 return this; 1614 } 1615 1616 /** 1617 * Beans require setters for getters. 1618 * 1619 * <p> 1620 * When enabled, ignore read-only properties (properties with getters but not setters). 1621 * 1622 * <h5 class='section'>Example:</h5> 1623 * <p class='bjava'> 1624 * <jc>// A bean without a Serializable interface.</jc> 1625 * <jk>public class</jk> MyBean { 1626 * 1627 * <jc>// A read/write property.</jc> 1628 * <jk>public</jk> String getFoo() { <jk>return</jk> <js>"foo"</js>; } 1629 * <jk>public void</jk> setFoo(String <jv>foo</jv>) { ... } 1630 * 1631 * <jc>// A read-only property.</jc> 1632 * <jk>public</jk> String getBar() { <jk>return</jk> <js>"bar"</js>; } 1633 * } 1634 * 1635 * <jc>// Create a serializer that ignores bean properties without setters.</jc> 1636 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1637 * .<jsm>create</jsm>() 1638 * .beansRequireSettersForGetters() 1639 * .build(); 1640 * 1641 * <jc>// Produces: {"foo":"foo"}</jc> 1642 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1643 * </p> 1644 * 1645 * <h5 class='section'>Notes:</h5><ul> 1646 * <li class='note'>The {@link Beanp @Beanp} annotation can be used on the getter to override this setting. 1647 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on getters to ignore them as bean properties. 1648 * </ul> 1649 * 1650 * @return This object. 1651 */ 1652 public Builder beansRequireSettersForGetters() { 1653 return beansRequireSettersForGetters(true); 1654 } 1655 1656 /** 1657 * Same as {@link #beansRequireSettersForGetters()} but allows you to explicitly specify the value. 1658 * 1659 * @param value The value for this setting. 1660 * @return This object. 1661 */ 1662 public Builder beansRequireSettersForGetters(boolean value) { 1663 beansRequireSettersForGetters = value; 1664 return this; 1665 } 1666 1667 @Override /* Overridden from Context.Builder */ 1668 public BeanContext build() { 1669 return cache(CACHE).build(BeanContext.class); 1670 } 1671 1672 @Override /* Overridden from Builder */ 1673 public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) { 1674 super.cache(value); 1675 return this; 1676 } 1677 1678 @Override /* Overridden from Context.Builder */ 1679 public Builder copy() { 1680 return new Builder(this); 1681 } 1682 1683 @Override /* Overridden from Builder */ 1684 public Builder debug() { 1685 super.debug(); 1686 return this; 1687 } 1688 1689 @Override /* Overridden from Builder */ 1690 public Builder debug(boolean value) { 1691 super.debug(value); 1692 return this; 1693 } 1694 1695 /** 1696 * Bean dictionary. 1697 * 1698 * <p> 1699 * This is identical to {@link #beanDictionary(Class...)}, but specifies a dictionary within the context of 1700 * a single class as opposed to globally. 1701 * 1702 * <h5 class='section'>Example:</h5> 1703 * <p class='bjava'> 1704 * <jc>// POJOs with @Bean(name) annotations.</jc> 1705 * <ja>@Bean</ja>(typeName=<js>"foo"</js>) 1706 * <jk>public class</jk> Foo {...} 1707 * <ja>@Bean</ja>(typeName=<js>"bar"</js>) 1708 * <jk>public class</jk> Bar {...} 1709 * 1710 * <jc>// A bean with a field with an indeterminate type.</jc> 1711 * <jk>public class</jk> MyBean { 1712 * <jk>public</jk> Object <jf>mySimpleField</jf>; 1713 * } 1714 * 1715 * <jc>// Create a parser and tell it which classes to try to resolve.</jc> 1716 * ReaderParser <jv>parser</jv> = JsonParser 1717 * .<jsm>create</jsm>() 1718 * .dictionaryOn(MyBean.<jk>class</jk>, Foo.<jk>class</jk>, Bar.<jk>class</jk>) 1719 * .build(); 1720 * 1721 * <jc>// Parse bean.</jc> 1722 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{mySimpleField:{_type:'foo',...}}"</js>, MyBean.<jk>class</jk>); 1723 * </p> 1724 * 1725 * <p> 1726 * This is functionally equivalent to the {@link Bean#dictionary()} annotation. 1727 * 1728 * <h5 class='section'>See Also:</h5><ul> 1729 * <li class='jma'>{@link Bean#dictionary()} 1730 * <li class='jm'>{@link #beanDictionary(Class...)} 1731 * </ul> 1732 * 1733 * @param on The class that the dictionary values apply to. 1734 * @param values 1735 * The new values for this setting. 1736 * @return This object. 1737 */ 1738 public Builder dictionaryOn(Class<?> on, Class<?>...values) { 1739 assertArgNotNull("on", on); 1740 assertArgNoNulls("values", values); 1741 return annotations(BeanAnnotation.create(on).dictionary(values).build()); 1742 } 1743 1744 /** 1745 * Beans don't require at least one property. 1746 * 1747 * <p> 1748 * When enabled, then a Java class doesn't need to contain at least 1 property to be considered a bean. 1749 * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 1750 * 1751 * <p> 1752 * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>. 1753 * 1754 * <h5 class='section'>Example:</h5> 1755 * <p class='bjava'> 1756 * <jc>// A bean with no properties.</jc> 1757 * <jk>public class</jk> MyBean { 1758 * } 1759 * 1760 * <jc>// Create a serializer that serializes beans even if they have zero properties.</jc> 1761 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1762 * .<jsm>create</jsm>() 1763 * .disableBeansRequireSomeProperties() 1764 * .build(); 1765 * 1766 * <jc>// Produces: {}</jc> 1767 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1768 * </p> 1769 * 1770 * <h5 class='section'>Notes:</h5><ul> 1771 * <li class='note'>The {@link Bean @Bean} annotation can be used on the class to force it to be recognized as a bean class 1772 * even if it has no properties. 1773 * </ul> 1774 * 1775 * <h5 class='section'>See Also:</h5><ul> 1776 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableBeansRequireSomeProperties()} 1777 * </ul> 1778 * 1779 * @return This object. 1780 */ 1781 public Builder disableBeansRequireSomeProperties() { 1782 return disableBeansRequireSomeProperties(true); 1783 } 1784 1785 /** 1786 * Same as {@link #disableBeansRequireSomeProperties()} but allows you to explicitly specify the value. 1787 * 1788 * @param value The value for this setting. 1789 * @return This object. 1790 */ 1791 public Builder disableBeansRequireSomeProperties(boolean value) { 1792 disableBeansRequireSomeProperties = value; 1793 return this; 1794 } 1795 1796 /** 1797 * Don't silently ignore missing setters. 1798 * 1799 * <p> 1800 * When enabled, trying to set a value on a bean property without a setter will throw a {@link BeanRuntimeException}. 1801 * Otherwise, it will be silently ignored. 1802 * 1803 * <h5 class='section'>Example:</h5> 1804 * <p class='bjava'> 1805 * <jc>// A bean with a property with a getter but not a setter.</jc> 1806 * <jk>public class</jk> MyBean { 1807 * <jk>public void</jk> getFoo() { 1808 * <jk>return</jk> <js>"foo"</js>; 1809 * } 1810 * } 1811 * 1812 * <jc>// Create a parser that throws an exception if a setter is not found but a getter is.</jc> 1813 * ReaderParser <jv>parser</jv> = JsonParser 1814 * .<jsm>create</jsm>() 1815 * .disableIgnoreMissingSetters() 1816 * .build(); 1817 * 1818 * <jc>// Throws a ParseException.</jc> 1819 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>); 1820 * </p> 1821 * 1822 * <h5 class='section'>Notes:</h5><ul> 1823 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on getters and fields to ignore them. 1824 * </ul> 1825 * 1826 * <h5 class='section'>See Also:</h5><ul> 1827 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableIgnoreMissingSetters()} 1828 * </ul> 1829 * 1830 * @return This object. 1831 */ 1832 public Builder disableIgnoreMissingSetters() { 1833 return disableIgnoreMissingSetters(true); 1834 } 1835 1836 /** 1837 * Same as {@link #disableIgnoreMissingSetters()} but allows you to explicitly specify the value. 1838 * 1839 * @param value The value for this setting. 1840 * @return This object. 1841 */ 1842 public Builder disableIgnoreMissingSetters(boolean value) { 1843 disableIgnoreMissingSetters = value; 1844 return this; 1845 } 1846 1847 /** 1848 * Don't ignore transient fields. 1849 * 1850 * <p> 1851 * When enabled, methods and fields marked as <jk>transient</jk> will not be ignored as bean properties. 1852 * 1853 * <h5 class='section'>Example:</h5> 1854 * <p class='bjava'> 1855 * <jc>// A bean with a transient field.</jc> 1856 * <jk>public class</jk> MyBean { 1857 * <jk>public transient</jk> String <jf>foo</jf> = <js>"foo"</js>; 1858 * } 1859 * 1860 * <jc>// Create a serializer that doesn't ignore transient fields.</jc> 1861 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1862 * .<jsm>create</jsm>() 1863 * .disableIgnoreTransientFields() 1864 * .build(); 1865 * 1866 * <jc>// Produces: {"foo":"foo"}</jc> 1867 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 1868 * </p> 1869 * 1870 * <h5 class='section'>Notes:</h5><ul> 1871 * <li class='note'>The {@link Beanp @Beanp} annotation can also be used on transient fields to keep them from being ignored. 1872 * </ul> 1873 * 1874 * <h5 class='section'>See Also:</h5><ul> 1875 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableIgnoreTransientFields()} 1876 * </ul> 1877 * 1878 * @return This object. 1879 */ 1880 public Builder disableIgnoreTransientFields() { 1881 return disableIgnoreTransientFields(true); 1882 } 1883 1884 /** 1885 * Same as {@link #disableIgnoreTransientFields()} but allows you to explicitly specify the value. 1886 * 1887 * @param value The value for this setting. 1888 * @return This object. 1889 */ 1890 public Builder disableIgnoreTransientFields(boolean value) { 1891 disableIgnoreTransientFields = value; 1892 return this; 1893 } 1894 1895 /** 1896 * Don't ignore unknown properties with null values. 1897 * 1898 * <p> 1899 * When enabled, trying to set a <jk>null</jk> value on a non-existent bean property will throw a {@link BeanRuntimeException}. 1900 * Otherwise it will be silently ignored. 1901 * 1902 * <h5 class='section'>Example:</h5> 1903 * <p class='bjava'> 1904 * <jc>// A bean with a single property.</jc> 1905 * <jk>public class</jk> MyBean { 1906 * <jk>public</jk> String <jf>foo</jf>; 1907 * } 1908 * 1909 * <jc>// Create a parser that throws an exception on an unknown property even if the value being set is null.</jc> 1910 * ReaderParser <jv>parser</jv> = JsonParser 1911 * .<jsm>create</jsm>() 1912 * .disableIgnoreUnknownNullBeanProperties() 1913 * .build(); 1914 * 1915 * <jc>// Throws a BeanRuntimeException wrapped in a ParseException on the unknown 'bar' property.</jc> 1916 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:null}"</js>, MyBean.<jk>class</jk>); 1917 * </p> 1918 * 1919 * <h5 class='section'>See Also:</h5><ul> 1920 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableIgnoreUnknownNullBeanProperties()} 1921 * </ul> 1922 * 1923 * @return This object. 1924 */ 1925 public Builder disableIgnoreUnknownNullBeanProperties() { 1926 return disableIgnoreUnknownNullBeanProperties(true); 1927 } 1928 1929 /** 1930 * Same as {@link #disableIgnoreUnknownNullBeanProperties()} but allows you to explicitly specify the value. 1931 * 1932 * @param value The value for this setting. 1933 * @return This object. 1934 */ 1935 public Builder disableIgnoreUnknownNullBeanProperties(boolean value) { 1936 disableIgnoreUnknownNullBeanProperties = value; 1937 return this; 1938 } 1939 1940 /** 1941 * Don't use interface proxies. 1942 * 1943 * <p> 1944 * When enabled, interfaces will be instantiated as proxy classes through the use of an 1945 * {@link InvocationHandler} if there is no other way of instantiating them. 1946 * Otherwise, throws a {@link BeanRuntimeException}. 1947 * 1948 * <h5 class='section'>See Also:</h5><ul> 1949 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#disableInterfaceProxies()} 1950 * </ul> 1951 * 1952 * @return This object. 1953 */ 1954 public Builder disableInterfaceProxies() { 1955 return disableInterfaceProxies(true); 1956 } 1957 1958 /** 1959 * Same as {@link #disableInterfaceProxies()} but allows you to explicitly specify the value. 1960 * 1961 * @param value The value for this setting. 1962 * @return This object. 1963 */ 1964 public Builder disableInterfaceProxies(boolean value) { 1965 disableInterfaceProxies = value; 1966 return this; 1967 } 1968 1969 /** 1970 * POJO example. 1971 * 1972 * <p> 1973 * Specifies an example in JSON of the specified class. 1974 * 1975 * <p> 1976 * Examples are used in cases such as POJO examples in Swagger documents. 1977 * 1978 * <p> 1979 * Setting applies to specified class and all subclasses. 1980 * 1981 * <h5 class='section'>Example:</h5> 1982 * <p class='bjava'> 1983 * <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc> 1984 * WriterSerializer <jv>serializer</jv> = JsonSerializer 1985 * .<jsm>create</jsm>() 1986 * .example(MyBean.<jk>class</jk>, <js>"{foo:'bar'}"</js>) 1987 * .build(); 1988 * </p> 1989 * 1990 * <p> 1991 * This is a shorthand method for the following code: 1992 * <p class='bjava'> 1993 * <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>pojoClass</jv>).example(<jv>json</jv>).build()) 1994 * </p> 1995 * 1996 * <p> 1997 * POJO examples can also be defined on classes via the following: 1998 * <ul class='spaced-list'> 1999 * <li>A static field annotated with {@link Example @Example}. 2000 * <li>A static method annotated with {@link Example @Example} with zero arguments or one {@link BeanSession} argument. 2001 * <li>A static method with name <c>example</c> with no arguments or one {@link BeanSession} argument. 2002 * </ul> 2003 * 2004 * <h5 class='section'>See Also:</h5><ul> 2005 * <li class='ja'>{@link Marshalled#example()} 2006 * </ul> 2007 * 2008 * @param <T> The POJO class type. 2009 * @param pojoClass The POJO class. 2010 * <br>Cannot be <jk>null</jk>. 2011 * @param json The JSON 5 representation of the example. 2012 * <br>Can be <jk>null</jk> or empty (treated as no example). 2013 * @return This object. 2014 */ 2015 public <T> Builder example(Class<T> pojoClass, String json) { 2016 return annotations(MarshalledAnnotation.create(assertArgNotNull("pojoClass", pojoClass)).example(json).build()); 2017 } 2018 2019 /** 2020 * POJO example. 2021 * 2022 * <p> 2023 * Specifies an example of the specified class. 2024 * 2025 * <p> 2026 * Examples are used in cases such as POJO examples in Swagger documents. 2027 * 2028 * <h5 class='section'>Example:</h5> 2029 * <p class='bjava'> 2030 * <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc> 2031 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2032 * .<jsm>create</jsm>() 2033 * .example(MyBean.<jk>class</jk>, <jk>new</jk> MyBean().setFoo(<js>"foo"</js>).setBar(123)) 2034 * .build(); 2035 * </p> 2036 * 2037 * <p> 2038 * This is a shorthand method for the following code: 2039 * <p class='bjava'> 2040 * <jv>builder</jv>.annotations(MarshalledAnnotation.<jsm>create</jsm>(<jv>pojoClass</jv>).example(Json5.<jsf>DEFAULT</jsf>.toString(<jv>object</jv>)).build()) 2041 * </p> 2042 * 2043 * <h5 class='section'>Notes:</h5><ul> 2044 * <li class='note'>Using this method assumes the serialized form of the object is the same as that produced 2045 * by the default serializer. This may not be true based on settings or swaps on the constructed serializer. 2046 * </ul> 2047 * 2048 * <p> 2049 * POJO examples can also be defined on classes via the following: 2050 * <ul class='spaced-list'> 2051 * <li>The {@link Marshalled#example()} annotation on the class itself. 2052 * <li>A static field annotated with {@link Example @Example}. 2053 * <li>A static method annotated with {@link Example @Example} with zero arguments or one {@link BeanSession} argument. 2054 * <li>A static method with name <c>example</c> with no arguments or one {@link BeanSession} argument. 2055 * </ul> 2056 * 2057 * @param <T> The POJO class. 2058 * @param pojoClass The POJO class. 2059 * <br>Cannot be <jk>null</jk>. 2060 * @param o 2061 * An instance of the POJO class used for examples. 2062 * <br>Can be <jk>null</jk> (will be serialized as <js>"null"</js>). 2063 * @return This object. 2064 */ 2065 public <T> Builder example(Class<T> pojoClass, T o) { 2066 return annotations(MarshalledAnnotation.create(assertArgNotNull("pojoClass", pojoClass)).example(Json5.of(o)).build()); 2067 } 2068 2069 /** 2070 * Find fluent setters. 2071 * 2072 * <p> 2073 * When enabled, fluent setters are detected on beans during parsing. 2074 * 2075 * <p> 2076 * Fluent setters must have the following attributes: 2077 * <ul> 2078 * <li>Public. 2079 * <li>Not static. 2080 * <li>Take in one parameter. 2081 * <li>Return the bean itself. 2082 * </ul> 2083 * 2084 * <h5 class='section'>Example:</h5> 2085 * <p class='bjava'> 2086 * <jc>// A bean with a fluent setter.</jc> 2087 * <jk>public class</jk> MyBean { 2088 * <jk>public</jk> MyBean foo(String <jv>value</jv>) {...} 2089 * } 2090 * 2091 * <jc>// Create a parser that finds fluent setters.</jc> 2092 * ReaderParser <jv>parser</jv> = JsonParser 2093 * .<jsm>create</jsm>() 2094 * .findFluentSetters() 2095 * .build(); 2096 * 2097 * <jc>// Parse into bean using fluent setter.</jc> 2098 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>); 2099 * </p> 2100 * 2101 * <h5 class='section'>Notes:</h5><ul> 2102 * <li class='note'>The {@link Beanp @Beanp} annotation can also be used on methods to individually identify them as fluent setters. 2103 * <li class='note'>The {@link Bean#findFluentSetters() @Bean.fluentSetters()} annotation can also be used on classes to specify to look for fluent setters. 2104 * </ul> 2105 * 2106 * <h5 class='section'>See Also:</h5><ul> 2107 * <li class='ja'>{@link org.apache.juneau.annotation.Bean#findFluentSetters()} 2108 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#findFluentSetters()} 2109 * </ul> 2110 * 2111 * @return This object. 2112 */ 2113 public Builder findFluentSetters() { 2114 return findFluentSetters(true); 2115 } 2116 2117 /** 2118 * Same as {@link #findFluentSetters()} but allows you to explicitly specify the value. 2119 * 2120 * @param value The value for this setting. 2121 * @return This object. 2122 */ 2123 public Builder findFluentSetters(boolean value) { 2124 findFluentSetters = value; 2125 return this; 2126 } 2127 2128 /** 2129 * Find fluent setters. 2130 * 2131 * <p> 2132 * Identical to {@link #findFluentSetters()} but enables it on a specific class only. 2133 * 2134 * <h5 class='section'>Example:</h5> 2135 * <p class='bjava'> 2136 * <jc>// A bean with a fluent setter.</jc> 2137 * <jk>public class</jk> MyBean { 2138 * <jk>public</jk> MyBean foo(String <jv>value</jv>) {...} 2139 * } 2140 * 2141 * <jc>// Create a parser that finds fluent setters.</jc> 2142 * ReaderParser <jv>parser</jv> = JsonParser 2143 * .<jsm>create</jsm>() 2144 * .findFluentSetters(MyBean.<jk>class</jk>) 2145 * .build(); 2146 * 2147 * <jc>// Parse into bean using fluent setter.</jc> 2148 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>); 2149 * </p> 2150 * 2151 * <h5 class='section'>Notes:</h5><ul> 2152 * <li class='note'>This method is functionally equivalent to using the {@link Bean#findFluentSetters()} annotation. 2153 * </ul> 2154 * 2155 * <h5 class='section'>See Also:</h5><ul> 2156 * <li class='ja'>{@link Bean#findFluentSetters()} 2157 * <li class='jm'>{@link #findFluentSetters()} 2158 * </ul> 2159 * 2160 * @param on The class that this applies to. 2161 * <br>Cannot be <jk>null</jk>. 2162 * @return This object. 2163 */ 2164 public Builder findFluentSetters(Class<?> on) { 2165 assertArgNotNull("on", on); 2166 return annotations(BeanAnnotation.create(on).findFluentSetters(true).build()); 2167 } 2168 2169 @Override /* Overridden from Context.Builder */ 2170 public HashKey hashKey() { 2171 // @formatter:off 2172 return HashKey.of( 2173 super.hashKey(), 2174 beanClassVisibility, 2175 beanConstructorVisibility, 2176 beanMethodVisibility, 2177 beanFieldVisibility, 2178 beanDictionary, 2179 swaps, 2180 notBeanClasses, 2181 notBeanPackages, 2182 integer( 2183 disableBeansRequireSomeProperties, 2184 beanMapPutReturnsOldValue, 2185 beansRequireDefaultConstructor, 2186 beansRequireSerializable, 2187 beansRequireSettersForGetters, 2188 disableIgnoreTransientFields, 2189 disableIgnoreUnknownNullBeanProperties, 2190 disableIgnoreMissingSetters, 2191 disableInterfaceProxies, 2192 findFluentSetters, 2193 ignoreInvocationExceptionsOnGetters, 2194 ignoreInvocationExceptionsOnSetters, 2195 ignoreUnknownBeanProperties, 2196 ignoreUnknownEnumValues, 2197 sortProperties, 2198 useEnumNames, 2199 useJavaBeanIntrospector 2200 ), 2201 typePropertyName, 2202 mediaType, 2203 timeZone, 2204 locale, 2205 propertyNamer 2206 ); 2207 // @formatter:on 2208 } 2209 2210 /** 2211 * Ignore invocation errors on getters. 2212 * 2213 * <p> 2214 * When enabled, errors thrown when calling bean getter methods will silently be ignored. 2215 * Otherwise, a {@code BeanRuntimeException} is thrown. 2216 * 2217 * <h5 class='section'>Example:</h5> 2218 * <p class='bjava'> 2219 * <jc>// A bean with a property that throws an exception.</jc> 2220 * <jk>public class</jk> MyBean { 2221 * <jk>public</jk> String getFoo() { 2222 * <jk>throw new</jk> RuntimeException(<js>"foo"</js>); 2223 * } 2224 * } 2225 * 2226 * <jc>// Create a serializer that ignores bean getter exceptions.</jc> 2227 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2228 * .<jsm>create</jsm>() 2229 * .ingoreInvocationExceptionsOnGetters() 2230 * .build(); 2231 * 2232 * <jc>// Exception is ignored.</jc> 2233 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 2234 * </p> 2235 * 2236 * <h5 class='section'>See Also:</h5><ul> 2237 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreInvocationExceptionsOnGetters()} 2238 * </ul> 2239 * 2240 * @return This object. 2241 */ 2242 public Builder ignoreInvocationExceptionsOnGetters() { 2243 return ignoreInvocationExceptionsOnGetters(true); 2244 } 2245 2246 /** 2247 * Same as {@link #ignoreInvocationExceptionsOnGetters()} but allows you to explicitly specify the value. 2248 * 2249 * @param value The value for this setting. 2250 * @return This object. 2251 */ 2252 public Builder ignoreInvocationExceptionsOnGetters(boolean value) { 2253 ignoreInvocationExceptionsOnGetters = value; 2254 return this; 2255 } 2256 2257 /** 2258 * Ignore invocation errors on setters. 2259 * 2260 * <p> 2261 * When enabled, errors thrown when calling bean setter methods will silently be ignored. 2262 * Otherwise, a {@code BeanRuntimeException} is thrown. 2263 * 2264 * <h5 class='section'>Example:</h5> 2265 * <p class='bjava'> 2266 * <jc>// A bean with a property that throws an exception.</jc> 2267 * <jk>public class</jk> MyBean { 2268 * <jk>public void</jk> setFoo(String <jv>foo</jv>) { 2269 * <jk>throw new</jk> RuntimeException(<js>"foo"</js>); 2270 * } 2271 * } 2272 * 2273 * <jc>// Create a parser that ignores bean setter exceptions.</jc> 2274 * ReaderParser <jv>parser</jv> = JsonParser 2275 * .<jsm>create</jsm>() 2276 * .ignoreInvocationExceptionsOnSetters() 2277 * .build(); 2278 * 2279 * <jc>// Exception is ignored.</jc> 2280 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>); 2281 * </p> 2282 * 2283 * <h5 class='section'>See Also:</h5><ul> 2284 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreInvocationExceptionsOnSetters()} 2285 * </ul> 2286 * 2287 * @return This object. 2288 */ 2289 public Builder ignoreInvocationExceptionsOnSetters() { 2290 return ignoreInvocationExceptionsOnSetters(true); 2291 } 2292 2293 /** 2294 * Same as {@link #ignoreInvocationExceptionsOnSetters()} but allows you to explicitly specify the value. 2295 * 2296 * @param value The value for this setting. 2297 * @return This object. 2298 */ 2299 public Builder ignoreInvocationExceptionsOnSetters(boolean value) { 2300 ignoreInvocationExceptionsOnSetters = value; 2301 return this; 2302 } 2303 2304 /** 2305 * Ignore unknown properties. 2306 * 2307 * <p> 2308 * When enabled, trying to set a value on a non-existent bean property will silently be ignored. 2309 * Otherwise, a {@code BeanRuntimeException} is thrown. 2310 * 2311 * <h5 class='section'>Example:</h5> 2312 * <p class='bjava'> 2313 * <jc>// A bean with a single property.</jc> 2314 * <jk>public class</jk> MyBean { 2315 * <jk>public</jk> String <jf>foo</jf>; 2316 * } 2317 * 2318 * <jc>// Create a parser that ignores missing bean properties.</jc> 2319 * ReaderParser <jv>parser</jv> = JsonParser 2320 * .<jsm>create</jsm>() 2321 * .ignoreUnknownBeanProperties() 2322 * .build(); 2323 * 2324 * <jc>// Doesn't throw an exception on unknown 'bar' property.</jc> 2325 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"{foo:'foo',bar:'bar'}"</js>, MyBean.<jk>class</jk>); 2326 * </p> 2327 * 2328 * <h5 class='section'>See Also:</h5><ul> 2329 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreUnknownBeanProperties()} 2330 * </ul> 2331 * 2332 * @return This object. 2333 */ 2334 public Builder ignoreUnknownBeanProperties() { 2335 return ignoreUnknownBeanProperties(true); 2336 } 2337 2338 /** 2339 * Same as {@link #ignoreUnknownBeanProperties()} but allows you to explicitly specify the value. 2340 * 2341 * @param value The value for this setting. 2342 * @return This object. 2343 */ 2344 public Builder ignoreUnknownBeanProperties(boolean value) { 2345 ignoreUnknownBeanProperties = value; 2346 return this; 2347 } 2348 2349 /** 2350 * Ignore unknown properties. 2351 * 2352 * <p> 2353 * When enabled, unknown enum values will be set to <jk>null</jk> instead of throwing an exception. 2354 * 2355 * <h5 class='section'>See Also:</h5><ul> 2356 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreUnknownEnumValues()} 2357 * </ul> 2358 * 2359 * @return This object. 2360 */ 2361 public Builder ignoreUnknownEnumValues() { 2362 return ignoreUnknownEnumValues(true); 2363 } 2364 2365 /** 2366 * Same as {@link #ignoreUnknownEnumValues()} but allows you to explicitly specify the value. 2367 * 2368 * @param value The value for this setting. 2369 * @return This object. 2370 */ 2371 public Builder ignoreUnknownEnumValues(boolean value) { 2372 ignoreUnknownEnumValues = value; 2373 return this; 2374 } 2375 2376 @Override /* Overridden from Builder */ 2377 public Builder impl(Context value) { 2378 super.impl(value); 2379 return this; 2380 } 2381 2382 /** 2383 * Implementation classes. 2384 * 2385 * <p> 2386 * For interfaces and abstract classes this method can be used to specify an implementation class for the 2387 * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a 2388 * parse). 2389 * 2390 * <h5 class='section'>Example:</h5> 2391 * <p class='bjava'> 2392 * <jc>// A bean interface.</jc> 2393 * <jk>public interface</jk> MyBean { 2394 * ... 2395 * } 2396 * 2397 * <jc>// A bean implementation.</jc> 2398 * <jk>public class</jk> MyBeanImpl <jk>implements</jk> MyBean { 2399 * ... 2400 * } 2401 2402 * <jc>// Create a parser that instantiates MyBeanImpls when parsing MyBeans.</jc> 2403 * ReaderParser <jv>parser</jv> = JsonParser 2404 * .<jsm>create</jsm>() 2405 * .implClass(MyBean.<jk>class</jk>, MyBeanImpl.<jk>class</jk>) 2406 * .build(); 2407 * 2408 * <jc>// Instantiates a MyBeanImpl,</jc> 2409 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"..."</js>, MyBean.<jk>class</jk>); 2410 * </p> 2411 * 2412 * @param interfaceClass The interface class. 2413 * <br>Cannot be <jk>null</jk>. 2414 * @param implClass The implementation class. 2415 * <br>Cannot be <jk>null</jk>. 2416 * @return This object. 2417 */ 2418 public Builder implClass(Class<?> interfaceClass, Class<?> implClass) { 2419 assertArgNotNull("interfaceClass", interfaceClass); 2420 assertArgNotNull("implClass", implClass); 2421 return annotations(MarshalledAnnotation.create(interfaceClass).implClass(implClass).build()); 2422 } 2423 2424 /** 2425 * Implementation classes. 2426 * 2427 * <p> 2428 * For interfaces and abstract classes this method can be used to specify an implementation class for the 2429 * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a 2430 * parse). 2431 * 2432 * <h5 class='section'>Example:</h5> 2433 * <p class='bjava'> 2434 * <jc>// A bean with a single property.</jc> 2435 * <jk>public interface</jk> MyBean { 2436 * ... 2437 * } 2438 * 2439 * <jc>// A bean with a single property.</jc> 2440 * <jk>public class</jk> MyBeanImpl <jk>implements</jk> MyBean { 2441 * ... 2442 * } 2443 2444 * <jc>// Create a parser that instantiates MyBeanImpls when parsing MyBeans.</jc> 2445 * ReaderParser <jv>parser</jv> = JsonParser 2446 * .<jsm>create</jsm>() 2447 * .implClasses(AMap.<jsm>of</jsm>(MyBean.<jk>class</jk>, MyBeanImpl.<jk>class</jk>)) 2448 * .build(); 2449 * 2450 * <jc>// Instantiates a MyBeanImpl,</jc> 2451 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<js>"..."</js>, MyBean.<jk>class</jk>); 2452 * </p> 2453 * 2454 * @param values 2455 * The new value for this setting. 2456 * <br>Cannot be <jk>null</jk>. 2457 * @return This object. 2458 */ 2459 public Builder implClasses(Map<Class<?>,Class<?>> values) { 2460 assertArgNotNull("values", values); 2461 values.forEach((k, v) -> annotations(MarshalledAnnotation.create(k).implClass(v).build())); 2462 return this; 2463 } 2464 2465 /** 2466 * Identifies a class to be used as the interface class for the specified class and all subclasses. 2467 * 2468 * <p> 2469 * When specified, only the list of properties defined on the interface class will be used during serialization. 2470 * Additional properties on subclasses will be ignored. 2471 * 2472 * <p class='bjava'> 2473 * <jc>// Parent class or interface</jc> 2474 * <jk>public abstract class</jk> A { 2475 * <jk>public</jk> String <jf>foo</jf> = <js>"foo"</js>; 2476 * } 2477 * 2478 * <jc>// Sub class</jc> 2479 * <jk>public class</jk> A1 <jk>extends</jk> A { 2480 * <jk>public</jk> String <jf>bar</jf> = <js>"bar"</js>; 2481 * } 2482 * 2483 * <jc>// Create a serializer and define our interface class mapping.</jc> 2484 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2485 * .<jsm>create</jsm>() 2486 * .interfaceClass(A1.<jk>class</jk>, A.<jk>class</jk>) 2487 * .build(); 2488 * 2489 * <jc>// Produces "{"foo":"foo"}"</jc> 2490 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> A1()); 2491 * </p> 2492 * 2493 * <p> 2494 * This annotation can be used on the parent class so that it filters to all child classes, or can be set 2495 * individually on the child classes. 2496 * 2497 * <h5 class='section'>Notes:</h5><ul> 2498 * <li class='note'>The {@link Bean#interfaceClass() @Bean(interfaceClass)} annotation is the equivalent annotation-based solution. 2499 * </ul> 2500 * 2501 * @param on The class that the interface class applies to. 2502 * <br>Cannot be <jk>null</jk>. 2503 * @param value 2504 * The new value for this setting. 2505 * <br>Cannot be <jk>null</jk>. 2506 * @return This object. 2507 */ 2508 public Builder interfaceClass(Class<?> on, Class<?> value) { 2509 assertArgNotNull("on", on); 2510 assertArgNotNull("value", value); 2511 return annotations(BeanAnnotation.create(on).interfaceClass(value).build()); 2512 } 2513 2514 /** 2515 * Identifies a set of interfaces. 2516 * 2517 * <p> 2518 * When specified, only the list of properties defined on the interface class will be used during serialization 2519 * of implementation classes. Additional properties on subclasses will be ignored. 2520 * 2521 * <p class='bjava'> 2522 * <jc>// Parent class or interface</jc> 2523 * <jk>public abstract class</jk> A { 2524 * <jk>public</jk> String <jf>foo</jf> = <js>"foo"</js>; 2525 * } 2526 * 2527 * <jc>// Sub class</jc> 2528 * <jk>public class</jk> A1 <jk>extends</jk> A { 2529 * <jk>public</jk> String <jf>bar</jf> = <js>"bar"</js>; 2530 * } 2531 * 2532 * <jc>// Create a serializer and define our interface class mapping.</jc> 2533 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2534 * .<jsm>create</jsm>() 2535 * .interfaces(A.<jk>class</jk>) 2536 * .build(); 2537 * 2538 * <jc>// Produces "{"foo":"foo"}"</jc> 2539 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> A1()); 2540 * </p> 2541 * 2542 * <p> 2543 * This annotation can be used on the parent class so that it filters to all child classes, or can be set 2544 * individually on the child classes. 2545 * 2546 * <h5 class='section'>Notes:</h5><ul> 2547 * <li class='note'>The {@link Bean#interfaceClass() @Bean(interfaceClass)} annotation is the equivalent annotation-based solution. 2548 * </ul> 2549 * 2550 * @param value 2551 * The new value for this setting. 2552 * <br>Cannot be <jk>null</jk>. 2553 * @return This object. 2554 */ 2555 public Builder interfaces(Class<?>...value) { 2556 assertArgNoNulls("value", value); 2557 for (var v : value) 2558 annotations(BeanAnnotation.create(v).interfaceClass(v).build()); 2559 return this; 2560 } 2561 2562 /** 2563 * <i><l>Context</l> configuration property: </i> Locale. 2564 * 2565 * <p> 2566 * Specifies the default locale for serializer and parser sessions when not specified via {@link BeanSession.Builder#locale(Locale)}. 2567 * Typically used for POJO swaps that need to deal with locales such as swaps that convert <l>Date</l> and <l>Calendar</l> 2568 * objects to strings by accessing it via the session passed into the {@link ObjectSwap#swap(BeanSession, Object)} and 2569 * {@link ObjectSwap#unswap(BeanSession, Object, ClassMeta, String)} methods. 2570 * 2571 * <h5 class='section'>Example:</h5> 2572 * <p class='bjava'> 2573 * <jc>// Define a POJO swap that skips serializing beans if we're in the UK.</jc> 2574 * <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap<MyBean> { 2575 * <ja>@Override</ja> 2576 * <jk>public</jk> String swap(BeanSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception { 2577 * <jk>if</jk> (<jv>session</jv>.getLocale().equals(Locale.<jsf>UK</jsf>)) 2578 * <jk>return null</jk>; 2579 * <jk>return</jk> <jv>bean</jv>.toString(); 2580 * } 2581 * } 2582 * 2583 * <jc>// Create a serializer that uses the specified locale if it's not passed in through session args.</jc> 2584 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2585 * .<jsm>create</jsm>() 2586 * .locale(Locale.<jsf>UK</jsf>) 2587 * .swaps(MyBeanSwap.<jk>class</jk>) 2588 * .build(); 2589 * </p> 2590 * 2591 * <h5 class='section'>See Also:</h5><ul> 2592 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#locale()} 2593 * <li class='jm'>{@link org.apache.juneau.BeanSession.Builder#locale(Locale)} 2594 * </ul> 2595 * 2596 * @param value The new value for this property. 2597 * <br>Cannot be <jk>null</jk>. 2598 * @return This object. 2599 */ 2600 public Builder locale(Locale value) { 2601 locale = assertArgNotNull("value", value); 2602 return this; 2603 } 2604 2605 /** 2606 * <i><l>Context</l> configuration property: </i> Media type. 2607 * 2608 * <p> 2609 * Specifies the default media type for serializer and parser sessions when not specified via {@link BeanSession.Builder#mediaType(MediaType)}. 2610 * Typically used for POJO swaps that need to serialize the same POJO classes differently depending on 2611 * the specific requested media type. For example, a swap could handle a request for media types <js>"application/json"</js> 2612 * and <js>"application/json+foo"</js> slightly differently even though they're both being handled by the same JSON 2613 * serializer or parser. 2614 * 2615 * <h5 class='section'>Example:</h5> 2616 * <p class='bjava'> 2617 * <jc>// Define a POJO swap that skips serializing beans if the media type is application/json.</jc> 2618 * <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap<MyBean> { 2619 * <ja>@Override</ja> 2620 * <jk>public</jk> String swap(BeanSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception { 2621 * <jk>if</jk> (<jv>session</jv>.getMediaType().equals(<js>"application/json"</js>)) 2622 * <jk>return null</jk>; 2623 * <jk>return</jk> <jv>bean</jv>.toString(); 2624 * } 2625 * } 2626 * 2627 * <jc>// Create a serializer that uses the specified media type if it's not passed in through session args.</jc> 2628 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2629 * .<jsm>create</jsm>() 2630 * .mediaType(MediaType.<jsf>JSON</jsf>) 2631 * .build(); 2632 * </p> 2633 * 2634 * <h5 class='section'>See Also:</h5><ul> 2635 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#mediaType()} 2636 * <li class='jm'>{@link org.apache.juneau.BeanSession.Builder#mediaType(MediaType)} 2637 * </ul> 2638 * 2639 * @param value The new value for this property. 2640 * <br>Can be <jk>null</jk> (no default media type will be set). 2641 * @return This object. 2642 */ 2643 public Builder mediaType(MediaType value) { 2644 mediaType = value; 2645 return this; 2646 } 2647 2648 /** 2649 * Returns the set of not-bean classes. 2650 * 2651 * <p> 2652 * Gives access to the inner set if you need to make more than simple additions via {@link #notBeanClasses(ClassInfo...)}. 2653 * 2654 * @return The set of not-bean classes. 2655 * @see #notBeanClasses(ClassInfo...) 2656 */ 2657 public Set<ClassInfo> notBeanClasses() { 2658 return notBeanClasses; 2659 } 2660 2661 /** 2662 * Convenience method for {@link #notBeanClasses(ClassInfo...)} that accepts {@link Class} objects. 2663 * 2664 * @param values 2665 * The values to add to this setting. 2666 * <br>Cannot contain <jk>null</jk> values. 2667 * @return This object. 2668 * @see #notBeanClasses(ClassInfo...) 2669 */ 2670 public Builder notBeanClasses(Class<?>...values) { 2671 assertArgNoNulls("values", values); 2672 return notBeanClasses(Stream.of(values).map(ReflectionUtils::info).toArray(ClassInfo[]::new)); 2673 } 2674 2675 /** 2676 * Bean class exclusions. 2677 * 2678 * <p> 2679 * List of classes that should not be treated as beans even if they appear to be bean-like. 2680 * Not-bean classes are converted to <c>Strings</c> during serialization. 2681 * 2682 * <p> 2683 * Values can consist of any of the following types: 2684 * <ul> 2685 * <li>Classes. 2686 * <li>Arrays and collections of classes. 2687 * </ul> 2688 * 2689 * <h5 class='section'>Example:</h5> 2690 * <p class='bjava'> 2691 * <jc>// A bean with a single property.</jc> 2692 * <jk>public class</jk> MyBean { 2693 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 2694 * 2695 * <jk>public</jk> String toString() { 2696 * <jk>return</jk> <js>"baz"</js>; 2697 * } 2698 * } 2699 * 2700 * <jc>// Create a serializer that doesn't treat MyBean as a bean class.</jc> 2701 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2702 * .<jsm>create</jsm>() 2703 * .notBeanClasses(MyBean.<jk>class</jk>) 2704 * .build(); 2705 * 2706 * <jc>// Produces "baz" instead of {"foo":"bar"}</jc> 2707 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 2708 * </p> 2709 * 2710 * <h5 class='section'>Notes:</h5><ul> 2711 * <li class='note'>The {@link BeanIgnore @BeanIgnore} annotation can also be used on classes to prevent them from being recognized as beans. 2712 * </ul> 2713 * 2714 * <h5 class='section'>See Also:</h5><ul> 2715 * <li class='ja'>{@link org.apache.juneau.annotation.BeanIgnore} 2716 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#notBeanClasses()} 2717 * </ul> 2718 * 2719 * @param values 2720 * The values to add to this setting. 2721 * <br>Cannot contain <jk>null</jk> values. 2722 * @return This object. 2723 */ 2724 public Builder notBeanClasses(ClassInfo...values) { 2725 assertArgNoNulls("values", values); 2726 notBeanClasses().addAll(l(values)); 2727 return this; 2728 } 2729 2730 /** 2731 * Same as {@link #notBeanClasses(ClassInfo...)} but allows you to pass in a collection of class info objects. 2732 * 2733 * @param values 2734 * The values to add to this setting. 2735 * <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values. 2736 * @return This object. 2737 * @see #notBeanClasses(ClassInfo...) 2738 */ 2739 public Builder notBeanClasses(Collection<ClassInfo> values) { 2740 assertArgNoNulls("values", values); 2741 notBeanClasses().addAll(values); 2742 return this; 2743 } 2744 2745 /** 2746 * Returns the list of not-bean Java package names. 2747 * 2748 * <p> 2749 * Gives access to the inner list if you need to make more than simple additions via {@link #notBeanPackages(String...)}. 2750 * 2751 * @return The list of not-bean Java package names. 2752 * @see #notBeanPackages(String...) 2753 */ 2754 public Set<String> notBeanPackages() { 2755 return notBeanPackages; 2756 } 2757 2758 /** 2759 * Same as {@link #notBeanPackages(String...)} but allows you to pass in a collection of classes. 2760 * 2761 * @param values 2762 * The values to add to this setting. 2763 * <br>Cannot be <jk>null</jk> or contain <jk>null</jk> values. 2764 * @return This object. 2765 * @see #notBeanPackages(String...) 2766 */ 2767 public Builder notBeanPackages(Collection<String> values) { 2768 assertArgNoNulls("values", values); 2769 notBeanPackages().addAll(values); 2770 return this; 2771 } 2772 2773 /** 2774 * Bean package exclusions. 2775 * 2776 * <p> 2777 * Used as a convenient way of defining the {@link #notBeanClasses(Class...)} property for entire packages. 2778 * Any classes within these packages will be serialized to strings using {@link Object#toString()}. 2779 * 2780 * <p> 2781 * Note that you can specify suffix patterns to include all subpackages. 2782 * 2783 * <p> 2784 * Values can consist of any of the following types: 2785 * <ul> 2786 * <li>Strings. 2787 * <li>Arrays and collections of strings. 2788 * </ul> 2789 * 2790 * <h5 class='section'>Example:</h5> 2791 * <p class='bjava'> 2792 * <jc>// Create a serializer that ignores beans in the specified packages.</jc> 2793 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2794 * .<jsm>create</jsm>() 2795 * .notBeanPackages(<js>"org.apache.foo"</js>, <js>"org.apache.bar.*"</js>) 2796 * .build(); 2797 * </p> 2798 * 2799 * @param values 2800 * The values to add to this setting. 2801 * <br>Values can consist of any of the following types: 2802 * <ul> 2803 * <li>{@link Package} objects. 2804 * <li>Strings. 2805 * <li>Arrays and collections of anything in this list. 2806 * </ul> 2807 * <br>Cannot contain <jk>null</jk> values. 2808 * @return This object. 2809 */ 2810 public Builder notBeanPackages(String...values) { 2811 assertArgNoNulls("values", values); 2812 return notBeanPackages(l(values)); 2813 } 2814 2815 /** 2816 * Bean property namer 2817 * 2818 * <p> 2819 * Same as {@link #propertyNamer(Class)} but allows you to specify a namer for a specific class. 2820 * 2821 * <h5 class='section'>Example:</h5> 2822 * <p class='bjava'> 2823 * <jc>// A bean with a single property.</jc> 2824 * <jk>public class</jk> MyBean { 2825 * <jk>public</jk> String <jf>fooBarBaz</jf> = <js>"fooBarBaz"</js>; 2826 * } 2827 * 2828 * <jc>// Create a serializer that uses Dashed-Lower-Case property names for the MyBean class only.</jc> 2829 * <jc>// (e.g. "foo-bar-baz" instead of "fooBarBaz")</jc> 2830 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2831 * .<jsm>create</jsm>() 2832 * .propertyNamer(MyBean.<jk>class</jk>, PropertyNamerDLC.<jk>class</jk>) 2833 * .build(); 2834 * 2835 * <jc>// Produces: {"foo-bar-baz":"fooBarBaz"}</jc> 2836 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 2837 * </p> 2838 * 2839 * <h5 class='section'>See Also:</h5><ul> 2840 * <li class='ja'>{@link Bean#propertyNamer() Bean(propertyNamer)} 2841 * <li class='jm'>{@link #propertyNamer(Class)} 2842 * </ul> 2843 * 2844 * @param on The class that the namer applies to. 2845 * <br>Cannot be <jk>null</jk>. 2846 * @param value 2847 * The new value for this setting. 2848 * <br>The default is {@link BasicPropertyNamer}. 2849 * <br>Cannot be <jk>null</jk>. 2850 * @return This object. 2851 */ 2852 public Builder propertyNamer(Class<?> on, Class<? extends PropertyNamer> value) { 2853 assertArgNotNull("on", on); 2854 assertArgNotNull("value", value); 2855 return annotations(BeanAnnotation.create(on).propertyNamer(value).build()); 2856 } 2857 2858 /** 2859 * Bean property namer 2860 * 2861 * <p> 2862 * The class to use for calculating bean property names. 2863 * 2864 * <p> 2865 * Predefined classes: 2866 * <ul> 2867 * <li>{@link BasicPropertyNamer} - Default. 2868 * <li>{@link PropertyNamerDLC} - Dashed-lower-case names. 2869 * <li>{@link PropertyNamerULC} - Dashed-upper-case names. 2870 * </ul> 2871 * 2872 * <h5 class='section'>Example:</h5> 2873 * <p class='bjava'> 2874 * <jc>// A bean with a single property.</jc> 2875 * <jk>public class</jk> MyBean { 2876 * <jk>public</jk> String <jf>fooBarBaz</jf> = <js>"fooBarBaz"</js>; 2877 * } 2878 * 2879 * <jc>// Create a serializer that uses Dashed-Lower-Case property names.</jc> 2880 * <jc>// (e.g. "foo-bar-baz" instead of "fooBarBaz")</jc> 2881 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2882 * .<jsm>create</jsm>() 2883 * .propertyNamer(PropertyNamerDLC.<jk>class</jk>) 2884 * .build(); 2885 * 2886 * <jc>// Produces: {"foo-bar-baz":"fooBarBaz"}</jc> 2887 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 2888 * </p> 2889 * 2890 * @param value 2891 * The new value for this setting. 2892 * <br>Can be <jk>null</jk> (will use {@link BasicPropertyNamer} as the default). 2893 * @return This object. 2894 */ 2895 public Builder propertyNamer(Class<? extends PropertyNamer> value) { 2896 propertyNamer = value; 2897 return this; 2898 } 2899 2900 /** 2901 * Sort bean properties. 2902 * 2903 * <p> 2904 * When enabled, all bean properties will be serialized and access in alphabetical order. 2905 * Otherwise, the natural order of the bean properties is used which is dependent on the JVM vendor. 2906 * On IBM JVMs, the bean properties are ordered based on their ordering in the Java file. 2907 * On Oracle JVMs, the bean properties are not ordered (which follows the official JVM specs). 2908 * 2909 * <p> 2910 * this setting is disabled by default so that IBM JVM users don't have to use {@link Bean @Bean} annotations 2911 * to force bean properties to be in a particular order and can just alter the order of the fields/methods 2912 * in the Java file. 2913 * 2914 * <h5 class='section'>Example:</h5> 2915 * <p class='bjava'> 2916 * <jc>// A bean with 3 properties.</jc> 2917 * <jk>public class</jk> MyBean { 2918 * <jk>public</jk> String <jf>c</jf> = <js>"1"</js>; 2919 * <jk>public</jk> String <jf>b</jf> = <js>"2"</js>; 2920 * <jk>public</jk> String <jf>a</jf> = <js>"3"</js>; 2921 * } 2922 * 2923 * <jc>// Create a serializer that sorts bean properties.</jc> 2924 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2925 * .<jsm>create</jsm>() 2926 * .sortProperties() 2927 * .build(); 2928 * 2929 * <jc>// Produces: {"a":"3","b":"2","c":"1"}</jc> 2930 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 2931 * </p> 2932 * 2933 * <h5 class='section'>Notes:</h5><ul> 2934 * <li class='note'>The {@link Bean#sort() @Bean.sort()} annotation can also be used to sort properties on just a single class. 2935 * </ul> 2936 * 2937 * @return This object. 2938 */ 2939 public Builder sortProperties() { 2940 sortProperties = true; 2941 return sortProperties(true); 2942 } 2943 2944 /** 2945 * Same as {@link #sortProperties()} but allows you to explicitly specify the value. 2946 * 2947 * @param value The value for this setting. 2948 * @return This object. 2949 */ 2950 public Builder sortProperties(boolean value) { 2951 sortProperties = value; 2952 return this; 2953 } 2954 2955 /** 2956 * Sort bean properties. 2957 * 2958 * <p> 2959 * Same as {@link #sortProperties()} but allows you to specify individual bean classes instead of globally. 2960 * 2961 * <h5 class='section'>Example:</h5> 2962 * <p class='bjava'> 2963 * <jc>// A bean with 3 properties.</jc> 2964 * <jk>public class</jk> MyBean { 2965 * <jk>public</jk> String <jf>c</jf> = <js>"1"</js>; 2966 * <jk>public</jk> String <jf>b</jf> = <js>"2"</js>; 2967 * <jk>public</jk> String <jf>a</jf> = <js>"3"</js>; 2968 * } 2969 * 2970 * <jc>// Create a serializer that sorts properties on MyBean.</jc> 2971 * WriterSerializer <jv>serializer</jv> = JsonSerializer 2972 * .<jsm>create</jsm>() 2973 * .sortProperties(MyBean.<jk>class</jk>) 2974 * .build(); 2975 * 2976 * <jc>// Produces: {"a":"3","b":"2","c":"1"}</jc> 2977 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 2978 * </p> 2979 * 2980 * <h5 class='section'>See Also:</h5><ul> 2981 * <li class='ja'>{@link Bean#sort() Bean(sort)} 2982 * <li class='jm'>{@link #sortProperties()} 2983 * </ul> 2984 * 2985 * @param on The bean classes to sort properties on. 2986 * <br>Cannot contain <jk>null</jk> values. 2987 * @return This object. 2988 */ 2989 public Builder sortProperties(Class<?>...on) { 2990 assertArgNoNulls("on", on); 2991 for (var c : on) 2992 annotations(BeanAnnotation.create(c).sort(true).build()); 2993 return this; 2994 } 2995 2996 /** 2997 * Identifies a stop class for the annotated class. 2998 * 2999 * <p> 3000 * Identical in purpose to the stop class specified by {@link Introspector#getBeanInfo(Class, Class)}. 3001 * Any properties in the stop class or in its base classes will be ignored during analysis. 3002 * 3003 * <p> 3004 * For example, in the following class hierarchy, instances of <c>C3</c> will include property <c>p3</c>, 3005 * but not <c>p1</c> or <c>p2</c>. 3006 * 3007 * <h5 class='section'>Example:</h5> 3008 * <p class='bjava'> 3009 * <jk>public class</jk> C1 { 3010 * <jk>public int</jk> getP1(); 3011 * } 3012 * 3013 * <jk>public class</jk> C2 <jk>extends</jk> C1 { 3014 * <jk>public int</jk> getP2(); 3015 * } 3016 * 3017 * <jk>public class</jk> C3 <jk>extends</jk> C2 { 3018 * <jk>public int</jk> getP3(); 3019 * } 3020 * 3021 * <jc>// Create a serializer specifies a stop class for C3.</jc> 3022 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3023 * .<jsm>create</jsm>() 3024 * .stopClass(C3.<jk>class</jk>, C2.<jk>class</jk>) 3025 * .build(); 3026 * 3027 * <jc>// Produces: {"p3":"..."}</jc> 3028 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> C3()); 3029 * </p> 3030 * 3031 * @param on The class on which the stop class is being applied. 3032 * <br>Cannot be <jk>null</jk>. 3033 * @param value 3034 * The new value for this setting. 3035 * <br>Cannot be <jk>null</jk>. 3036 * @return This object. 3037 */ 3038 public Builder stopClass(Class<?> on, Class<?> value) { 3039 assertArgNotNull("on", on); 3040 assertArgNotNull("value", value); 3041 return annotations(BeanAnnotation.create(on).stopClass(value).build()); 3042 } 3043 3044 /** 3045 * A shortcut for defining a {@link FunctionalSwap}. 3046 * 3047 * <h5 class='section'>Example:</h5> 3048 * <p class='bjava'> 3049 * <jc>// Create a serializer that performs a custom format for DAte objects.</jc> 3050 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3051 * .<jsm>create</jsm>() 3052 * .swap(Date.<jk>class</jk>, String.<jk>class</jk>, <jv>x</jv> -> <jsm>format</jsm>(<jv>x</jv>)) 3053 * .build(); 3054 * </p> 3055 * 3056 * @param <T> The object type being swapped out. 3057 * @param <S> The object type being swapped in. 3058 * @param normalClass The object type being swapped out. 3059 * <br>Cannot be <jk>null</jk>. 3060 * @param swappedClass The object type being swapped in. 3061 * <br>Cannot be <jk>null</jk>. 3062 * @param swapFunction The function to convert the object. 3063 * <br>Cannot be <jk>null</jk>. 3064 * @return This object. 3065 */ 3066 public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) { 3067 return swap(normalClass, swappedClass, swapFunction, null); 3068 } 3069 3070 /** 3071 * A shortcut for defining a {@link FunctionalSwap}. 3072 * 3073 * <h5 class='section'>Example:</h5> 3074 * <p class='bjava'> 3075 * <jc>// Create a serializer that performs a custom format for Date objects.</jc> 3076 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3077 * .<jsm>create</jsm>() 3078 * .swap(Date.<jk>class</jk>, String.<jk>class</jk>, <jv>x</jv> -> <jsm>format</jsm>(<jv>x</jv>), <jv>x</jv> -> <jsm>parse</jsm>(<jv>x</jv>)) 3079 * .build(); 3080 * </p> 3081 * 3082 * @param <T> The object type being swapped out. 3083 * @param <S> The object type being swapped in. 3084 * @param normalClass The object type being swapped out. 3085 * <br>Cannot be <jk>null</jk>. 3086 * @param swappedClass The object type being swapped in. 3087 * <br>Cannot be <jk>null</jk>. 3088 * @param swapFunction The function to convert the object during serialization. 3089 * <br>Cannot be <jk>null</jk>. 3090 * @param unswapFunction The function to convert the object during parsing. 3091 * <br>Cannot be <jk>null</jk>. 3092 * @return This object. 3093 */ 3094 public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) { 3095 assertArgNotNull("normalClass", normalClass); 3096 assertArgNotNull("swappedClass", swappedClass); 3097 assertArgNotNull("swapFunction", swapFunction); 3098 assertArgNotNull("unswapFunction", unswapFunction); 3099 swaps().add(0, new FunctionalSwap<>(normalClass, swappedClass, swapFunction, unswapFunction)); 3100 return this; 3101 } 3102 3103 /** 3104 * Returns the bean swaps list. 3105 * 3106 * <p> 3107 * Gives access to the inner list if you need to make more than simple additions via {@link #swaps(Class...)}. 3108 * 3109 * @return The bean swaps list. 3110 * @see #swaps(Class...) 3111 */ 3112 public List<Object> swaps() { 3113 return swaps; 3114 } 3115 3116 /** 3117 * Same as {@link #swaps(Object...)} but explicitly specifies an array of classes to avoid compilation warnings. 3118 * 3119 * @param values 3120 * The values to add to this setting. 3121 * <br>Values can consist of any of the following types: 3122 * <ul> 3123 * <li>Any subclass of {@link ObjectSwap}. 3124 * <li>Any surrogate class. A shortcut for defining a {@link SurrogateSwap}. 3125 * </ul> 3126 * <br>Cannot be <jk>null</jk>. 3127 * @return This object. 3128 */ 3129 public Builder swaps(Class<?>...values) { 3130 assertArgNoNulls("values", values); 3131 swaps().addAll(0, accumulate(values)); 3132 return this; 3133 } 3134 3135 /** 3136 * Java object swaps. 3137 * 3138 * <p> 3139 * Swaps are used to "swap out" non-serializable classes with serializable equivalents during serialization, 3140 * and "swap in" the non-serializable class during parsing. 3141 * 3142 * <p> 3143 * An example of a swap would be a <c>Calendar</c> object that gets swapped out for an ISO8601 string. 3144 * 3145 * <p> 3146 * Multiple swaps can be associated with a single class. 3147 * When multiple swaps are applicable to the same class, the media type pattern defined by 3148 * {@link ObjectSwap#forMediaTypes()} or {@link Swap#mediaTypes() @Swap(mediaTypes)} are used to come up with the best match. 3149 * 3150 * <p> 3151 * Values can consist of any of the following types: 3152 * <ul> 3153 * <li>Any subclass of {@link ObjectSwap}. 3154 * <li>Any instance of {@link ObjectSwap}. 3155 * <li>Any surrogate class. A shortcut for defining a {@link SurrogateSwap}. 3156 * <li>Any array or collection of the objects above. 3157 * </ul> 3158 * 3159 * <h5 class='section'>Example:</h5> 3160 * <p class='bjava'> 3161 * <jc>// Sample swap for converting Dates to ISO8601 strings.</jc> 3162 * <jk>public class</jk> MyDateSwap <jk>extends</jk> StringSwap<Date> { 3163 * <jc>// ISO8601 formatter.</jc> 3164 * <jk>private</jk> DateFormat <jf>format</jf> = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>); 3165 * 3166 * <ja>@Override</ja> 3167 * <jk>public</jk> String swap(BeanSession <jv>session</jv>, Date <jv>date</jv>) { 3168 * <jk>return</jk> <jf>format</jf>.format(<jv>date</jv>); 3169 * } 3170 * 3171 * <ja>@Override</ja> 3172 * <jk>public</jk> Date unswap(BeanSession <jv>session</jv>, String <jv>string</jv>, ClassMeta <jv>hint</jv>) <jk>throws</jk> Exception { 3173 * <jk>return</jk> <jf>format</jf>.parse(<jv>string</jv>); 3174 * } 3175 * } 3176 * 3177 * <jc>// Sample bean with a Date field.</jc> 3178 * <jk>public class</jk> MyBean { 3179 * <jk>public</jk> Date <jf>date</jf> = <jk>new</jk> Date(112, 2, 3, 4, 5, 6); 3180 * } 3181 * 3182 * <jc>// Create a serializer that uses our date swap.</jc> 3183 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3184 * .<jsm>create</jsm>() 3185 * .swaps(MyDateSwap.<jk>class</jk>) 3186 * .build(); 3187 * 3188 * <jc>// Produces: {"date":"2012-03-03T04:05:06-0500"}</jc> 3189 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 3190 * 3191 * <jc>// Create a serializer that uses our date swap.</jc> 3192 * ReaderParser <jv>parser</jv> = JsonParser 3193 * .<jsm>create</jsm>() 3194 * .swaps(MyDateSwap.<jk>class</jk>) 3195 * .build(); 3196 * 3197 * <jc>// Use our parser to parse a bean.</jc> 3198 * MyBean <jv>bean</jv> = <jv>parser</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>); 3199 * </p> 3200 * 3201 * <h5 class='section'>Notes:</h5><ul> 3202 * <li class='note'>The {@link Swap @Swap} annotation can also be used on classes to identify swaps for the class. 3203 * <li class='note'>The {@link Swap @Swap} annotation can also be used on bean methods and fields to identify swaps for values of those bean properties. 3204 * </ul> 3205 * 3206 * @param values 3207 * The values to add to this setting. 3208 * <br>Values can consist of any of the following types: 3209 * <ul> 3210 * <li>Any subclass of {@link ObjectSwap}. 3211 * <li>Any surrogate class. A shortcut for defining a {@link SurrogateSwap}. 3212 * <li>Any array/collection/stream of the objects above. 3213 * </ul> 3214 * <br>Cannot be <jk>null</jk>. 3215 * @return This object. 3216 */ 3217 public Builder swaps(Object...values) { 3218 assertArgNoNulls("values", values); 3219 swaps().addAll(0, accumulate(values)); 3220 return this; 3221 } 3222 3223 /** 3224 * <i><l>Context</l> configuration property: </i> TimeZone. 3225 * 3226 * <p> 3227 * Specifies the default time zone for serializer and parser sessions when not specified via {@link BeanSession.Builder#timeZone(TimeZone)}. 3228 * Typically used for POJO swaps that need to deal with timezones such as swaps that convert <l>Date</l> and <l>Calendar</l> 3229 * objects to strings by accessing it via the session passed into the {@link ObjectSwap#swap(BeanSession, Object)} and 3230 * {@link ObjectSwap#unswap(BeanSession, Object, ClassMeta, String)} methods. 3231 * 3232 * <h5 class='section'>Example:</h5> 3233 * <p class='bjava'> 3234 * <jc>// Define a POJO swap that skips serializing beans if the time zone is GMT.</jc> 3235 * <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap<MyBean> { 3236 * <ja>@Override</ja> 3237 * <jk>public</jk> String swap(BeanSession <jv>session</jv>, MyBean <jv>bean</jv>) <jk>throws</jk> Exception { 3238 * <jk>if</jk> (<jv>session</jv>.getTimeZone().equals(TimeZone.<jsf>GMT</jsf>)) 3239 * <jk>return null</jk>; 3240 * <jk>return</jk> <jv>bean</jv>.toString(); 3241 * } 3242 * } 3243 * 3244 * <jc>// Create a serializer that uses GMT if the timezone is not specified in the session args.</jc> 3245 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3246 * .<jsm>create</jsm>() 3247 * .timeZone(TimeZone.<jsf>GMT</jsf>) 3248 * .build(); 3249 * </p> 3250 * 3251 * <h5 class='section'>See Also:</h5><ul> 3252 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#timeZone()} 3253 * <li class='jm'>{@link org.apache.juneau.BeanSession.Builder#timeZone(TimeZone)} 3254 * </ul> 3255 * 3256 * @param value The new value for this property. 3257 * <br>Can be <jk>null</jk> (timezone will not be set, defaults to system timezone). 3258 * @return This object. 3259 */ 3260 public Builder timeZone(TimeZone value) { 3261 timeZone = value; 3262 return this; 3263 } 3264 3265 @Override /* Overridden from Builder */ 3266 public Builder type(Class<? extends org.apache.juneau.Context> value) { 3267 assertArgNotNull("value", value); 3268 super.type(value); 3269 return this; 3270 } 3271 3272 /** 3273 * An identifying name for this class. 3274 * 3275 * <p> 3276 * The name is used to identify the class type during parsing when it cannot be inferred through reflection. 3277 * For example, if a bean property is of type <c>Object</c>, then the serializer will add the name to the 3278 * output so that the class can be determined during parsing. 3279 * 3280 * <p> 3281 * It is also used to specify element names in XML. 3282 * 3283 * <h5 class='section'>Example:</h5> 3284 * <p class='bjava'> 3285 * <jc>// Use _type='mybean' to identify this bean.</jc> 3286 * <jk>public class</jk> MyBean {...} 3287 * 3288 * <jc>// Create a serializer and specify the type name..</jc> 3289 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3290 * .<jsm>create</jsm>() 3291 * .typeName(MyBean.<jk>class</jk>, <js>"mybean"</js>) 3292 * .build(); 3293 * 3294 * <jc>// Produces: {"_type":"mybean",...}</jc> 3295 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 3296 * </p> 3297 * 3298 * <h5 class='section'>Notes:</h5><ul> 3299 * <li class='note'>Equivalent to the {@link Bean#typeName() Bean(typeName)} annotation. 3300 * </ul> 3301 * 3302 * <h5 class='section'>See Also:</h5><ul> 3303 * <li class='jc'>{@link Bean#typeName() Bean(typeName)} 3304 * <li class='jm'>{@link #beanDictionary(Class...)} 3305 * </ul> 3306 * 3307 * @param on 3308 * The class the type name is being defined on. 3309 * <br>Cannot be <jk>null</jk>. 3310 * @param value 3311 * The new value for this setting. 3312 * <br>Cannot be <jk>null</jk>. 3313 * @return This object. 3314 */ 3315 public Builder typeName(Class<?> on, String value) { 3316 assertArgNotNull("on", on); 3317 assertArgNotNull("value", value); 3318 return annotations(BeanAnnotation.create(on).typeName(value).build()); 3319 } 3320 3321 /** 3322 * Bean type property name. 3323 * 3324 * <p> 3325 * Same as {@link #typePropertyName(String)} except targets a specific bean class instead of globally. 3326 * 3327 * <h5 class='section'>Example:</h5> 3328 * <p class='bjava'> 3329 * <jc>// POJOs with @Bean(name) annotations.</jc> 3330 * <ja>@Bean</ja>(typeName=<js>"foo"</js>) 3331 * <jk>public class</jk> Foo {...} 3332 * <ja>@Bean</ja>(typeName=<js>"bar"</js>) 3333 * <jk>public class</jk> Bar {...} 3334 * 3335 * <jc>// A bean with a field with an indeterminate type.</jc> 3336 * <jk>public class</jk> MyBean { 3337 * <jk>public</jk> Object <jf>mySimpleField</jf>; 3338 * } 3339 * 3340 * <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc> 3341 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3342 * .<jsm>create</jsm>() 3343 * .typePropertyName(MyBean.<jk>class</jk>, <js>"t"</js>) 3344 * .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>) 3345 * .build(); 3346 * 3347 * <jc>// Produces "{mySimpleField:{t:'foo',...}}".</jc> 3348 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 3349 * </p> 3350 * 3351 * <h5 class='section'>See Also:</h5><ul> 3352 * <li class='ja'>{@link Bean#typePropertyName() Bean(typePropertyName)} 3353 * </ul> 3354 * 3355 * @param on The class the type property name applies to. 3356 * <br>Cannot be <jk>null</jk>. 3357 * @param value 3358 * The new value for this setting. 3359 * <br>The default is <js>"_type"</js>. 3360 * <br>Cannot be <jk>null</jk>. 3361 * @return This object. 3362 */ 3363 public Builder typePropertyName(Class<?> on, String value) { 3364 assertArgNotNull("on", on); 3365 assertArgNotNull("value", value); 3366 return annotations(BeanAnnotation.create(on).typePropertyName(value).build()); 3367 } 3368 3369 /** 3370 * Bean type property name. 3371 * 3372 * <p> 3373 * This specifies the name of the bean property used to store the dictionary name of a bean type so that the 3374 * parser knows the data type to reconstruct. 3375 * 3376 * <h5 class='section'>Example:</h5> 3377 * <p class='bjava'> 3378 * <jc>// POJOs with @Bean(name) annotations.</jc> 3379 * <ja>@Bean</ja>(typeName=<js>"foo"</js>) 3380 * <jk>public class</jk> Foo {...} 3381 * <ja>@Bean</ja>(typeName=<js>"bar"</js>) 3382 * <jk>public class</jk> Bar {...} 3383 * 3384 * <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc> 3385 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3386 * .<jsm>create</jsm>() 3387 * .typePropertyName(<js>"t"</js>) 3388 * .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>) 3389 * .build(); 3390 * 3391 * <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc> 3392 * ReaderParser <jv>parser</jv> = JsonParser 3393 * .<jsm>create</jsm>() 3394 * .typePropertyName(<js>"t"</js>) 3395 * .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>) 3396 * .build(); 3397 * 3398 * <jc>// A bean with a field with an indeterminate type.</jc> 3399 * <jk>public class</jk> MyBean { 3400 * <jk>public</jk> Object <jf>mySimpleField</jf>; 3401 * } 3402 * 3403 * <jc>// Produces "{mySimpleField:{t:'foo',...}}".</jc> 3404 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 3405 * 3406 * <jc>// Parse bean.</jc> 3407 * MyBean <jv>bean</jv> = <jv>parser</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>); 3408 * </p> 3409 * 3410 * <h5 class='section'>See Also:</h5><ul> 3411 * <li class='ja'>{@link org.apache.juneau.annotation.Bean#typePropertyName()} 3412 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#typePropertyName()} 3413 * </ul> 3414 * 3415 * @param value 3416 * The new value for this setting. 3417 * <br>The default is <js>"_type"</js>. 3418 * <br>Cannot be <jk>null</jk>. 3419 * @return This object. 3420 */ 3421 public Builder typePropertyName(String value) { 3422 typePropertyName = assertArgNotNull("value", value); 3423 return this; 3424 } 3425 3426 /** 3427 * Use enum names. 3428 * 3429 * <p> 3430 * When enabled, enums are always serialized by name, not using {@link Object#toString()}. 3431 * 3432 * <h5 class='section'>Example:</h5> 3433 * <p class='bjava'> 3434 * <jc>// Create a serializer with debug enabled.</jc> 3435 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3436 * .<jsm>create</jsm>() 3437 * .useEnumNames() 3438 * .build(); 3439 * 3440 * <jc>// Enum with overridden toString().</jc> 3441 * <jc>// Will be serialized as ONE/TWO/THREE even though there's a toString() method.</jc> 3442 * <jk>public enum</jk> Option { 3443 * <jsf>ONE</jsf>(1), 3444 * <jsf>TWO</jsf>(2), 3445 * <jsf>THREE</jsf>(3); 3446 * 3447 * <jk>private int</jk> <jf>value</jf>; 3448 * 3449 * Option(<jk>int</jk> <jv>value</jv>) { 3450 * <jk>this</jk>.<jf>value</jf> = <jv>value</jv>; 3451 * } 3452 * 3453 * <ja>@Override</ja> 3454 * <jk>public</jk> String toString() { 3455 * <jk>return</jk> String.<jsm>valueOf</jsm>(<jf>value</jf>); 3456 * } 3457 * } 3458 * </p> 3459 * 3460 * @return This object. 3461 */ 3462 public Builder useEnumNames() { 3463 return useEnumNames(true); 3464 } 3465 3466 /** 3467 * Same as {@link #useEnumNames()} but allows you to explicitly specify the value. 3468 * 3469 * @param value The value for this setting. 3470 * @return This object. 3471 */ 3472 public Builder useEnumNames(boolean value) { 3473 useEnumNames = value; 3474 return this; 3475 } 3476 3477 /** 3478 * Use Java Introspector. 3479 * 3480 * <p> 3481 * Using the built-in Java bean introspector will not pick up fields or non-standard getters/setters. 3482 * <br>Most {@link Bean @Bean} annotations will be ignored. 3483 * 3484 * <h5 class='section'>Example:</h5> 3485 * <p class='bjava'> 3486 * <jc>// Create a serializer that only uses the built-in java bean introspector for finding properties.</jc> 3487 * WriterSerializer <jv>serializer</jv> = JsonSerializer 3488 * .<jsm>create</jsm>() 3489 * .useJavaBeanIntrospector() 3490 * .build(); 3491 * </p> 3492 * 3493 * @return This object. 3494 */ 3495 public Builder useJavaBeanIntrospector() { 3496 return useJavaBeanIntrospector(true); 3497 } 3498 3499 /** 3500 * Same as {@link #useJavaBeanIntrospector()} but allows you to explicitly specify the value. 3501 * 3502 * @param value The value for this setting. 3503 * @return This object. 3504 */ 3505 public Builder useJavaBeanIntrospector(boolean value) { 3506 useJavaBeanIntrospector = value; 3507 return this; 3508 } 3509 } 3510 3511 /* 3512 * The default package pattern exclusion list. 3513 * Any beans in packages in this list will not be considered beans. 3514 */ 3515 // @formatter:off 3516 private static final List<String> DEFAULT_NOTBEAN_PACKAGES = l( 3517 "java.lang", 3518 "java.lang.annotation", 3519 "java.lang.ref", 3520 "java.lang.reflect", 3521 "java.io", 3522 "java.net", 3523 "java.nio.*", 3524 "java.util.*" 3525 ); 3526 // @formatter:on 3527 3528 /* 3529 * The default bean class exclusion list. 3530 * Anything in this list will not be considered beans. 3531 */ 3532 // @formatter:off 3533 private static final List<ClassInfo> DEFAULT_NOTBEAN_CLASSES = l( 3534 info(Map.class), 3535 info(Collection.class), 3536 info(Reader.class), 3537 info(Writer.class), 3538 info(InputStream.class), 3539 info(OutputStream.class), 3540 info(Throwable.class) 3541 ); 3542 // @formatter:on 3543 3544 /** Default config. All default settings. */ 3545 public static final BeanContext DEFAULT = create().build(); 3546 3547 /** Default config. All default settings except sort bean properties. */ 3548 public static final BeanContext DEFAULT_SORTED = create().sortProperties().build(); 3549 3550 /** Default reusable unmodifiable session. Can be used to avoid overhead of creating a session (for creating BeanMaps for example).*/ 3551 public static final BeanSession DEFAULT_SESSION = DEFAULT.createSession().unmodifiable().build(); 3552 3553 /** 3554 * Creates a new builder for this object. 3555 * 3556 * @return A new builder. 3557 */ 3558 public static Builder create() { 3559 return new Builder(); 3560 } 3561 3562 /** 3563 * Checks if the specified class should be cached. 3564 * 3565 * <p> 3566 * Generated classes (proxies, lambda expressions, etc.) shouldn't be cacheable to prevent 3567 * needlessly filling up the cache. 3568 * 3569 * @param c The class to check. 3570 * @return <jk>true</jk> if the class should be cached. 3571 */ 3572 private static boolean isCacheable(Class<?> c) { 3573 var n = c.getName(); 3574 var x = n.charAt(n.length() - 1); // All generated classes appear to end with digits. 3575 if (x >= '0' && x <= '9') { 3576 if (n.indexOf("$$") != -1 || n.startsWith("sun") || n.startsWith("com.sun") || n.indexOf("$Proxy") != -1) 3577 return false; 3578 } 3579 return true; 3580 } 3581 3582 private final OptionalSupplier<WriterSerializer> beanToStringSerializer; 3583 private final BeanRegistry beanRegistry; 3584 private final BeanSession defaultSession; 3585 private final boolean beanMapPutReturnsOldValue; 3586 private final boolean beansRequireDefaultConstructor; 3587 private final boolean beansRequireSerializable; 3588 private final boolean beansRequireSettersForGetters; 3589 private final boolean beansRequireSomeProperties; 3590 private final boolean findFluentSetters; 3591 private final boolean ignoreInvocationExceptionsOnGetters; 3592 private final boolean ignoreInvocationExceptionsOnSetters; 3593 private final boolean ignoreMissingSetters; 3594 private final boolean ignoreTransientFields; 3595 private final boolean ignoreUnknownBeanProperties; 3596 private final boolean ignoreUnknownEnumValues; 3597 private final boolean ignoreUnknownNullBeanProperties; 3598 private final boolean sortProperties; 3599 private final boolean useEnumNames; 3600 private final boolean useInterfaceProxies; 3601 private final boolean useJavaBeanIntrospector; 3602 private final Class<? extends PropertyNamer> propertyNamer; 3603 private final ClassMeta<Object> cmObject; // Reusable ClassMeta that represents general Objects. 3604 private final ClassMeta<String> cmString; // Reusable ClassMeta that represents general Strings. 3605 private final HashKey hashKey; 3606 private final List<ClassInfo> beanDictionary; 3607 private final List<ClassInfo> notBeanClasses; 3608 private final List<Object> swaps; 3609 private final List<String> notBeanPackages; 3610 private final Locale locale; 3611 private final Cache<Class,ClassMeta> cmCache; 3612 private final MediaType mediaType; 3613 private final List<ObjectSwap<?,?>> objectSwaps; 3614 private final PropertyNamer propertyNamerBean; 3615 private final String typePropertyName; 3616 private final Set<String> notBeanPackageNames; 3617 private final List<String> notBeanPackagePrefixes; 3618 private final TimeZone timeZone; 3619 private final Visibility beanClassVisibility; 3620 private final Visibility beanConstructorVisibility; 3621 private final Visibility beanFieldVisibility; 3622 private final Visibility beanMethodVisibility; 3623 3624 /** 3625 * Constructor. 3626 * 3627 * @param builder The builder for this object. 3628 */ 3629 public BeanContext(Builder builder) { 3630 super(builder); 3631 3632 beanClassVisibility = builder.beanClassVisibility; 3633 beanConstructorVisibility = builder.beanConstructorVisibility; 3634 beanDictionary = u(copyOf(builder.beanDictionary)); 3635 beanFieldVisibility = builder.beanFieldVisibility; 3636 beanMapPutReturnsOldValue = builder.beanMapPutReturnsOldValue; 3637 beanMethodVisibility = builder.beanMethodVisibility; 3638 beansRequireDefaultConstructor = builder.beansRequireDefaultConstructor; 3639 beansRequireSerializable = builder.beansRequireSerializable; 3640 beansRequireSettersForGetters = builder.beansRequireSettersForGetters; 3641 beansRequireSomeProperties = ! builder.disableBeansRequireSomeProperties; 3642 findFluentSetters = builder.findFluentSetters; 3643 hashKey = builder.hashKey(); 3644 ignoreInvocationExceptionsOnGetters = builder.ignoreInvocationExceptionsOnGetters; 3645 ignoreInvocationExceptionsOnSetters = builder.ignoreInvocationExceptionsOnSetters; 3646 ignoreMissingSetters = ! builder.disableIgnoreMissingSetters; 3647 ignoreTransientFields = ! builder.disableIgnoreTransientFields; 3648 ignoreUnknownBeanProperties = builder.ignoreUnknownBeanProperties; 3649 ignoreUnknownEnumValues = builder.ignoreUnknownEnumValues; 3650 ignoreUnknownNullBeanProperties = ! builder.disableIgnoreUnknownNullBeanProperties; 3651 locale = opt(builder.locale).orElse(Locale.getDefault()); 3652 mediaType = builder.mediaType; 3653 notBeanPackages = u(new ArrayList<>(builder.notBeanPackages)); 3654 propertyNamer = nn(builder.propertyNamer) ? builder.propertyNamer : BasicPropertyNamer.class; 3655 sortProperties = builder.sortProperties; 3656 swaps = u(copyOf(builder.swaps)); 3657 timeZone = builder.timeZone; 3658 typePropertyName = opt(builder.typePropertyName).orElse("_type"); 3659 useEnumNames = builder.useEnumNames; 3660 useInterfaceProxies = ! builder.disableInterfaceProxies; 3661 useJavaBeanIntrospector = builder.useJavaBeanIntrospector; 3662 3663 var builderNotBeanClasses = new ArrayList<>(builder.notBeanClasses); 3664 notBeanClasses = builderNotBeanClasses.isEmpty() ? DEFAULT_NOTBEAN_CLASSES : Stream.concat(builderNotBeanClasses.stream(), DEFAULT_NOTBEAN_CLASSES.stream()).distinct().toList(); 3665 3666 List<String> _notBeanPackages = notBeanPackages.isEmpty() ? DEFAULT_NOTBEAN_PACKAGES : Stream.concat(notBeanPackages.stream(), DEFAULT_NOTBEAN_PACKAGES.stream()).toList(); 3667 LinkedHashSet<String> _notBeanPackageNames = _notBeanPackages.stream().filter(x -> ! x.endsWith(".*")).collect(Collectors.toCollection(LinkedHashSet::new)); 3668 notBeanPackageNames = u(_notBeanPackageNames); 3669 notBeanPackagePrefixes = _notBeanPackages.stream().filter(x -> x.endsWith(".*")).map(x -> x.substring(0, x.length() - 2)).toList(); 3670 3671 propertyNamerBean = safe(()->propertyNamer.getDeclaredConstructor().newInstance()); 3672 3673 var _objectSwaps = new LinkedList<ObjectSwap<?,?>>(); 3674 swaps.forEach(x -> { 3675 if (x instanceof ObjectSwap<?,?> os) { 3676 _objectSwaps.add(os); 3677 } else { 3678 var ci = info((Class<?>)x); 3679 if (ci.isChildOf(ObjectSwap.class)) 3680 _objectSwaps.add(BeanCreator.of(ObjectSwap.class).type(ci).run()); 3681 else if (ci.isChildOf(Surrogate.class)) 3682 _objectSwaps.addAll(SurrogateSwap.findObjectSwaps(ci.inner(), this)); 3683 else 3684 throw rex("Invalid class {0} specified in BeanContext.swaps property. Must be a subclass of ObjectSwap or Surrogate.", cn(ci.inner())); 3685 } 3686 }); 3687 objectSwaps = u(_objectSwaps); 3688 3689 cmCache = Cache.<Class,ClassMeta>create().supplier(type -> new ClassMeta<>(type, this)).build(); 3690 cmString = cmCache.get(String.class); 3691 cmObject = cmCache.get(Object.class); 3692 3693 beanRegistry = new BeanRegistry(this, null, list()); 3694 defaultSession = createSession().unmodifiable().build(); 3695 beanToStringSerializer = mem(() -> JsonSerializer.create().beanContext(this).sq().simpleAttrs().build()); 3696 } 3697 3698 /** 3699 * Converts the specified value to the specified class type. 3700 * 3701 * <p> 3702 * This is a shortcut for the following code: <c>createSession().build().convertToType(<jv>value</jv>, <jv>type</jv>);</c> 3703 * 3704 * @param <T> The class type to convert the value to. 3705 * @param value The value to convert. 3706 * @param type The class type to convert the value to. 3707 * @throws InvalidDataConversionException If the specified value cannot be converted to the specified type. 3708 * @return The converted value. 3709 * @see BeanSession#convertToType(Object, Class) 3710 */ 3711 public final <T> T convertToType(Object value, Class<T> type) throws InvalidDataConversionException { 3712 return defaultSession.convertToType(value, type); 3713 } 3714 3715 @Override /* Overridden from Context */ 3716 public Builder copy() { 3717 return new Builder(this); 3718 } 3719 3720 @Override /* Overridden from Context */ 3721 public BeanSession.Builder createSession() { 3722 return BeanSession.create(this); 3723 } 3724 3725 /** 3726 * Minimum bean class visibility. 3727 * 3728 * @see BeanContext.Builder#beanClassVisibility(Visibility) 3729 * @return 3730 * Classes are not considered beans unless they meet the minimum visibility requirements. 3731 */ 3732 public final Visibility getBeanClassVisibility() { return beanClassVisibility; } 3733 3734 /** 3735 * Minimum bean constructor visibility. 3736 * 3737 * @see BeanContext.Builder#beanConstructorVisibility(Visibility) 3738 * @return 3739 * Only look for constructors with this specified minimum visibility. 3740 */ 3741 public final Visibility getBeanConstructorVisibility() { return beanConstructorVisibility; } 3742 3743 /** 3744 * Bean dictionary. 3745 * 3746 * @see BeanContext.Builder#beanDictionary() 3747 * @return 3748 * The list of classes that make up the bean dictionary in this bean context. 3749 * <br>Never <jk>null</jk>. 3750 * <br>List is unmodifiable. 3751 */ 3752 public final List<ClassInfo> getBeanDictionary() { return beanDictionary; } 3753 3754 /** 3755 * Minimum bean field visibility. 3756 * 3757 * 3758 * @see BeanContext.Builder#beanFieldVisibility(Visibility) 3759 * @return 3760 * Only look for bean fields with this specified minimum visibility. 3761 */ 3762 public final Visibility getBeanFieldVisibility() { return beanFieldVisibility; } 3763 3764 /** 3765 * Returns the {@link BeanMeta} class for the specified class. 3766 * 3767 * @param <T> The class type to get the meta-data on. 3768 * @param c The class to get the meta-data on. 3769 * <br>Cannot be <jk>null</jk>. 3770 * @return 3771 * The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class is not a bean per the settings on 3772 * this context. 3773 */ 3774 public final <T> BeanMeta<T> getBeanMeta(Class<T> c) { 3775 assertArgNotNull("c", c); 3776 return getClassMeta(c).getBeanMeta(); 3777 } 3778 3779 /** 3780 * Minimum bean method visibility. 3781 * 3782 * @see BeanContext.Builder#beanMethodVisibility(Visibility) 3783 * @return 3784 * Only look for bean methods with this specified minimum visibility. 3785 */ 3786 public final Visibility getBeanMethodVisibility() { return beanMethodVisibility; } 3787 3788 3789 /** 3790 * Bean type property name. 3791 * 3792 * @see BeanContext.Builder#typePropertyName(String) 3793 * @return 3794 * The name of the bean property used to store the dictionary name of a bean type so that the parser knows the data type to reconstruct. 3795 */ 3796 public final String getBeanTypePropertyName() { return typePropertyName; } 3797 3798 /** 3799 * Construct a {@code ClassMeta} wrapper around a {@link Class} object. 3800 * 3801 * @param <T> The class type being wrapped. 3802 * @param type The class to resolve. 3803 * @return 3804 * If the class is not an array, returns a cached {@link ClassMeta} object. 3805 * Otherwise, returns a new {@link ClassMeta} object every time. 3806 */ 3807 public final <T> ClassMeta<T> getClassMeta(Class<T> type) { 3808 // Non-cacheable classes (proxies, generated classes) should not be cached 3809 if (! isCacheable(type)) 3810 return new ClassMeta<>(type, this); 3811 return cmCache.get(type); 3812 } 3813 3814 /** 3815 * Used to resolve <c>ClassMetas</c> of type <c>Collection</c> and <c>Map</c> that have 3816 * <c>ClassMeta</c> values that themselves could be collections or maps. 3817 * 3818 * <p> 3819 * <c>Collection</c> meta objects are assumed to be followed by zero or one meta objects indicating the element type. 3820 * 3821 * <p> 3822 * <c>Map</c> meta objects are assumed to be followed by zero or two meta objects indicating the key and value types. 3823 * 3824 * <p> 3825 * The array can be arbitrarily long to indicate arbitrarily complex data structures. 3826 * 3827 * <h5 class='section'>Examples:</h5> 3828 * <ul> 3829 * <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type. 3830 * <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects. 3831 * <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings. 3832 * <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing 3833 * strings. 3834 * <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - 3835 * A linked-list containing linked-lists of strings. 3836 * <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values. 3837 * <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map 3838 * containing string keys/values. 3839 * <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> - 3840 * A map containing string keys and values of lists containing beans. 3841 * </ul> 3842 * 3843 * @param <T> 3844 * The class to resolve. 3845 * @param type 3846 * The class to resolve. 3847 * <br>Can be any of the following: {@link ClassMeta}, {@link ClassInfo}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 3848 * @param args 3849 * The type arguments of the class if it's a collection or map. 3850 * <br>Can be any of the following: {@link ClassMeta}, {@link ClassInfo}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 3851 * <br>Ignored if the main type is not a map or collection. 3852 * @return The resolved class meta. 3853 */ 3854 public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) { 3855 if (type == null) 3856 return null; 3857 var cm = (ClassMeta<T>)null; 3858 if (type instanceof Class type2) 3859 cm = getClassMeta(type2); 3860 else 3861 cm = resolveClassMeta(type, null); 3862 if (args.length == 0) 3863 return cm; 3864 var cma = new ClassMeta<?>[args.length + 1]; 3865 cma[0] = cm; 3866 for (var i = 0; i < length(args); i++) { 3867 var arg = (Type)Array.get(args, i); 3868 if (arg instanceof Class arg2) 3869 cma[i + 1] = getClassMeta(arg2); 3870 else 3871 cma[i + 1] = resolveClassMeta(arg, null); 3872 } 3873 return (ClassMeta<T>)getTypedClassMeta(cma, 0); 3874 } 3875 3876 /** 3877 * Shortcut for calling {@code getClassMeta(o.getClass())}. 3878 * 3879 * @param <T> The class of the object being passed in. 3880 * @param o The class to find the class type for. 3881 * <br>Cannot be <jk>null</jk>. 3882 * @return The ClassMeta object. 3883 */ 3884 public final <T> ClassMeta<T> getClassMetaForObject(T o) { 3885 assertArgNotNull("o", o); 3886 return (ClassMeta<T>)getClassMeta(o.getClass()); 3887 } 3888 3889 /** 3890 * Locale. 3891 * 3892 * @see BeanContext.Builder#locale(Locale) 3893 * @return 3894 * The default locale for serializer and parser sessions. 3895 */ 3896 public final Locale getDefaultLocale() { return locale; } 3897 3898 /** 3899 * Media type. 3900 * 3901 * @see BeanContext.Builder#mediaType(MediaType) 3902 * @return 3903 * The default media type value for serializer and parser sessions. 3904 */ 3905 public final MediaType getDefaultMediaType() { return mediaType; } 3906 3907 /** 3908 * Time zone. 3909 * 3910 * @see BeanContext.Builder#timeZone(TimeZone) 3911 * @return 3912 * The default timezone for serializer and parser sessions. 3913 */ 3914 public final TimeZone getDefaultTimeZone() { return timeZone; } 3915 3916 /** 3917 * Bean package exclusions. 3918 * 3919 * @see BeanContext.Builder#notBeanPackages(String...) 3920 * @return 3921 * The set of fully-qualified package names to exclude from being classified as beans. 3922 * <br>Never <jk>null</jk>. 3923 * <br>Set is unmodifiable. 3924 * <br>Backed by a {@link LinkedHashSet} to preserve insertion order. 3925 */ 3926 public final Set<String> getNotBeanPackagesNames() { return notBeanPackageNames; } 3927 3928 /** 3929 * Bean property namer. 3930 * 3931 * @see BeanContext.Builder#propertyNamer(Class) 3932 * @return 3933 * The interface used to calculate bean property names. 3934 */ 3935 public final PropertyNamer getPropertyNamer() { return propertyNamerBean; } 3936 3937 @Override /* Overridden from Context */ 3938 public BeanSession getSession() { return defaultSession; } 3939 3940 /** 3941 * Java object swaps. 3942 * 3943 * @see BeanContext.Builder#swaps(Class...) 3944 * @return 3945 * The list POJO swaps defined. 3946 * <br>Never <jk>null</jk>. 3947 * <br>List is unmodifiable. 3948 */ 3949 public final List<ObjectSwap<?,?>> getSwaps() { return objectSwaps; } 3950 3951 /** 3952 * Returns <jk>true</jk> if the specified bean context shares the same cache as this bean context. 3953 * 3954 * <p> 3955 * Useful for testing purposes. 3956 * 3957 * @param bc The bean context to compare to. 3958 * <br>Cannot be <jk>null</jk>. 3959 * @return <jk>true</jk> if the bean contexts have equivalent settings and thus share caches. 3960 */ 3961 public final boolean hasSameCache(BeanContext bc) { 3962 assertArgNotNull("bc", bc); 3963 return bc.getCmCache() == this.getCmCache(); 3964 } 3965 3966 /** 3967 * BeanMap.put() returns old property value. 3968 * 3969 * @see BeanContext.Builder#beanMapPutReturnsOldValue() 3970 * @return 3971 * <jk>true</jk> if the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property values. 3972 * <br>Otherwise, it returns <jk>null</jk>. 3973 */ 3974 public final boolean isBeanMapPutReturnsOldValue() { return beanMapPutReturnsOldValue; } 3975 3976 /** 3977 * Beans require no-arg constructors. 3978 * 3979 * @see BeanContext.Builder#beansRequireDefaultConstructor() 3980 * @return 3981 * <jk>true</jk> if a Java class must implement a default no-arg constructor to be considered a bean. 3982 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 3983 */ 3984 public final boolean isBeansRequireDefaultConstructor() { return beansRequireDefaultConstructor; } 3985 3986 /** 3987 * Beans require Serializable interface. 3988 * 3989 * @see BeanContext.Builder#beansRequireSerializable() 3990 * @return 3991 * <jk>true</jk> if a Java class must implement the {@link Serializable} interface to be considered a bean. 3992 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 3993 */ 3994 public final boolean isBeansRequireSerializable() { return beansRequireSerializable; } 3995 3996 /** 3997 * Beans require setters for getters. 3998 * 3999 * @see BeanContext.Builder#beansRequireSettersForGetters() 4000 * @return 4001 * <jk>true</jk> if only getters that have equivalent setters will be considered as properties on a bean. 4002 * <br>Otherwise, they are ignored. 4003 */ 4004 public final boolean isBeansRequireSettersForGetters() { return beansRequireSettersForGetters; } 4005 4006 /** 4007 * Beans require at least one property. 4008 * 4009 * @see BeanContext.Builder#disableBeansRequireSomeProperties() 4010 * @return 4011 * <jk>true</jk> if a Java class doesn't need to contain at least 1 property to be considered a bean. 4012 * <br>Otherwise, the bean is serialized as a string using the {@link Object#toString()} method. 4013 */ 4014 public final boolean isBeansRequireSomeProperties() { return beansRequireSomeProperties; } 4015 4016 /** 4017 * Find fluent setters. 4018 * 4019 * <h5 class='section'>Description:</h5> 4020 * <p> 4021 * 4022 * @see BeanContext.Builder#findFluentSetters() 4023 * @return 4024 * <jk>true</jk> if fluent setters are detected on beans. 4025 */ 4026 public final boolean isFindFluentSetters() { return findFluentSetters; } 4027 4028 /** 4029 * Ignore invocation errors on getters. 4030 * 4031 * @see BeanContext.Builder#ignoreInvocationExceptionsOnGetters() 4032 * @return 4033 * <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored. 4034 */ 4035 public final boolean isIgnoreInvocationExceptionsOnGetters() { return ignoreInvocationExceptionsOnGetters; } 4036 4037 /** 4038 * Ignore invocation errors on setters. 4039 * 4040 * @see BeanContext.Builder#ignoreInvocationExceptionsOnSetters() 4041 * @return 4042 * <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored. 4043 */ 4044 public final boolean isIgnoreInvocationExceptionsOnSetters() { return ignoreInvocationExceptionsOnSetters; } 4045 4046 /** 4047 * Silently ignore missing setters. 4048 * 4049 * @see BeanContext.Builder#disableIgnoreMissingSetters() 4050 * @return 4051 * <jk>true</jk> if trying to set a value on a bean property without a setter should throw a {@link BeanRuntimeException}. 4052 */ 4053 public final boolean isIgnoreMissingSetters() { return ignoreMissingSetters; } 4054 4055 /** 4056 * Ignore unknown properties. 4057 * 4058 * @see BeanContext.Builder#ignoreUnknownBeanProperties() 4059 * @return 4060 * <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored. 4061 * <br>Otherwise, a {@code RuntimeException} is thrown. 4062 */ 4063 public final boolean isIgnoreUnknownBeanProperties() { return ignoreUnknownBeanProperties; } 4064 4065 /** 4066 * Ignore unknown enum values. 4067 * 4068 * @see BeanContext.Builder#ignoreUnknownEnumValues() 4069 * @return 4070 * <jk>true</jk> if unknown enum values should be set as <jk>null</jk> instead of throwing an exception. 4071 */ 4072 public final boolean isIgnoreUnknownEnumValues() { return ignoreUnknownEnumValues; } 4073 4074 /** 4075 * Ignore unknown properties with null values. 4076 * 4077 * @see BeanContext.Builder#disableIgnoreUnknownNullBeanProperties() 4078 * @return 4079 * <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property should throw a {@link BeanRuntimeException}. 4080 */ 4081 public final boolean isIgnoreUnknownNullBeanProperties() { return ignoreUnknownNullBeanProperties; } 4082 4083 /** 4084 * Sort bean properties. 4085 * 4086 * @see BeanContext.Builder#sortProperties() 4087 * @return 4088 * <jk>true</jk> if all bean properties will be serialized and access in alphabetical order. 4089 */ 4090 public final boolean isSortProperties() { return sortProperties; } 4091 4092 /** 4093 * Use enum names. 4094 * 4095 * @see BeanContext.Builder#useEnumNames() 4096 * @return 4097 * <jk>true</jk> if enums are always serialized by name, not using {@link Object#toString()}. 4098 */ 4099 public final boolean isUseEnumNames() { return useEnumNames; } 4100 4101 /** 4102 * Use interface proxies. 4103 * 4104 * @see BeanContext.Builder#disableInterfaceProxies() 4105 * @return 4106 * <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an 4107 * {@link InvocationHandler} if there is no other way of instantiating them. 4108 */ 4109 public final boolean isUseInterfaceProxies() { return useInterfaceProxies; } 4110 4111 /** 4112 * Use Java Introspector. 4113 * 4114 * @see BeanContext.Builder#useJavaBeanIntrospector() 4115 * @return 4116 * <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection. 4117 */ 4118 public final boolean isUseJavaBeanIntrospector() { return useJavaBeanIntrospector; } 4119 4120 /** 4121 * Creates a new {@link BeanMap} object (a modifiable {@link Map}) of the given class with uninitialized 4122 * property values. 4123 * 4124 * <p> 4125 * This is a shortcut for the following code: <c>createSession().build().newBeanMap(<jv>_class</jv>);</c> 4126 * 4127 * <h5 class='section'>Example:</h5> 4128 * <p class='bjava'> 4129 * <jc>// Construct a new bean map wrapped around a new Person object</jc> 4130 * BeanMap<Person> <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.newBeanMap(Person.<jk>class</jk>); 4131 * </p> 4132 * 4133 * @param <T> The class of the object being wrapped. 4134 * @param c The name of the class to create a new instance of. 4135 * <br>Cannot be <jk>null</jk>. 4136 * @return A new instance of the class. 4137 * @see BeanSession#newBeanMap(Class) 4138 */ 4139 public <T> BeanMap<T> newBeanMap(Class<T> c) { 4140 assertArgNotNull("c", c); 4141 return defaultSession.newBeanMap(c); 4142 } 4143 4144 /** 4145 * Wraps an object inside a {@link BeanMap} object (a modifiable {@link Map}). 4146 * 4147 * <p> 4148 * This is a shortcut for the following code: <c>createSession().build().toBeanMap(<jv>object</jv>);</c> 4149 * 4150 * <h5 class='section'>Example:</h5> 4151 * <p class='bjava'> 4152 * <jc>// Construct a bean map around a bean instance</jc> 4153 * BeanMap<Person> <jv>beanMap</jv> = BeanContext.<jsf>DEFAULT</jsf>.toBeanMap(<jk>new</jk> Person()); 4154 * </p> 4155 * 4156 * @param <T> The class of the object being wrapped. 4157 * @param object The object to wrap in a map interface. 4158 * <br>Cannot be <jk>null</jk>. 4159 * @return The wrapped object. 4160 * @see BeanSession#toBeanMap(Object) 4161 */ 4162 public <T> BeanMap<T> toBeanMap(T object) { 4163 assertArgNotNull("object", object); 4164 return defaultSession.toBeanMap(object); 4165 } 4166 4167 /** 4168 * Returns the lookup table for resolving bean types by name. 4169 * 4170 * @return The lookup table for resolving bean types by name. 4171 */ 4172 protected final BeanRegistry getBeanRegistry() { return beanRegistry; } 4173 4174 /** 4175 * Returns the serializer to use for serializing beans when using the {@link BeanSession#convertToType(Object, Class)} 4176 * and related methods. 4177 * 4178 * @return The serializer. May be <jk>null</jk> if all initialization has occurred. 4179 */ 4180 protected WriterSerializer getBeanToStringSerializer() { 4181 return beanToStringSerializer.get(); 4182 } 4183 4184 /** 4185 * Class metadata cache. 4186 * 4187 * @return The class metadata cache. 4188 */ 4189 protected final Cache<Class,ClassMeta> getCmCache() { return cmCache; } 4190 4191 4192 /** 4193 * Hash key. 4194 * 4195 * @return The hash key. 4196 */ 4197 protected final HashKey getHashKey() { return hashKey; } 4198 4199 /** 4200 * Locale. 4201 * 4202 * @return The locale. 4203 */ 4204 protected final Locale getLocale() { return locale; } 4205 4206 /** 4207 * Media type. 4208 * 4209 * @return The media type. 4210 */ 4211 protected final MediaType getMediaType() { return mediaType; } 4212 4213 /** 4214 * Bean class exclusions. 4215 * 4216 * @see BeanContext.Builder#notBeanClasses(ClassInfo...) 4217 * @return 4218 * The list of classes that are explicitly not beans. 4219 * <br>Never <jk>null</jk>. 4220 * <br>List is unmodifiable. 4221 */ 4222 protected final List<ClassInfo> getNotBeanClasses() { return notBeanClasses; } 4223 4224 /** 4225 * Time zone. 4226 * 4227 * @return The time zone. 4228 */ 4229 protected final TimeZone getTimeZone() { return timeZone; } 4230 4231 /** 4232 * Ignore transient fields. 4233 * 4234 * @see BeanContext.Builder#disableIgnoreTransientFields() 4235 * @return 4236 * <jk>true</jk> if fields and methods marked as transient should not be ignored. 4237 */ 4238 protected final boolean isIgnoreTransientFields() { return ignoreTransientFields; } 4239 4240 /** 4241 * Determines whether the specified class is ignored as a bean class based on the various exclusion parameters 4242 * specified on this context class. 4243 * 4244 * @param ci The class info being tested. 4245 * @return <jk>true</jk> if the specified class matches any of the exclusion parameters. 4246 */ 4247 protected final boolean isNotABean(ClassInfo ci) { 4248 if (ci.isArray() || ci.isPrimitive() || ci.isEnum() || ci.isAnnotation()) 4249 return true; 4250 var p = ci.getPackage(); 4251 if (nn(p)) { 4252 var pn = p.getName(); 4253 for (var p2 : notBeanPackageNames) 4254 if (pn.equals(p2)) 4255 return true; 4256 for (var p2 : notBeanPackagePrefixes) 4257 if (pn.startsWith(p2)) 4258 return true; 4259 } 4260 for (var exclude : notBeanClasses) 4261 if (ci.isChildOf(exclude)) 4262 return true; 4263 return false; 4264 } 4265 4266 /** 4267 * Returns a reusable {@link ClassMeta} representation for the class <c>Object</c>. 4268 * 4269 * <p> 4270 * This <c>ClassMeta</c> is often used to represent "any object type" when an object type is not known. 4271 * 4272 * <p> 4273 * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to 4274 * avoid a hashmap lookup. 4275 * 4276 * @return The {@link ClassMeta} object associated with the <c>Object</c> class. 4277 */ 4278 protected final ClassMeta<Object> object() { 4279 return cmObject; 4280 } 4281 4282 @Override /* Overridden from Context */ 4283 protected FluentMap<String,Object> properties() { 4284 return super.properties() 4285 .a("beanClassVisibility", beanClassVisibility) 4286 .a("beanConstructorVisibility", beanConstructorVisibility) 4287 .a("beanDictionary", beanDictionary) 4288 .a("beanFieldVisibility", beanFieldVisibility) 4289 .a("beanMethodVisibility", beanMethodVisibility) 4290 .a("beansRequireDefaultConstructor", beansRequireDefaultConstructor) 4291 .a("beansRequireSerializable", beansRequireSerializable) 4292 .a("beansRequireSettersForGetters", beansRequireSettersForGetters) 4293 .a("beansRequireSomeProperties", beansRequireSomeProperties) 4294 .a("id", System.identityHashCode(this)) 4295 .a("ignoreInvocationExceptionsOnGetters", ignoreInvocationExceptionsOnGetters) 4296 .a("ignoreInvocationExceptionsOnSetters", ignoreInvocationExceptionsOnSetters) 4297 .a("ignoreTransientFields", ignoreTransientFields) 4298 .a("ignoreUnknownBeanProperties", ignoreUnknownBeanProperties) 4299 .a("ignoreUnknownNullBeanProperties", ignoreUnknownNullBeanProperties) 4300 .a("notBeanClasses", notBeanClasses) 4301 .a("notBeanPackageNames", notBeanPackageNames) 4302 .a("notBeanPackagePrefixes", notBeanPackagePrefixes) 4303 .a("sortProperties", sortProperties) 4304 .a("swaps", swaps) 4305 .a("useEnumNames", useEnumNames) 4306 .a("useInterfaceProxies", useInterfaceProxies) 4307 .a("useJavaBeanIntrospector", useJavaBeanIntrospector); 4308 } 4309 4310 /** 4311 * Used for determining the class type on a method or field where a {@code @Beanp} annotation may be present. 4312 * 4313 * @param <T> The class type we're wrapping. 4314 * @param p The property annotation info on the type if there is one. 4315 * @param ci The class info for the type. 4316 * @param typeVarImpls 4317 * Contains known resolved type parameters on the specified class so that we can result 4318 * {@code ParameterizedTypes} and {@code TypeVariables}. 4319 * Can be <jk>null</jk> if the information is not known. 4320 * @return The new {@code ClassMeta} object wrapped around the type. 4321 */ 4322 protected final <T> ClassMeta<T> resolveClassMeta(AnnotationInfo<Beanp> p, ClassInfo ci, TypeVariables typeVarImpls) { 4323 var cm = resolveClassMeta(ci, typeVarImpls); 4324 var cm2 = cm; 4325 4326 if (nn(p)) { 4327 var beanp = p.inner(); 4328 4329 if (isNotVoid(beanp.type())) 4330 cm2 = resolveClassMeta(beanp.type(), typeVarImpls); 4331 4332 if (cm2.isMap()) { 4333 var pParams = (beanp.params().length == 0 ? a(Object.class, Object.class) : beanp.params()); 4334 if (pParams.length != 2) 4335 throw rex("Invalid number of parameters specified for Map (must be 2): {0}", pParams.length); 4336 var keyType = resolveType(pParams[0], cm2.getKeyType(), cm.getKeyType()); 4337 var valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType()); 4338 if (keyType.isObject() && valueType.isObject()) 4339 return cm2; 4340 return new ClassMeta<>(cm2, keyType, valueType, null); 4341 } 4342 4343 if (cm2.isCollection() || cm2.isOptional()) { 4344 var pParams = (beanp.params().length == 0 ? a(Object.class) : beanp.params()); 4345 if (pParams.length != 1) 4346 throw rex("Invalid number of parameters specified for {1} (must be 1): {0}", pParams.length, (cm2.isCollection() ? "Collection" : cm2.isOptional() ? "Optional" : "Array")); 4347 var elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType()); 4348 if (elementType.isObject()) 4349 return cm2; 4350 return new ClassMeta<>(cm2, null, null, elementType); 4351 } 4352 4353 return cm2; 4354 } 4355 4356 return cm; 4357 } 4358 4359 /** 4360 * Returns a reusable {@link ClassMeta} representation for the class <c>String</c>. 4361 * 4362 * <p> 4363 * This <c>ClassMeta</c> is often used to represent key types in maps. 4364 * 4365 * <p> 4366 * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to 4367 * avoid a hashmap lookup. 4368 * 4369 * @return The {@link ClassMeta} object associated with the <c>String</c> class. 4370 */ 4371 protected final ClassMeta<String> string() { 4372 return cmString; 4373 } 4374 4375 final ClassMeta[] findParameters(Type o, Class c) { 4376 if (o == null) 4377 o = c; 4378 4379 // Loop until we find a ParameterizedType 4380 if (! (o instanceof ParameterizedType)) { 4381 loop: do { 4382 o = c.getGenericSuperclass(); 4383 if (o instanceof ParameterizedType) 4384 break loop; 4385 for (var t : c.getGenericInterfaces()) { 4386 o = t; 4387 if (o instanceof ParameterizedType) 4388 break loop; 4389 } 4390 c = c.getSuperclass(); 4391 } while (nn(c)); 4392 } 4393 4394 if (o instanceof ParameterizedType o2) { 4395 if (! o2.getRawType().equals(Enum.class)) { 4396 var l = new LinkedList<ClassMeta<?>>(); 4397 for (var pt2 : o2.getActualTypeArguments()) { 4398 if (pt2 instanceof WildcardType || pt2 instanceof TypeVariable) 4399 return null; 4400 l.add(resolveClassMeta(pt2, null)); 4401 } 4402 if (l.isEmpty()) 4403 return null; 4404 return l.toArray(new ClassMeta[l.size()]); 4405 } 4406 } 4407 4408 return null; 4409 } 4410 4411 final ClassMeta resolveClassMeta(Type o, TypeVariables typeVars) { 4412 if (o == null) 4413 return null; 4414 4415 if (o instanceof ClassMeta<?> cm) { 4416 4417 // This classmeta could have been created by a different context. 4418 // Need to re-resolve it to pick up ObjectSwaps and stuff on this context. 4419 if (cm.getBeanContext() == this) 4420 return cm; 4421 if (cm.isMap()) 4422 return getClassMeta(cm.inner(), cm.getKeyType(), cm.getValueType()); 4423 if (cm.isCollection() || cm.isOptional()) 4424 return getClassMeta(cm.inner(), cm.getElementType()); 4425 return getClassMeta(cm.inner()); 4426 } 4427 4428 // Handle ClassInfo by extracting the underlying Type 4429 if (o instanceof ClassInfo ci) { 4430 return resolveClassMeta(ci.innerType(), typeVars); 4431 } 4432 4433 var c = TypeVariables.resolve(o, typeVars); 4434 4435 // This can happen when trying to resolve the "E getFirst()" method on LinkedList, whose type is a TypeVariable 4436 // These should just resolve to Object. 4437 if (c == null) 4438 return object(); 4439 4440 var rawType = getClassMeta(c); 4441 4442 // If this is a Map or Collection, and the parameter types aren't part 4443 // of the class definition itself (e.g. class AddressBook extends List<Person>), 4444 // then we need to figure out the parameters. 4445 if (rawType.isMap() || rawType.isCollection() || rawType.isOptional()) { 4446 var params = findParameters(o, c); 4447 if (params == null) 4448 return rawType; 4449 if (rawType.isMap()) { 4450 if (params.length != 2 || (params[0].isObject() && params[1].isObject())) 4451 return rawType; 4452 return new ClassMeta(rawType, params[0], params[1], null); 4453 } 4454 if (rawType.isCollection() || rawType.isOptional()) { 4455 if (params.length != 1 || params[0].isObject()) 4456 return rawType; 4457 return new ClassMeta(rawType, null, null, params[0]); 4458 } 4459 } 4460 4461 if (rawType.isArray()) { 4462 if (o instanceof GenericArrayType o2) { 4463 var elementType = resolveClassMeta(o2.getGenericComponentType(), typeVars); 4464 return new ClassMeta(rawType, null, null, elementType); 4465 } 4466 } 4467 4468 return rawType; 4469 } 4470 4471 /* 4472 * Resolves the 'genericized' class meta at the specified position in the ClassMeta array. 4473 */ 4474 private ClassMeta<?> getTypedClassMeta(ClassMeta<?>[] c, int pos) { 4475 var cm = c[pos++]; 4476 if (cm.isCollection() || cm.isOptional()) { 4477 var ce = c.length == pos ? object() : getTypedClassMeta(c, pos); 4478 return (ce.isObject() ? cm : new ClassMeta(cm, null, null, ce)); 4479 } else if (cm.isMap()) { 4480 var ck = c.length == pos ? object() : c[pos++]; 4481 var cv = c.length == pos ? object() : getTypedClassMeta(c, pos); 4482 return (ck.isObject() && cv.isObject() ? cm : new ClassMeta(cm, ck, cv, null)); 4483 } 4484 return cm; 4485 } 4486 4487 4488 private ClassMeta<?> resolveType(Type...t) { 4489 for (var tt : t) { 4490 if (nn(tt)) { 4491 var cm = getClassMeta(tt); 4492 if (tt != cmObject) 4493 return cm; 4494 } 4495 } 4496 return cmObject; 4497 } 4498}