001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau; 014 015import java.util.*; 016 017import org.apache.juneau.annotation.*; 018import org.apache.juneau.collections.*; 019import org.apache.juneau.http.*; 020import org.apache.juneau.internal.*; 021import org.apache.juneau.json.*; 022import org.apache.juneau.serializer.*; 023import org.apache.juneau.transform.*; 024 025/** 026 * A reusable stateless thread-safe read-only configuration, typically used for creating one-time use {@link Session} 027 * objects. 028 * 029 * <p> 030 * Contexts are created through the {@link ContextBuilder#build()} method (and subclasses of {@link ContextBuilder}). 031 * 032 * <p> 033 * Subclasses MUST implement the following constructor: 034 * 035 * <p class='bcode w800'> 036 * <jk>public</jk> T(PropertyStore); 037 * </p> 038 * 039 * <p> 040 * Besides that restriction, a context object can do anything you desire. 041 * <br>However, it MUST be thread-safe and all fields should be declared final to prevent modification. 042 * <br>It should NOT be used for storing temporary or state information. 043 * 044 * @see PropertyStore 045 */ 046@ConfigurableContext 047public abstract class Context { 048 049 static final String PREFIX = "Context"; 050 051 /** 052 * Configuration property: Debug mode. 053 * 054 * <h5 class='section'>Property:</h5> 055 * <ul class='spaced-list'> 056 * <li><b>ID:</b> {@link org.apache.juneau.Context#CONTEXT_debug CONTEXT_debug} 057 * <li><b>Name:</b> <js>"Context.debug.b"</js> 058 * <li><b>Data type:</b> <jk>boolean</jk> 059 * <li><b>System property:</b> <c>Context.debug</c> 060 * <li><b>Environment variable:</b> <c>CONTEXT_DEBUG</c> 061 * <li><b>Default:</b> <jk>false</jk> 062 * <li><b>Session property:</b> <jk>true</jk> 063 * <li><b>Annotations:</b> 064 * <ul> 065 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#debug()} 066 * </ul> 067 * <li><b>Methods:</b> 068 * <ul> 069 * <li class='jm'>{@link org.apache.juneau.ContextBuilder#debug()} 070 * <li class='jm'>{@link org.apache.juneau.SessionArgs#debug(Boolean)} 071 * </ul> 072 * </ul> 073 * 074 * <h5 class='section'>Description:</h5> 075 * 076 * <p> 077 * Enables the following additional information during serialization: 078 * <ul class='spaced-list'> 079 * <li> 080 * When bean getters throws exceptions, the exception includes the object stack information 081 * in order to determine how that method was invoked. 082 * <li> 083 * Enables {@link Serializer#BEANTRAVERSE_detectRecursions}. 084 * </ul> 085 * 086 * <p> 087 * Enables the following additional information during parsing: 088 * <ul class='spaced-list'> 089 * <li> 090 * When bean setters throws exceptions, the exception includes the object stack information 091 * in order to determine how that method was invoked. 092 * </ul> 093 * 094 * <h5 class='section'>Example:</h5> 095 * <p class='bcode w800'> 096 * <jc>// Create a serializer with debug enabled.</jc> 097 * WriterSerializer s = JsonSerializer 098 * .<jsm>create</jsm>() 099 * .debug() 100 * .build(); 101 * 102 * <jc>// Same, but use property.</jc> 103 * WriterSerializer s = JsonSerializer 104 * .<jsm>create</jsm>() 105 * .set(<jsf>BEAN_debug</jsf>, <jk>true</jk>) 106 * .build(); 107 * 108 * <jc>// Create a POJO model with a recursive loop.</jc> 109 * <jk>public class</jk> A { 110 * <jk>public</jk> Object <jf>f</jf>; 111 * } 112 * A a = <jk>new</jk> A(); 113 * a.<jf>f</jf> = a; 114 * 115 * <jc>// Throws a SerializeException and not a StackOverflowError</jc> 116 * String json = s.serialize(a); 117 * </p> 118 */ 119 public static final String CONTEXT_debug = PREFIX + ".debug.b"; 120 121 /** 122 * Configuration property: Locale. 123 * 124 * <h5 class='section'>Property:</h5> 125 * <ul class='spaced-list'> 126 * <li><b>ID:</b> {@link org.apache.juneau.Context#CONTEXT_locale CONTEXT_locale} 127 * <li><b>Name:</b> <js>"Context.locale.s"</js> 128 * <li><b>Data type:</b> {@link java.util.Locale} 129 * <li><b>System property:</b> <c>Context.locale</c> 130 * <li><b>Environment variable:</b> <c>CONTEXT_LOCALE</c> 131 * <li><b>Default:</b> <jk>null</jk> (defaults to {@link java.util.Locale#getDefault()}) 132 * <li><b>Session property:</b> <jk>true</jk> 133 * <li><b>Annotations:</b> 134 * <ul> 135 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#locale()} 136 * </ul> 137 * <li><b>Methods:</b> 138 * <ul> 139 * <li class='jm'>{@link org.apache.juneau.ContextBuilder#locale(Locale)} 140 * <li class='jm'>{@link org.apache.juneau.SessionArgs#locale(Locale)} 141 * </ul> 142 * </ul> 143 * 144 * <h5 class='section'>Description:</h5> 145 * 146 * <p> 147 * Specifies the default locale for serializer and parser sessions when not specified via {@link SessionArgs#locale(Locale)}. 148 * Typically used for POJO swaps that need to deal with locales such as swaps that convert <l>Date</l> and <l>Calendar</l> 149 * objects to strings by accessing it via the session passed into the {@link PojoSwap#swap(BeanSession, Object)} and 150 * {@link PojoSwap#unswap(BeanSession, Object, ClassMeta, String)} methods. 151 * 152 * <h5 class='section'>Example:</h5> 153 * <p class='bcode w800'> 154 * <jc>// Define a POJO swap that skips serializing beans if we're in the UK.</jc> 155 * <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap<MyBean> { 156 * <ja>@Override</ja> 157 * public String swap(BeanSession session, MyBean o) throws Exception { 158 * <jk>if</jk> (session.getLocale().equals(Locale.<jsf>UK</jsf>)) 159 * <jk>return null</jk>; 160 * <jk>return</jk> o.toString(); 161 * } 162 * } 163 * 164 * <jc>// Create a serializer that uses the specified locale if it's not passed in through session args.</jc> 165 * WriterSerializer s = JsonSerializer 166 * .<jsm>create</jsm>() 167 * .locale(Locale.<jsf>UK</jsf>) 168 * .pojoSwaps(MyBeanSwap.<jk>class</jk>) 169 * .build(); 170 * 171 * <jc>// Same, but use property.</jc> 172 * WriterSerializer s = JsonSerializer 173 * .<jsm>create</jsm>() 174 * .set(<jsf>CONTEXT_locale</jsf>, Locale.<jsf>UK</jsf>) 175 * .addTo(<jsf>BEAN_pojoSwaps</jsf>, MyBeanSwap.<jk>class</jk>) 176 * .build(); 177 * 178 * <jc>// Define on session-args instead.</jc> 179 * SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().locale(Locale.<jsf>UK</jsf>); 180 * <jk>try</jk> (WriterSerializerSession session = s.createSession(sessionArgs)) { 181 * 182 * <jc>// Produces "null" if in the UK.</jc> 183 * String json = s.serialize(<jk>new</jk> MyBean()); 184 * } 185 * </p> 186 */ 187 public static final String CONTEXT_locale = PREFIX + ".locale.s"; 188 189 /** 190 * Configuration property: Media type. 191 * 192 * <h5 class='section'>Property:</h5> 193 * <ul class='spaced-list'> 194 * <li><b>ID:</b> {@link org.apache.juneau.Context#CONTEXT_mediaType CONTEXT_mediaType} 195 * <li><b>Name:</b> <js>"Context.mediaType.s"</js> 196 * <li><b>Data type:</b> {@link org.apache.juneau.http.MediaType} 197 * <li><b>System property:</b> <c>Context.mediaType</c> 198 * <li><b>Environment variable:</b> <c>CONTEXT_MEDIATYPE</c> 199 * <li><b>Default:</b> <jk>null</jk> 200 * <li><b>Session property:</b> <jk>true</jk> 201 * <li><b>Annotations:</b> 202 * <ul> 203 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#mediaType()} 204 * </ul> 205 * <li><b>Methods:</b> 206 * <ul> 207 * <li class='jm'>{@link org.apache.juneau.ContextBuilder#mediaType(MediaType)} 208 * <li class='jm'>{@link org.apache.juneau.SessionArgs#mediaType(MediaType)} 209 * </ul> 210 * </ul> 211 * 212 * <h5 class='section'>Description:</h5> 213 * 214 * <p> 215 * Specifies the default media type for serializer and parser sessions when not specified via {@link SessionArgs#mediaType(MediaType)}. 216 * Typically used for POJO swaps that need to serialize the same POJO classes differently depending on 217 * the specific requested media type. For example, a swap could handle a request for media types <js>"application/json"</js> 218 * and <js>"application/json+foo"</js> slightly differently even though they're both being handled by the same JSON 219 * serializer or parser. 220 * 221 * <h5 class='section'>Example:</h5> 222 * <p class='bcode w800'> 223 * <jc>// Define a POJO swap that skips serializing beans if the media type is application/json.</jc> 224 * <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap<MyBean> { 225 * <ja>@Override</ja> 226 * public String swap(BeanSession session, MyBean o) throws Exception { 227 * <jk>if</jk> (session.getMediaType().equals(<js>"application/json"</js>)) 228 * <jk>return null</jk>; 229 * <jk>return</jk> o.toString(); 230 * } 231 * } 232 * 233 * <jc>// Create a serializer that uses the specified media type if it's not passed in through session args.</jc> 234 * WriterSerializer s = JsonSerializer 235 * .<jsm>create</jsm>() 236 * .mediaType(MediaType.<jsf>JSON</jsf>) 237 * .build(); 238 * 239 * <jc>// Same, but use property.</jc> 240 * WriterSerializer s = JsonSerializer 241 * .<jsm>create</jsm>() 242 * .set(<jsf>CONTEXT_mediaType</jsf>, MediaType.<jsf>JSON</jsf>) 243 * .build(); 244 * 245 * <jc>// Define on session-args instead.</jc> 246 * SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().mediaType(MediaType.<jsf>JSON</jsf>); 247 * <jk>try</jk> (WriterSerializerSession session = s.createSession(sessionArgs)) { 248 * 249 * <jc>// Produces "null" since it's JSON.</jc> 250 * String json = s.serialize(<jk>new</jk> MyBean()); 251 * } 252 * </p> 253 */ 254 public static final String CONTEXT_mediaType = PREFIX + ".mediaType.s"; 255 256 /** 257 * Configuration property: Time zone. 258 * 259 * <h5 class='section'>Property:</h5> 260 * <ul class='spaced-list'> 261 * <li><b>ID:</b> {@link org.apache.juneau.Context#CONTEXT_timeZone CONTEXT_timeZone} 262 * <li><b>Name:</b> <js>"Context.timeZone.s"</js> 263 * <li><b>Data type:</b> {@link java.util.TimeZone} 264 * <li><b>System property:</b> <c>Context.timeZone</c> 265 * <li><b>Environment variable:</b> <c>CONTEXT_TIMEZONE</c> 266 * <li><b>Default:</b> <jk>null</jk> 267 * <li><b>Session property:</b> <jk>true</jk> 268 * <li><b>Annotations:</b> 269 * <ul> 270 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#timeZone()} 271 * </ul> 272 * <li><b>Methods:</b> 273 * <ul> 274 * <li class='jm'>{@link org.apache.juneau.ContextBuilder#timeZone(TimeZone)} 275 * <li class='jm'>{@link org.apache.juneau.SessionArgs#timeZone(TimeZone)} 276 * </ul> 277 * </ul> 278 * 279 * <h5 class='section'>Description:</h5> 280 * 281 * <p> 282 * Specifies the default time zone for serializer and parser sessions when not specified via {@link SessionArgs#timeZone(TimeZone)}. 283 * Typically used for POJO swaps that need to deal with timezones such as swaps that convert <l>Date</l> and <l>Calendar</l> 284 * objects to strings by accessing it via the session passed into the {@link PojoSwap#swap(BeanSession, Object)} and 285 * {@link PojoSwap#unswap(BeanSession, Object, ClassMeta, String)} methods. 286 * 287 * <h5 class='section'>Example:</h5> 288 * <p class='bcode w800'> 289 * <jc>// Define a POJO swap that skips serializing beans if the time zone is GMT.</jc> 290 * <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap<MyBean> { 291 * <ja>@Override</ja> 292 * public String swap(BeanSession session, MyBean o) throws Exception { 293 * <jk>if</jk> (session.getTimeZone().equals(TimeZone.<jsf>GMT</jsf>)) 294 * <jk>return null</jk>; 295 * <jk>return</jk> o.toString(); 296 * } 297 * } 298 * 299 * <jc>// Create a serializer that uses GMT if the timezone is not specified in the session args.</jc> 300 * WriterSerializer s = JsonSerializer 301 * .<jsm>create</jsm>() 302 * .timeZone(TimeZone.<jsf>GMT</jsf>) 303 * .build(); 304 * 305 * <jc>// Same, but use property.</jc> 306 * WriterSerializer s = JsonSerializer 307 * .<jsm>create</jsm>() 308 * .set(<jsf>CONTEXT_timeZone</jsf>, TimeZone.<jsf>GMT</jsf>) 309 * .build(); 310 * 311 * <jc>// Define on session-args instead.</jc> 312 * SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().timeZone(TimeZone.<jsf>GMT</jsf>); 313 * <jk>try</jk> (WriterSerializerSession ss = JsonSerializer.<jsf>DEFAULT</jsf>.createSession(sessionArgs)) { 314 * 315 * <jc>// Produces "null" since the time zone is GMT.</jc> 316 * String json = s.serialize(<jk>new</jk> MyBean()); 317 * } 318 * </p> 319 */ 320 public static final String CONTEXT_timeZone = PREFIX + ".timeZone.s"; 321 322 323 private final PropertyStore propertyStore; 324 private final int identityCode; 325 326 private final boolean debug; 327 private final Locale locale; 328 private final TimeZone timeZone; 329 private final MediaType mediaType; 330 331 /** 332 * Constructor for this class. 333 * 334 * <p> 335 * Subclasses MUST implement the same public constructor. 336 * 337 * @param ps The read-only configuration for this context object. 338 * @param allowReuse If <jk>true</jk>, subclasses that share the same property store values can be reused. 339 */ 340 public Context(PropertyStore ps, boolean allowReuse) { 341 this.propertyStore = ps == null ? PropertyStore.DEFAULT : ps; 342 this.identityCode = allowReuse ? new HashCode().add(getClass().getName()).add(ps).get() : System.identityHashCode(this); 343 debug = getBooleanProperty(CONTEXT_debug, false); 344 locale = getInstanceProperty(CONTEXT_locale, Locale.class, Locale.getDefault()); 345 timeZone = getInstanceProperty(CONTEXT_timeZone, TimeZone.class, null); 346 mediaType = getInstanceProperty(CONTEXT_mediaType, MediaType.class, null); 347 } 348 349 /** 350 * Returns the raw property value with the specified name. 351 * 352 * @param key The property name. 353 * @return The property value, or <jk>null</jk> if it doesn't exist. 354 */ 355 public Object getProperty(String key) { 356 return propertyStore.getProperty(key); 357 } 358 359 /** 360 * Returns the property value with the specified name. 361 * 362 * @param key The property name. 363 * @param c The class to cast or convert the value to. 364 * @param def The default value. 365 * @return The property value, or the default value if it doesn't exist. 366 */ 367 public final <T> T getProperty(String key, Class<T> c, T def) { 368 return propertyStore.getProperty(key, c, def); 369 } 370 371 /** 372 * Shortcut for calling <code>getProperty(key, Boolean.<jk>class</jk>, def)</code>. 373 * 374 * @param key The property name. 375 * @param def The default value. 376 * @return The property value, or the default value if it doesn't exist. 377 */ 378 public final Boolean getBooleanProperty(String key, Boolean def) { 379 return getProperty(key, Boolean.class, def); 380 } 381 382 /** 383 * Shortcut for calling <code>getProperty(key, Integer.<jk>class</jk>, def)</code>. 384 * 385 * @param key The property name. 386 * @param def The default value. 387 * @return The property value, or the default value if it doesn't exist. 388 */ 389 public final Integer getIntegerProperty(String key, Integer def) { 390 return getProperty(key, Integer.class, def); 391 } 392 393 /** 394 * Shortcut for calling <code>getProperty(key, Long.<jk>class</jk>, def)</code>. 395 * 396 * @param key The property name. 397 * @param def The default value. 398 * @return The property value, or the default value if it doesn't exist. 399 */ 400 public final Long getLongProperty(String key, Long def) { 401 return getProperty(key, Long.class, def); 402 } 403 404 /** 405 * Shortcut for calling <code>getProperty(key, String.<jk>class</jk>, def)</code>. 406 * 407 * @param key The property name. 408 * @param def The default value. 409 * @return The property value, or the default value if it doesn't exist. 410 */ 411 public final String getStringProperty(String key, String def) { 412 return getProperty(key, String.class, def); 413 } 414 415 /** 416 * Returns a property as a parsed comma-delimited list of strings. 417 * 418 * @param key The property name. 419 * @param def The default value. 420 * @return The property value, or the default value if it doesn't exist. 421 */ 422 public final String[] getCdlProperty(String key, String def) { 423 return StringUtils.split(StringUtils.emptyIfNull(getProperty(key, String.class, def))); 424 } 425 426 /** 427 * Same as {@link #getStringProperty(String, String)} but returns a blank instead of the default value if it resolves to <js>"NONE"</js>. 428 * 429 * @param key The property name. 430 * @param def The default value. 431 * @return The property value, or the default value if it doesn't exist. 432 */ 433 public final String getStringPropertyWithNone(String key, String def) { 434 String s = getProperty(key, String.class, def); 435 return "NONE".equalsIgnoreCase(s) ? "" : s; 436 } 437 438 /** 439 * Returns the class property with the specified name. 440 * 441 * @param key The property name. 442 * @param type The class type of the property. 443 * @param def The default value. 444 * @return The property value, or the default value if it doesn't exist. 445 */ 446 public final <T> Class<? extends T> getClassProperty(String key, Class<T> type, Class<? extends T> def) { 447 return propertyStore.getClassProperty(key, type, def); 448 } 449 450 /** 451 * Returns the array property value with the specified name. 452 * 453 * @param key The property name. 454 * @param eType The class type of the elements in the property. 455 * @return The property value, or the default value if it doesn't exist. 456 */ 457 public final <T> T[] getArrayProperty(String key, Class<T> eType) { 458 return propertyStore.getArrayProperty(key, eType); 459 } 460 461 /** 462 * Returns the array property value with the specified name. 463 * 464 * @param key The property name. 465 * @param eType The class type of the elements in the property. 466 * @param def The default value. 467 * @return The property value, or the default value if it doesn't exist. 468 */ 469 public final <T> T[] getArrayProperty(String key, Class<T> eType, T[] def) { 470 return propertyStore.getArrayProperty(key, eType, def); 471 } 472 473 /** 474 * Returns the class array property with the specified name. 475 * 476 * @param key The property name. 477 * @return The property value, or an empty array if it doesn't exist. 478 */ 479 public final Class<?>[] getClassArrayProperty(String key) { 480 return propertyStore.getClassArrayProperty(key); 481 } 482 483 /** 484 * Returns the class array property with the specified name. 485 * 486 * @param key The property name. 487 * @param def The default value. 488 * @return The property value, or an empty array if it doesn't exist. 489 */ 490 public final Class<?>[] getClassArrayProperty(String key, Class<?>[] def) { 491 return propertyStore.getClassArrayProperty(key, def); 492 } 493 494 /** 495 * Returns the class array property with the specified name. 496 * 497 * @param key The property name. 498 * @param eType The class type of the elements in the property. 499 * @return The property value, or an empty array if it doesn't exist. 500 */ 501 public final <T> Class<T>[] getClassArrayProperty(String key, Class<T> eType) { 502 return propertyStore.getClassArrayProperty(key, eType); 503 } 504 505 /** 506 * Returns the set property with the specified name. 507 * 508 * @param key The property name. 509 * @param eType The class type of the elements in the property. 510 * @return The property value as an unmodifiable <c>LinkedHashSet</c>, or an empty set if it doesn't exist. 511 */ 512 public final <T> Set<T> getSetProperty(String key, Class<T> eType) { 513 return propertyStore.getSetProperty(key, eType); 514 } 515 516 /** 517 * Returns the set property with the specified name. 518 * 519 * @param key The property name. 520 * @param eType The class type of the elements in the property. 521 * @param def The default value if the property doesn't exist or is empty. 522 * @return The property value as an unmodifiable <c>LinkedHashSet</c>, or the default value if it doesn't exist or is empty. 523 */ 524 public final <T> Set<T> getSetProperty(String key, Class<T> eType, Set<T> def) { 525 return propertyStore.getSetProperty(key, eType, def); 526 } 527 528 /** 529 * Returns the class set property with the specified name. 530 * 531 * @param key The property name. 532 * @return The property value as an unmodifiable <c>LinkedHashSet</c>, or an empty set if it doesn't exist. 533 */ 534 public final Set<Class<?>> getClassSetProperty(String key) { 535 return propertyStore.getClassSetProperty(key); 536 } 537 538 /** 539 * Returns the class set property with the specified name. 540 * 541 * @param key The property name. 542 * @param eType The class type of the elements in the property. 543 * @return The property value as an unmodifiable <c>LinkedHashSet</c>, or an empty set if it doesn't exist. 544 */ 545 public final <T> Set<Class<T>> getClassSetProperty(String key, Class<T> eType) { 546 return propertyStore.getClassSetProperty(key, eType); 547 } 548 549 /** 550 * Returns the list property with the specified name. 551 * 552 * @param key The property name. 553 * @param eType The class type of the elements in the property. 554 * @return The property value as an unmodifiable <c>ArrayList</c>, or an empty list if it doesn't exist. 555 */ 556 public final <T> List<T> getListProperty(String key, Class<T> eType) { 557 return propertyStore.getListProperty(key, eType); 558 } 559 560 /** 561 * Returns the list property with the specified name. 562 * 563 * @param key The property name. 564 * @param eType The class type of the elements in the property. 565 * @param def The default value if the property doesn't exist or is empty. 566 * @return The property value as an unmodifiable <c>ArrayList</c>, or the default value if it doesn't exist or is empty. 567 */ 568 public final <T> List<T> getListProperty(String key, Class<T> eType, List<T> def) { 569 return propertyStore.getListProperty(key, eType, def); 570 } 571 572 /** 573 * Returns the class list property with the specified name. 574 * 575 * @param key The property name. 576 * @return The property value as an unmodifiable <c>ArrayList</c>, or an empty list if it doesn't exist. 577 */ 578 public final List<Class<?>> getClassListProperty(String key) { 579 return propertyStore.getClassListProperty(key); 580 } 581 582 /** 583 * Returns the class list property with the specified name. 584 * 585 * @param key The property name. 586 * @param eType The class type of the elements in the property. 587 * @return The property value as an unmodifiable <c>ArrayList</c>, or an empty list if it doesn't exist. 588 */ 589 public final <T> List<Class<T>> getClassListProperty(String key, Class<T> eType) { 590 return propertyStore.getClassListProperty(key, eType); 591 } 592 593 /** 594 * Returns the map property with the specified name. 595 * 596 * @param key The property name. 597 * @param eType The class type of the elements in the property. 598 * @return The property value as an unmodifiable <c>LinkedHashMap</c>, or an empty map if it doesn't exist. 599 */ 600 public final <T> Map<String,T> getMapProperty(String key, Class<T> eType) { 601 return propertyStore.getMapProperty(key, eType); 602 } 603 604 /** 605 * Returns the class map property with the specified name. 606 * 607 * @param key The property name. 608 * @return The property value as an unmodifiable <c>LinkedHashMap</c>, or an empty map if it doesn't exist. 609 */ 610 public final Map<String,Class<?>> getClassMapProperty(String key) { 611 return propertyStore.getClassMapProperty(key); 612 } 613 614 /** 615 * Returns the class map property with the specified name. 616 * 617 * @param key The property name. 618 * @param eType The class type of the elements in the property. 619 * @return The property value as an unmodifiable <c>LinkedHashMap</c>, or an empty map if it doesn't exist. 620 */ 621 public final <T> Map<String,Class<T>> getClassMapProperty(String key, Class<T> eType) { 622 return propertyStore.getClassMapProperty(key, eType); 623 } 624 625 /** 626 * Returns an instance of the specified class, string, or object property. 627 * 628 * <p> 629 * If instantiating a class, assumes the class has a no-arg constructor. 630 * Otherwise, throws a runtime exception. 631 * 632 * @param key The property name. 633 * @param type The class type of the property. 634 * @param def 635 * The default value if the property doesn't exist. 636 * <br>Can either be an instance of <c>T</c>, or a <code>Class<? <jk>extends</jk> T></code>, or <jk>null</jk>. 637 * @return A new property instance. 638 */ 639 public <T> T getInstanceProperty(String key, Class<T> type, Object def) { 640 return propertyStore.getInstanceProperty(key, type, def); 641 } 642 643 /** 644 * Returns an instance of the specified class, string, or object property. 645 * 646 * @param key The property name. 647 * @param type The class type of the property. 648 * @param def 649 * The default value if the property doesn't exist. 650 * <br>Can either be an instance of <c>T</c>, or a <code>Class<? <jk>extends</jk> T></code>. 651 * @param resolver 652 * The resolver to use for instantiating objects. 653 * @param args 654 * Arguments to pass to the constructor. 655 * Constructors matching the arguments are always used before no-arg constructors. 656 * @return A new property instance. 657 */ 658 public <T> T getInstanceProperty(String key, Class<T> type, Object def, ResourceResolver resolver, Object...args) { 659 return propertyStore.getInstanceProperty(key, type, def, resolver, args); 660 } 661 662 /** 663 * Returns an instance of the specified class, string, or object property. 664 * 665 * @param key The property name. 666 * @param outer The outer object if the class we're instantiating is an inner class. 667 * @param type The class type of the property. 668 * @param def 669 * The default value if the property doesn't exist. 670 * <br>Can either be an instance of <c>T</c>, or a <code>Class<? <jk>extends</jk> T></code>. 671 * @param resolver 672 * The resolver to use for instantiating objects. 673 * @param args 674 * Arguments to pass to the constructor. 675 * Constructors matching the arguments are always used before no-arg constructors. 676 * @return A new property instance. 677 */ 678 public <T> T getInstanceProperty(String key, Object outer, Class<T> type, Object def, ResourceResolver resolver, Object...args) { 679 return propertyStore.getInstanceProperty(key, outer, type, def, resolver, args); 680 } 681 682 /** 683 * Returns the specified property as an array of instantiated objects. 684 * 685 * @param key The property name. 686 * @param type The class type of the property. 687 * @param def The default object to return if the property doesn't exist. 688 * @return A new property instance. 689 */ 690 public <T> T[] getInstanceArrayProperty(String key, Class<T> type, T[] def) { 691 return propertyStore.getInstanceArrayProperty(key, type, def); 692 } 693 694 /** 695 * Returns the specified property as an array of instantiated objects. 696 * 697 * @param key The property name. 698 * @param type The class type of the property. 699 * @param def The default object to return if the property doesn't exist. 700 * @param resolver 701 * The resolver to use for instantiating objects. 702 * @param args 703 * Arguments to pass to the constructor. 704 * Constructors matching the arguments are always used before no-arg constructors. 705 * @return A new property instance. 706 */ 707 public <T> T[] getInstanceArrayProperty(String key, Class<T> type, T[] def, ResourceResolver resolver, Object...args) { 708 return propertyStore.getInstanceArrayProperty(key, type, def, resolver, args); 709 } 710 711 /** 712 * Returns the specified property as an array of instantiated objects. 713 * 714 * @param key The property name. 715 * @param outer The outer object if the class we're instantiating is an inner class. 716 * @param type The class type of the property. 717 * @param def The default object to return if the property doesn't exist. 718 * @param resolver 719 * The resolver to use for instantiating objects. 720 * @param args 721 * Arguments to pass to the constructor. 722 * Constructors matching the arguments are always used before no-arg constructors. 723 * @return A new property instance. 724 */ 725 public <T> T[] getInstanceArrayProperty(String key, Object outer, Class<T> type, T[] def, ResourceResolver resolver, Object...args) { 726 return propertyStore.getInstanceArrayProperty(key, outer, type, def, resolver, args); 727 } 728 729 /** 730 * Returns the keys found in the specified property group. 731 * 732 * <p> 733 * The keys are NOT prefixed with group names. 734 * 735 * @param group The group name. 736 * @return The set of property keys, or an empty set if the group was not found. 737 */ 738 public Set<String> getPropertyKeys(String group) { 739 return propertyStore.getPropertyKeys(group); 740 } 741 742 /** 743 * Returns the property store associated with this context. 744 * 745 * @return The property store associated with this context. 746 */ 747 @BeanIgnore 748 public final PropertyStore getPropertyStore() { 749 return propertyStore; 750 } 751 752 /** 753 * Creates a builder from this context object. 754 * 755 * <p> 756 * Builders are used to define new contexts (e.g. serializers, parsers) based on existing configurations. 757 * 758 * @return A new ContextBuilder object. 759 */ 760 public ContextBuilder builder() { 761 return null; 762 } 763 764 /** 765 * Create a new bean session based on the properties defined on this context. 766 * 767 * <p> 768 * Use this method for creating sessions if you don't need to override any 769 * properties or locale/timezone currently set on this context. 770 * 771 * @return A new session object. 772 */ 773 public Session createSession() { 774 return createSession(createDefaultSessionArgs()); 775 } 776 777 /** 778 * Create a new session based on the properties defined on this context combined with the specified 779 * runtime args. 780 * 781 * <p> 782 * Use this method for creating sessions if you don't need to override any 783 * properties or locale/timezone currently set on this context. 784 * 785 * @param args 786 * The session arguments. 787 * @return A new session object. 788 */ 789 public abstract Session createSession(SessionArgs args); 790 791 /** 792 * Defines default session arguments used when calling the {@link #createSession()} method. 793 * 794 * @return A SessionArgs object, possibly a read-only reusable instance. 795 */ 796 public abstract SessionArgs createDefaultSessionArgs(); 797 798 @Override /* Object */ 799 public int hashCode() { 800 return identityCode; 801 } 802 803 /** 804 * Returns a uniqueness identity code for this context. 805 * 806 * @return A uniqueness identity code. 807 */ 808 public int identityCode() { 809 return identityCode; 810 } 811 812 @Override /* Object */ 813 public boolean equals(Object o) { 814 // Context objects are considered equal if they're the same class and have the same set of properties. 815 if (o == null) 816 return false; 817 if (o.getClass() != this.getClass()) 818 return false; 819 Context c = (Context)o; 820 return (c.propertyStore.equals(propertyStore)); 821 } 822 823 //----------------------------------------------------------------------------------------------------------------- 824 // Properties 825 //----------------------------------------------------------------------------------------------------------------- 826 827 /** 828 * Debug mode. 829 * 830 * @see #CONTEXT_debug 831 * @return 832 * <jk>true</jk> if debug mode is enabled. 833 */ 834 protected boolean isDebug() { 835 return debug; 836 } 837 838 /** 839 * Locale. 840 * 841 * @see #CONTEXT_locale 842 * @return 843 * The default locale for serializer and parser sessions. 844 */ 845 protected final Locale getDefaultLocale() { 846 return locale; 847 } 848 849 /** 850 * Media type. 851 * 852 * @see #CONTEXT_mediaType 853 * @return 854 * The default media type value for serializer and parser sessions. 855 */ 856 protected final MediaType getDefaultMediaType() { 857 return mediaType; 858 } 859 860 /** 861 * Time zone. 862 * 863 * @see #CONTEXT_timeZone 864 * @return 865 * The default timezone for serializer and parser sessions. 866 */ 867 protected final TimeZone getDefaultTimeZone() { 868 return timeZone; 869 } 870 871 //----------------------------------------------------------------------------------------------------------------- 872 // Other methods 873 //----------------------------------------------------------------------------------------------------------------- 874 875 @Override /* Object */ 876 public String toString() { 877 return SimpleJsonSerializer.DEFAULT_READABLE.toString(toMap()); 878 } 879 880 /** 881 * Returns the properties defined on this bean context as a simple map for debugging purposes. 882 * 883 * @return A new map containing the properties defined on this context. 884 */ 885 public OMap toMap() { 886 return new DefaultFilteringOMap() 887 .a("Context", new DefaultFilteringOMap() 888 .a("identityCode", identityCode) 889 .a("propertyStore", propertyStore) 890 ); 891 } 892}