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.serializer; 014 015import java.io.*; 016 017import org.apache.juneau.*; 018import org.apache.juneau.annotation.*; 019import org.apache.juneau.collections.*; 020import org.apache.juneau.http.*; 021import org.apache.juneau.internal.*; 022 023/** 024 * Parent class for all Juneau serializers. 025 * 026 * <h5 class='topic'>Description</h5> 027 * 028 * Base serializer class that serves as the parent class for all serializers. 029 * 030 * <p> 031 * The purpose of this class is: 032 * <ul> 033 * <li>Maintain a read-only configuration state of a serializer. 034 * <li>Create session objects used for serializing POJOs (i.e. {@link SerializerSession}). 035 * <li>Provide convenience methods for serializing POJOs without having to construct session objects. 036 * </ul> 037 * 038 * <p> 039 * Subclasses should extend directly from {@link OutputStreamSerializer} or {@link WriterSerializer} depending on 040 * whether it's a stream or character based serializer. 041 */ 042@ConfigurableContext 043public abstract class Serializer extends BeanTraverseContext { 044 045 /** 046 * Represents no Serializer. 047 */ 048 public static abstract class Null extends Serializer { 049 private Null(PropertyStore ps, String produces, String accept) { 050 super(ps, produces, accept); 051 } 052 } 053 054 //------------------------------------------------------------------------------------------------------------------- 055 // Configurable properties 056 //------------------------------------------------------------------------------------------------------------------- 057 058 static final String PREFIX = "Serializer"; 059 060 /** 061 * Configuration property: Add <js>"_type"</js> properties when needed. 062 * 063 * <h5 class='section'>Property:</h5> 064 * <ul class='spaced-list'> 065 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_addBeanTypes SERIALIZER_addBeanTypes} 066 * <li><b>Name:</b> <js>"Serializer.addBeanTypes.b"</js> 067 * <li><b>Data type:</b> <jk>boolean</jk> 068 * <li><b>System property:</b> <c>Serializer.addBeanTypes</c> 069 * <li><b>Environment variable:</b> <c>SERIALIZER_ADDBEANTYPES</c> 070 * <li><b>Default:</b> <jk>false</jk> 071 * <li><b>Session property:</b> <jk>false</jk> 072 * <li><b>Annotations:</b> 073 * <ul> 074 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#addBeanTypes()} 075 * </ul> 076 * <li><b>Methods:</b> 077 * <ul> 078 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#addBeanTypes()} 079 * </ul> 080 * </ul> 081 * 082 * <h5 class='section'>Description:</h5> 083 * 084 * <p> 085 * When enabled, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred 086 * through reflection. 087 * 088 * <p> 089 * This is used to recreate the correct objects during parsing if the object types cannot be inferred. 090 * <br>For example, when serializing a <c>Map<String,Object></c> field where the bean class cannot be determined from 091 * the type of the values. 092 * 093 * <p> 094 * Note the differences between the following settings: 095 * <ul class='javatree'> 096 * <li class='jf'>{@link #SERIALIZER_addRootType} - Affects whether <js>'_type'</js> is added to root node. 097 * <li class='jf'>{@link #SERIALIZER_addBeanTypes} - Affects whether <js>'_type'</js> is added to any nodes. 098 * </ul> 099 * 100 * <h5 class='section'>Example:</h5> 101 * <p class='bcode w800'> 102 * <jc>// Create a serializer that adds _type to nodes.</jc> 103 * WriterSerializer s = JsonSerializer 104 * .<jsm>create</jsm>() 105 * .addBeanTypes() 106 * .build(); 107 * 108 * <jc>// Same, but use property.</jc> 109 * WriterSerializer s = JsonSerializer 110 * .<jsm>create</jsm>() 111 * .set(<jsf>SERIALIZER_addBeanTypes</jsf>, <jk>true</jk>) 112 * .build(); 113 * 114 * <jc>// Our map of beans to serialize.</jc> 115 * <ja>@Bean</ja>(typeName=<js>"mybean"</js>) 116 * <jk>public class</jk> MyBean { 117 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 118 * } 119 * OMap map = OMap.of(<js>"foo"</js>, <jk>new</jk> MyBean()); 120 * 121 * <jc>// Will contain: {"foo":{"_type":"mybean","foo":"bar"}}</jc> 122 * String json = s.serialize(map); 123 * </p> 124 */ 125 public static final String SERIALIZER_addBeanTypes = PREFIX + ".addBeanTypes.b"; 126 127 /** 128 * Configuration property: Add type attribute to root nodes. 129 * 130 * <h5 class='section'>Property:</h5> 131 * <ul class='spaced-list'> 132 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_addRootType SERIALIZER_addRootType} 133 * <li><b>Name:</b> <js>"Serializer.addRootType.b"</js> 134 * <li><b>Data type:</b> <jk>boolean</jk> 135 * <li><b>System property:</b> <c>Serializer.addRootType</c> 136 * <li><b>Environment variable:</b> <c>SERIALIZER_ADDROOTTYPE</c> 137 * <li><b>Default:</b> <jk>false</jk> 138 * <li><b>Session property:</b> <jk>false</jk> 139 * <li><b>Annotations:</b> 140 * <ul> 141 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#addRootType()} 142 * </ul> 143 * <li><b>Methods:</b> 144 * <ul> 145 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#addRootType()} 146 * </ul> 147 * </ul> 148 * 149 * <h5 class='section'>Description:</h5> 150 * 151 * <p> 152 * When enabled, <js>"_type"</js> properties will be added to top-level beans. 153 * 154 * <p> 155 * When disabled, it is assumed that the parser knows the exact Java POJO type being parsed, and therefore top-level 156 * type information that might normally be included to determine the data type will not be serialized. 157 * 158 * <p> 159 * For example, when serializing a top-level POJO with a {@link Bean#typeName() @Bean(typeName)} value, a 160 * <js>'_type'</js> attribute will only be added when this setting is enabled. 161 * 162 * <p> 163 * Note the differences between the following settings: 164 * <ul class='javatree'> 165 * <li class='jf'>{@link #SERIALIZER_addRootType} - Affects whether <js>'_type'</js> is added to root node. 166 * <li class='jf'>{@link #SERIALIZER_addBeanTypes} - Affects whether <js>'_type'</js> is added to any nodes. 167 * </ul> 168 * 169 * <h5 class='section'>Example:</h5> 170 * <p class='bcode w800'> 171 * <jc>// Create a serializer that adds _type to root node.</jc> 172 * WriterSerializer s = JsonSerializer 173 * .<jsm>create</jsm>() 174 * .addRootType() 175 * .build(); 176 * 177 * <jc>// Same, but use property.</jc> 178 * WriterSerializer s = JsonSerializer 179 * .<jsm>create</jsm>() 180 * .set(<jsf>SERIALIZER_addRootType</jsf>, <jk>true</jk>) 181 * .build(); 182 * 183 * <jc>// Our bean to serialize.</jc> 184 * <ja>@Bean</ja>(typeName=<js>"mybean"</js>) 185 * <jk>public class</jk> MyBean { 186 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 187 * } 188 * 189 * <jc>// Will contain: {"_type":"mybean","foo":"bar"}</jc> 190 * String json = s.serialize(<jk>new</jk> MyBean()); 191 * </p> 192 */ 193 public static final String SERIALIZER_addRootType = PREFIX + ".addRootType.b"; 194 195 /** 196 * Configuration property: Serializer listener. 197 * 198 * <h5 class='section'>Property:</h5> 199 * <ul class='spaced-list'> 200 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_listener SERIALIZER_listener} 201 * <li><b>Name:</b> <js>"Serializer.listener.c"</js> 202 * <li><b>Data type:</b> <c>Class<{@link org.apache.juneau.serializer.SerializerListener}></c> 203 * <li><b>Default:</b> <jk>null</jk> 204 * <li><b>Session property:</b> <jk>false</jk> 205 * <li><b>Annotations:</b> 206 * <ul> 207 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#listener()} 208 * </ul> 209 * <li><b>Methods:</b> 210 * <ul> 211 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#listener(Class)} 212 * </ul> 213 * </ul> 214 * 215 * <h5 class='section'>Description:</h5> 216 * 217 * <p> 218 * Class used to listen for errors and warnings that occur during serialization. 219 * 220 * <h5 class='section'>Example:</h5> 221 * <p class='bcode w800'> 222 * <jc>// Define our serializer listener.</jc> 223 * <jc>// Simply captures all errors.</jc> 224 * <jk>public class</jk> MySerializerListener <jk>extends</jk> SerializerListener { 225 * 226 * <jc>// A simple property to store our events.</jc> 227 * <jk>public</jk> List<String> <jf>events</jf> = <jk>new</jk> LinkedList<>(); 228 * 229 * <ja>@Override</ja> 230 * <jk>public</jk> <T> <jk>void</jk> onError(SerializerSession session, Throwable t, String msg) { 231 * <jf>events</jf>.add(session.getLastLocation() + <js>","</js> + msg + <js>","</js> + t); 232 * } 233 * } 234 * 235 * <jc>// Create a serializer using our listener.</jc> 236 * WriterSerializer s = JsonSerializer 237 * .<jsm>create</jsm>() 238 * .listener(MySerializerListener.<jk>class</jk>) 239 * .build(); 240 * 241 * <jc>// Same, but use property.</jc> 242 * WriterSerializer s = JsonSerializer 243 * .<jsm>create</jsm>() 244 * .set(<jsf>SERIALIZER_listener</jsf>, MySerializerListener.<jk>class</jk>) 245 * .build(); 246 * 247 * <jc>// Create a session object.</jc> 248 * <jc>// Needed because listeners are created per-session.</jc> 249 * <jk>try</jk> (WriterSerializerSession ss = s.createSession()) { 250 * 251 * <jc>// Serialize a bean.</jc> 252 * String json = ss.serialize(<jk>new</jk> MyBean()); 253 * 254 * <jc>// Get the listener.</jc> 255 * MySerializerListener l = ss.getListener(MySerializerListener.<jk>class</jk>); 256 * 257 * <jc>// Dump the results to the console.</jc> 258 * SimpleJsonSerializer.<jsf>DEFAULT</jsf>.println(l.<jf>events</jf>); 259 * } 260 * </p> 261 */ 262 public static final String SERIALIZER_listener = PREFIX + ".listener.c"; 263 264 /** 265 * Configuration property: Don't trim null bean property values. 266 * 267 * <h5 class='section'>Property:</h5> 268 * <ul class='spaced-list'> 269 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_keepNullProperties SERIALIZER_keepNullProperties} 270 * <li><b>Name:</b> <js>"Serializer.keepNullProperties.b"</js> 271 * <li><b>Data type:</b> <jk>boolean</jk> 272 * <li><b>System property:</b> <c>Serializer.keepNullProperties</c> 273 * <li><b>Environment variable:</b> <c>SERIALIZER_KEEPNULLPROPERTIES</c> 274 * <li><b>Default:</b> <jk>false</jk> 275 * <li><b>Session property:</b> <jk>false</jk> 276 * <li><b>Annotations:</b> 277 * <ul> 278 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#keepNullProperties()} 279 * </ul> 280 * <li><b>Methods:</b> 281 * <ul> 282 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#keepNullProperties()} 283 * </ul> 284 * </ul> 285 * 286 * <h5 class='section'>Description:</h5> 287 * 288 * <p> 289 * When enabled, null bean values will be serialized to the output. 290 * 291 * <ul class='notes'> 292 * <li>Not enabling this setting will cause Maps with <jk>null</jk> values to be lost during parsing. 293 * </ul> 294 * 295 * <h5 class='section'>Example:</h5> 296 * <p class='bcode w800'> 297 * <jc>// Create a serializer that serializes null properties.</jc> 298 * WriterSerializer s = JsonSerializer 299 * .<jsm>create</jsm>() 300 * .keepNullProperties() 301 * .build(); 302 * 303 * <jc>// Same, but use property.</jc> 304 * WriterSerializer s = JsonSerializer 305 * .<jsm>create</jsm>() 306 * .set(<jsf>SERIALIZER_keepNullProperties</jsf>, <jk>true</jk>) 307 * .build(); 308 * 309 * <jc>// Our bean to serialize.</jc> 310 * <jk>public class</jk> MyBean { 311 * <jk>public</jk> String <jf>foo</jf> = <jk>null</jk>; 312 * } 313 * 314 * <jc>// Will contain "{foo:null}".</jc> 315 * String json = s.serialize(<jk>new</jk> MyBean()); 316 * </p> 317 */ 318 public static final String SERIALIZER_keepNullProperties = PREFIX + ".keepNullProperties.b"; 319 320 /** 321 * Configuration property: Sort arrays and collections alphabetically. 322 * 323 * <h5 class='section'>Property:</h5> 324 * <ul class='spaced-list'> 325 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_sortCollections SERIALIZER_sortCollections} 326 * <li><b>Name:</b> <js>"Serializer.sortCollections.b"</js> 327 * <li><b>Data type:</b> <jk>boolean</jk> 328 * <li><b>System property:</b> <c>Serializer.sortCollections</c> 329 * <li><b>Environment variable:</b> <c>SERIALIZER_SORTCOLLECTIONS</c> 330 * <li><b>Default:</b> <jk>false</jk> 331 * <li><b>Session property:</b> <jk>false</jk> 332 * <li><b>Annotations:</b> 333 * <ul> 334 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#sortCollections()} 335 * </ul> 336 * <li><b>Methods:</b> 337 * <ul> 338 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#sortCollections()} 339 * </ul> 340 * </ul> 341 * 342 * <h5 class='section'>Description:</h5> 343 * 344 * <p> 345 * When enabled, copies and sorts the contents of arrays and collections before serializing them. 346 * 347 * <p> 348 * Note that this introduces a performance penalty since it requires copying the existing collection. 349 * 350 * <h5 class='section'>Example:</h5> 351 * <p class='bcode w800'> 352 * <jc>// Create a serializer that sorts arrays and collections before serialization.</jc> 353 * WriterSerializer s = JsonSerializer 354 * .<jsm>create</jsm>() 355 * .sortCollections() 356 * .build(); 357 * 358 * <jc>// Same, but use property.</jc> 359 * WriterSerializer s = JsonSerializer 360 * .<jsm>create</jsm>() 361 * .set(<jsf>SERIALIZER_sortCollections</jsf>, <jk>true</jk>) 362 * .build(); 363 * 364 * <jc>// An unsorted array</jc> 365 * String[] array = {<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>} 366 * 367 * <jc>// Produces ["bar","baz","foo"]</jc> 368 * String json = s.serialize(array); 369 * </p> 370 */ 371 public static final String SERIALIZER_sortCollections = PREFIX + ".sortCollections.b"; 372 373 /** 374 * Configuration property: Sort maps alphabetically. 375 * 376 * <h5 class='section'>Property:</h5> 377 * <ul class='spaced-list'> 378 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_sortMaps SERIALIZER_sortMaps} 379 * <li><b>Name:</b> <js>"Serializer.sortMaps.b"</js> 380 * <li><b>Data type:</b> <jk>boolean</jk> 381 * <li><b>System property:</b> <c>Serializer.sortMaps</c> 382 * <li><b>Environment variable:</b> <c>SERIALIZER_SORTMAPS</c> 383 * <li><b>Default:</b> <jk>false</jk> 384 * <li><b>Session property:</b> <jk>false</jk> 385 * <li><b>Annotations:</b> 386 * <ul> 387 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#sortMaps()} 388 * </ul> 389 * <li><b>Methods:</b> 390 * <ul> 391 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#sortMaps()} 392 * </ul> 393 * </ul> 394 * 395 * <h5 class='section'>Description:</h5> 396 * 397 * <p> 398 * When enabled, copies and sorts the contents of maps by their keys before serializing them. 399 * 400 * <p> 401 * Note that this introduces a performance penalty. 402 * 403 * <h5 class='section'>Example:</h5> 404 * <p class='bcode w800'> 405 * <jc>// Create a serializer that sorts maps before serialization.</jc> 406 * WriterSerializer s = JsonSerializer 407 * .<jsm>create</jsm>() 408 * .sortMaps() 409 * .build(); 410 * 411 * <jc>// Same, but use property.</jc> 412 * WriterSerializer s = JsonSerializer 413 * .<jsm>create</jsm>() 414 * .set(<jsf>SERIALIZER_sortMaps</jsf>, <jk>true</jk>) 415 * .build(); 416 * 417 * <jc>// An unsorted map.</jc> 418 * OMap map = OMap.<jsm>of</jsm>(<js>"foo"</js>,1,<js>"bar"</js>,2,<js>"baz"</js>,3); 419 * 420 * <jc>// Produces {"bar":2,"baz":3,"foo":1}</jc> 421 * String json = s.serialize(map); 422 * </p> 423 */ 424 public static final String SERIALIZER_sortMaps = PREFIX + ".sortMaps.b"; 425 426 /** 427 * Configuration property: Trim empty lists and arrays. 428 * 429 * <h5 class='section'>Property:</h5> 430 * <ul class='spaced-list'> 431 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimEmptyCollections SERIALIZER_trimEmptyCollections} 432 * <li><b>Name:</b> <js>"Serializer.trimEmptyCollections.b"</js> 433 * <li><b>Data type:</b> <jk>boolean</jk> 434 * <li><b>System property:</b> <c>Serializer.trimEmptyCollections</c> 435 * <li><b>Environment variable:</b> <c>SERIALIZER_TRIMEMPTYCOLLECTIONS</c> 436 * <li><b>Default:</b> <jk>false</jk> 437 * <li><b>Session property:</b> <jk>false</jk> 438 * <li><b>Annotations:</b> 439 * <ul> 440 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#trimEmptyCollections()} 441 * </ul> 442 * <li><b>Methods:</b> 443 * <ul> 444 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#trimEmptyCollections()} 445 * </ul> 446 * </ul> 447 * 448 * <h5 class='section'>Description:</h5> 449 * 450 * <p> 451 * When enabled, empty lists and arrays will not be serialized. 452 * 453 * <p> 454 * Note that enabling this setting has the following effects on parsing: 455 * <ul class='spaced-list'> 456 * <li> 457 * Map entries with empty list values will be lost. 458 * <li> 459 * Bean properties with empty list values will not be set. 460 * </ul> 461 * 462 * <h5 class='section'>Example:</h5> 463 * <p class='bcode w800'> 464 * <jc>// Create a serializer that skips empty arrays and collections.</jc> 465 * WriterSerializer s = JsonSerializer 466 * .<jsm>create</jsm>() 467 * .trimEmptyCollections() 468 * .build(); 469 * 470 * <jc>// Same, but use property.</jc> 471 * WriterSerializer s = JsonSerializer 472 * .<jsm>create</jsm>() 473 * .set(<jsf>SERIALIZER_trimEmptyCollections</jsf>, <jk>true</jk>) 474 * .build(); 475 * 476 * <jc>// A bean with a field with an empty array.</jc> 477 * <jk>public class</jk> MyBean { 478 * <jk>public</jk> String[] <jf>foo</jf> = {}; 479 * } 480 * 481 * <jc>// Produces {}</jc> 482 * String json = s.serialize(<jk>new</jk> MyBean()); 483 * </p> 484 */ 485 public static final String SERIALIZER_trimEmptyCollections = PREFIX + ".trimEmptyCollections.b"; 486 487 /** 488 * Configuration property: Trim empty maps. 489 * 490 * <h5 class='section'>Property:</h5> 491 * <ul class='spaced-list'> 492 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimEmptyMaps SERIALIZER_trimEmptyMaps} 493 * <li><b>Name:</b> <js>"Serializer.trimEmptyMaps.b"</js> 494 * <li><b>Data type:</b> <jk>boolean</jk> 495 * <li><b>System property:</b> <c>Serializer.trimEmptyMaps</c> 496 * <li><b>Environment variable:</b> <c>SERIALIZER_TRIMEMPTYMAPS</c> 497 * <li><b>Default:</b> <jk>false</jk> 498 * <li><b>Session property:</b> <jk>false</jk> 499 * <li><b>Annotations:</b> 500 * <ul> 501 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#trimEmptyMaps()} 502 * </ul> 503 * <li><b>Methods:</b> 504 * <ul> 505 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#trimEmptyMaps()} 506 * </ul> 507 * </ul> 508 * 509 * <h5 class='section'>Description:</h5> 510 * 511 * <p> 512 * When enabled, empty map values will not be serialized to the output. 513 * 514 * <p> 515 * Note that enabling this setting has the following effects on parsing: 516 * <ul class='spaced-list'> 517 * <li> 518 * Bean properties with empty map values will not be set. 519 * </ul> 520 * 521 * <h5 class='section'>Example:</h5> 522 * <p class='bcode w800'> 523 * <jc>// Create a serializer that skips empty maps.</jc> 524 * WriterSerializer s = JsonSerializer 525 * .<jsm>create</jsm>() 526 * .trimEmptyMaps() 527 * .build(); 528 * 529 * <jc>// Same, but use property.</jc> 530 * WriterSerializer s = JsonSerializer 531 * .<jsm>create</jsm>() 532 * .set(<jsf>SERIALIZER_trimEmptyMaps</jsf>, <jk>true</jk>) 533 * .build(); 534 * 535 * <jc>// A bean with a field with an empty map.</jc> 536 * <jk>public class</jk> MyBean { 537 * <jk>public</jk> OMap <jf>foo</jf> = OMap.<jsm>of</jsm>(); 538 * } 539 * 540 * <jc>// Produces {}</jc> 541 * String json = s.serialize(<jk>new</jk> MyBean()); 542 * </p> 543 */ 544 public static final String SERIALIZER_trimEmptyMaps = PREFIX + ".trimEmptyMaps.b"; 545 546 /** 547 * Configuration property: Trim null bean property values. 548 * 549 * <h5 class='section'>Property:</h5> 550 * <ul class='spaced-list'> 551 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimNullProperties SERIALIZER_trimNullProperties} 552 * <li><b>Name:</b> <js>"Serializer.trimNullProperties.b"</js> 553 * <li><b>Data type:</b> <jk>boolean</jk> 554 * <li><b>System property:</b> <c>Serializer.trimNullProperties</c> 555 * <li><b>Environment variable:</b> <c>SERIALIZER_TRIMNULLPROPERTIES</c> 556 * <li><b>Default:</b> <jk>true</jk> 557 * <li><b>Session property:</b> <jk>false</jk> 558 * <li><b>Annotations:</b> 559 * <ul> 560 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#trimNullProperties()} 561 * </ul> 562 * <li><b>Methods:</b> 563 * <ul> 564 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#trimNullProperties(boolean)} 565 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#dontTrimNullProperties()} 566 * </ul> 567 * </ul> 568 * 569 * <h5 class='section'>Description:</h5> 570 * 571 * <p> 572 * When enabled, null bean values will not be serialized to the output. 573 * 574 * <p> 575 * Note that enabling this setting has the following effects on parsing: 576 * <ul class='spaced-list'> 577 * <li> 578 * Map entries with <jk>null</jk> values will be lost. 579 * </ul> 580 * 581 * <h5 class='section'>Example:</h5> 582 * <p class='bcode w800'> 583 * <jc>// Create a serializer that serializes null properties.</jc> 584 * WriterSerializer s = JsonSerializer 585 * .<jsm>create</jsm>() 586 * .dontTrimNullProperties() 587 * .build(); 588 * 589 * <jc>// Same, but use property.</jc> 590 * WriterSerializer s = JsonSerializer 591 * .<jsm>create</jsm>() 592 * .set(<jsf>SERIALIZER_trimNullProperties</jsf>, <jk>false</jk>) 593 * .build(); 594 * </p> 595 * @deprecated Use {@link #SERIALIZER_keepNullProperties} 596 */ 597 @Deprecated 598 public static final String SERIALIZER_trimNullProperties = PREFIX + ".trimNullProperties.b"; 599 600 /** 601 * Configuration property: Trim strings. 602 * 603 * <h5 class='section'>Property:</h5> 604 * <ul class='spaced-list'> 605 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_trimStrings SERIALIZER_trimStrings} 606 * <li><b>Name:</b> <js>"Serializer.trimStrings.b"</js> 607 * <li><b>Data type:</b> <jk>boolean</jk> 608 * <li><b>System property:</b> <c>Serializer.trimStrings</c> 609 * <li><b>Environment variable:</b> <c>SERIALIZER_TRIMSTRINGS</c> 610 * <li><b>Default:</b> <jk>false</jk> 611 * <li><b>Session property:</b> <jk>false</jk> 612 * <li><b>Annotations:</b> 613 * <ul> 614 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#trimStrings()} 615 * </ul> 616 * <li><b>Methods:</b> 617 * <ul> 618 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#trimStrings()} 619 * </ul> 620 * </ul> 621 * 622 * <h5 class='section'>Description:</h5> 623 * 624 * <p> 625 * When enabled, string values will be trimmed of whitespace using {@link String#trim()} before being serialized. 626 * 627 * <h5 class='section'>Example:</h5> 628 * <p class='bcode w800'> 629 * <jc>// Create a serializer that trims strings before serialization.</jc> 630 * WriterSerializer s = JsonSerializer 631 * .<jsm>create</jsm>() 632 * .trimStrings() 633 * .build(); 634 * 635 * <jc>// Same, but use property.</jc> 636 * WriterSerializer s = JsonSerializer 637 * .<jsm>create</jsm>() 638 * .set(<jsf>SERIALIZER_trimStrings</jsf>, <jk>true</jk>) 639 * .build(); 640 * 641 * <jc>// A map with space-padded keys/values</jc> 642 * OMap map = OMap.<jsm>of</jsm>(<js>" foo "</js>, <js>" bar "</js>); 643 * 644 * <jc>// Produces "{foo:'bar'}"</jc> 645 * String json = s.toString(map); 646 * </p> 647 */ 648 public static final String SERIALIZER_trimStrings = PREFIX + ".trimStrings.b"; 649 650 /** 651 * Configuration property: URI context bean. 652 * 653 * <h5 class='section'>Property:</h5> 654 * <ul class='spaced-list'> 655 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriContext SERIALIZER_uriContext} 656 * <li><b>Name:</b> <js>"Serializer.uriContext.s"</js> 657 * <li><b>Data type:</b> {@link org.apache.juneau.UriContext} 658 * <li><b>System property:</b> <c>Serializer.uriContext</c> 659 * <li><b>Environment variable:</b> <c>SERIALIZER_URICONTEXT</c> 660 * <li><b>Default:</b> <js>"{}"</js> 661 * <li><b>Session property:</b> <jk>true</jk> 662 * <li><b>Annotations:</b> 663 * <ul> 664 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#uriContext()} 665 * </ul> 666 * <li><b>Methods:</b> 667 * <ul> 668 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#uriContext(UriContext)} 669 * </ul> 670 * </ul> 671 * 672 * <h5 class='section'>Description:</h5> 673 * 674 * <p> 675 * Bean used for resolution of URIs to absolute or root-relative form. 676 * 677 * <h5 class='section'>Example:</h5> 678 * <p class='bcode w800'> 679 * <jc>// Our URI contextual information.</jc> 680 * String authority = <js>"http://localhost:10000"</js>; 681 * String contextRoot = <js>"/myContext"</js>; 682 * String servletPath = <js>"/myServlet"</js>; 683 * String pathInfo = <js>"/foo"</js>; 684 * 685 * <jc>// Create a UriContext object.</jc> 686 * UriContext uriContext = <jk>new</jk> UriContext(authority, contextRoot, servletPath, pathInfo); 687 * 688 * <jc>// Associate it with our serializer.</jc> 689 * WriterSerializer s = JsonSerializer 690 * .<jsm>create</jsm>() 691 * .uriContext(uriContext) 692 * .uriRelativity(<jsf>RESOURCE</jsf>) <jc>// Assume relative paths are relative to servlet.</jc> 693 * .uriResolution(<jsf>ABSOLUTE</jsf>) <jc>// Serialize URLs as absolute paths.</jc> 694 * .build(); 695 * 696 * <jc>// Same, but use properties.</jc> 697 * WriterSerializer s = JsonSerializer 698 * .<jsm>create</jsm>() 699 * .set(<jsf>SERIALIZER_uriContext</jsf>, uriContext) 700 * .set(<jsf>SERIALIZER_uriRelativity</jsf>, <js>"RESOURCE"</js>) 701 * .set(<jsf>SERIALIZER_uriResolution</jsf>, <js>"ABSOLUTE"</js>) 702 * .build(); 703 * 704 * <jc>// Same, but define it on the session args instead.</jc> 705 * SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().uriContext(uriContext); 706 * <jk>try</jk> (WriterSerializerSession session = s.createSession(sessionArgs)) { 707 * ... 708 * } 709 * 710 * <jc>// A relative URL</jc> 711 * URL url = <jk>new</jk> URL(<js>"bar"</js>); 712 * 713 * <jc>// Produces "http://localhost:10000/myContext/myServlet/foo/bar"</jc> 714 * String json = s.toString(url); 715 * </p> 716 * 717 * <ul class='seealso'> 718 * <li class='link'>{@doc MarshallingUris} 719 * </ul> 720 */ 721 public static final String SERIALIZER_uriContext = PREFIX + ".uriContext.s"; 722 723 /** 724 * Configuration property: URI relativity. 725 * 726 * <h5 class='section'>Property:</h5> 727 * <ul class='spaced-list'> 728 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriRelativity SERIALIZER_uriRelativity} 729 * <li><b>Name:</b> <js>"Serializer.uriRelativity.s"</js> 730 * <li><b>Data type:</b> {@link org.apache.juneau.UriRelativity} 731 * <li><b>System property:</b> <c>Serializer.uriRelativity</c> 732 * <li><b>Environment variable:</b> <c>SERIALIZER_URIRELATIVITY</c> 733 * <li><b>Default:</b> <js>"RESOURCE"</js> 734 * <li><b>Session property:</b> <jk>false</jk> 735 * <li><b>Annotations:</b> 736 * <ul> 737 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#uriRelativity()} 738 * </ul> 739 * <li><b>Methods:</b> 740 * <ul> 741 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#uriRelativity(UriRelativity)} 742 * </ul> 743 * </ul> 744 * 745 * <h5 class='section'>Description:</h5> 746 * 747 * <p> 748 * Defines what relative URIs are relative to when serializing any of the following: 749 * <ul> 750 * <li>{@link java.net.URI} 751 * <li>{@link java.net.URL} 752 * <li>Properties and classes annotated with {@link org.apache.juneau.annotation.URI @URI} 753 * </ul> 754 * 755 * <p> 756 * Possible values are: 757 * <ul class='javatree'> 758 * <li class='jf'>{@link org.apache.juneau.UriRelativity#RESOURCE} 759 * - Relative URIs should be considered relative to the servlet URI. 760 * <li class='jf'>{@link org.apache.juneau.UriRelativity#PATH_INFO} 761 * - Relative URIs should be considered relative to the request URI. 762 * </ul> 763 * 764 * <p> 765 * See {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriContext} for examples. 766 * 767 * <ul class='seealso'> 768 * <li class='link'>{@doc MarshallingUris} 769 * </ul> 770 */ 771 public static final String SERIALIZER_uriRelativity = PREFIX + ".uriRelativity.s"; 772 773 /** 774 * Configuration property: URI resolution. 775 * 776 * <h5 class='section'>Property:</h5> 777 * <ul class='spaced-list'> 778 * <li><b>ID:</b> {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriResolution SERIALIZER_uriResolution} 779 * <li><b>Name:</b> <js>"Serializer.uriResolution.s"</js> 780 * <li><b>Data type:</b> {@link org.apache.juneau.UriResolution} 781 * <li><b>System property:</b> <c>Serializer.uriResolution</c> 782 * <li><b>Environment variable:</b> <c>SERIALIZER_URIRESOLUTION</c> 783 * <li><b>Default:</b> <js>"NONE"</js> 784 * <li><b>Session property:</b> <jk>false</jk> 785 * <li><b>Annotations:</b> 786 * <ul> 787 * <li class='ja'>{@link org.apache.juneau.serializer.annotation.SerializerConfig#uriResolution()} 788 * </ul> 789 * <li><b>Methods:</b> 790 * <ul> 791 * <li class='jm'>{@link org.apache.juneau.serializer.SerializerBuilder#uriResolution(UriResolution)} 792 * </ul> 793 * </ul> 794 * 795 * <h5 class='section'>Description:</h5> 796 * 797 * <p> 798 * Defines the resolution level for URIs when serializing any of the following: 799 * <ul> 800 * <li>{@link java.net.URI} 801 * <li>{@link java.net.URL} 802 * <li>Properties and classes annotated with {@link org.apache.juneau.annotation.URI @URI} 803 * </ul> 804 * 805 * <p> 806 * Possible values are: 807 * <ul> 808 * <li class='jf'>{@link UriResolution#ABSOLUTE} 809 * - Resolve to an absolute URL (e.g. <js>"http://host:port/context-root/servlet-path/path-info"</js>). 810 * <li class='jf'>{@link UriResolution#ROOT_RELATIVE} 811 * - Resolve to a root-relative URL (e.g. <js>"/context-root/servlet-path/path-info"</js>). 812 * <li class='jf'>{@link UriResolution#NONE} 813 * - Don't do any URL resolution. 814 * </ul> 815 * 816 * <p> 817 * See {@link org.apache.juneau.serializer.Serializer#SERIALIZER_uriContext} for examples. 818 * 819 * <ul class='seealso'> 820 * <li class='link'>{@doc MarshallingUris} 821 * </ul> 822 */ 823 public static final String SERIALIZER_uriResolution = PREFIX + ".uriResolution.s"; 824 825 static final Serializer DEFAULT = new Serializer(PropertyStore.create().build(), "", "") { 826 @Override 827 public SerializerSession createSession(SerializerSessionArgs args) { 828 throw new NoSuchMethodError(); 829 } 830 }; 831 832 //------------------------------------------------------------------------------------------------------------------- 833 // Instance 834 //------------------------------------------------------------------------------------------------------------------- 835 836 private final boolean 837 addBeanTypes, 838 keepNullProperties, 839 trimEmptyCollections, 840 trimEmptyMaps, 841 trimStrings, 842 sortCollections, 843 sortMaps, 844 addRootType; 845 private final UriContext uriContext; 846 private final UriResolution uriResolution; 847 private final UriRelativity uriRelativity; 848 private final Class<? extends SerializerListener> listener; 849 850 private final MediaRanges accept; 851 private final MediaType[] accepts; 852 private final MediaType produces; 853 854 /** 855 * Constructor 856 * 857 * @param ps 858 * The property store containing all the settings for this object. 859 * @param produces 860 * The media type that this serializer produces. 861 * @param accept 862 * The accept media types that the serializer can handle. 863 * <p> 864 * Can contain meta-characters per the <c>media-type</c> specification of {@doc ExtRFC2616.section14.1} 865 * <p> 866 * If empty, then assumes the only media type supported is <c>produces</c>. 867 * <p> 868 * For example, if this serializer produces <js>"application/json"</js> but should handle media types of 869 * <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be: 870 * <p class='bcode w800'> 871 * <jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>); 872 * </p> 873 * <br>...or... 874 * <p class='bcode w800'> 875 * <jk>super</jk>(ps, <js>"application/json"</js>, <js>"*​/json"</js>); 876 * </p> 877 * <p> 878 * The accept value can also contain q-values. 879 */ 880 protected Serializer(PropertyStore ps, String produces, String accept) { 881 super(ps); 882 883 addBeanTypes = getBooleanProperty(SERIALIZER_addBeanTypes, false); 884 keepNullProperties = getBooleanProperty(SERIALIZER_keepNullProperties, ! getBooleanProperty(SERIALIZER_trimNullProperties, true)); 885 trimEmptyCollections = getBooleanProperty(SERIALIZER_trimEmptyCollections, false); 886 trimEmptyMaps = getBooleanProperty(SERIALIZER_trimEmptyMaps, false); 887 trimStrings = getBooleanProperty(SERIALIZER_trimStrings, false); 888 sortCollections = getBooleanProperty(SERIALIZER_sortCollections, false); 889 sortMaps = getBooleanProperty(SERIALIZER_sortMaps, false); 890 addRootType = getBooleanProperty(SERIALIZER_addRootType, false); 891 uriContext = getProperty(SERIALIZER_uriContext, UriContext.class, UriContext.DEFAULT); 892 uriResolution = getProperty(SERIALIZER_uriResolution, UriResolution.class, UriResolution.NONE); 893 uriRelativity = getProperty(SERIALIZER_uriRelativity, UriRelativity.class, UriRelativity.RESOURCE); 894 listener = getClassProperty(SERIALIZER_listener, SerializerListener.class, null); 895 896 this.produces = MediaType.of(produces); 897 this.accept = accept == null ? MediaRanges.of(produces) : MediaRanges.of(accept); 898 this.accepts = accept == null ? new MediaType[] {this.produces} : MediaType.ofAll(StringUtils.split(accept, ',')); 899 } 900 901 @Override /* Context */ 902 public SerializerBuilder builder() { 903 return null; 904 } 905 906 //----------------------------------------------------------------------------------------------------------------- 907 // Abstract methods 908 //----------------------------------------------------------------------------------------------------------------- 909 910 /** 911 * Returns <jk>true</jk> if this serializer subclasses from {@link WriterSerializer}. 912 * 913 * @return <jk>true</jk> if this serializer subclasses from {@link WriterSerializer}. 914 */ 915 public boolean isWriterSerializer() { 916 return true; 917 } 918 919 /** 920 * Create the session object used for actual serialization of objects. 921 * 922 * @param args 923 * Runtime arguments. 924 * These specify session-level information such as locale and URI context. 925 * It also include session-level properties that override the properties defined on the bean and serializer 926 * contexts. 927 * @return 928 * The new session object. 929 */ 930 public abstract SerializerSession createSession(SerializerSessionArgs args); 931 932 933 //----------------------------------------------------------------------------------------------------------------- 934 // Convenience methods 935 //----------------------------------------------------------------------------------------------------------------- 936 937 @Override /* Context */ 938 public SerializerSession createSession() { 939 return createSession(createDefaultSessionArgs()); 940 } 941 942 @Override /* Context */ 943 public final SerializerSessionArgs createDefaultSessionArgs() { 944 return new SerializerSessionArgs().mediaType(getResponseContentType()); 945 } 946 947 /** 948 * Serializes a POJO to the specified output stream or writer. 949 * 950 * <p> 951 * Equivalent to calling <c>serializer.createSession().serialize(o, output);</c> 952 * 953 * @param o The object to serialize. 954 * @param output 955 * The output object. 956 * <br>Character-based serializers can handle the following output class types: 957 * <ul> 958 * <li>{@link Writer} 959 * <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream. 960 * <li>{@link File} - Output will be written as system-default encoded stream. 961 * <li>{@link StringBuilder} - Output will be written to the specified string builder. 962 * </ul> 963 * <br>Stream-based serializers can handle the following output class types: 964 * <ul> 965 * <li>{@link OutputStream} 966 * <li>{@link File} 967 * </ul> 968 * @throws SerializeException If a problem occurred trying to convert the output. 969 * @throws IOException Thrown by the underlying stream. 970 */ 971 public final void serialize(Object o, Object output) throws SerializeException, IOException { 972 createSession().serialize(o, output); 973 } 974 975 /** 976 * Shortcut method for serializing objects directly to either a <c>String</c> or <code><jk>byte</jk>[]</code> 977 * depending on the serializer type. 978 * 979 * @param o The object to serialize. 980 * @return 981 * The serialized object. 982 * <br>Character-based serializers will return a <c>String</c> 983 * <br>Stream-based serializers will return a <code><jk>byte</jk>[]</code> 984 * @throws SerializeException If a problem occurred trying to convert the output. 985 */ 986 public Object serialize(Object o) throws SerializeException { 987 return createSession().serialize(o); 988 } 989 990 /** 991 * Convenience method for serializing an object to a String. 992 * 993 * <p> 994 * For writer-based serializers, this is identical to calling {@link #serialize(Object)}. 995 * <br>For stream-based serializers, this converts the returned byte array to a string based on 996 * the {@link OutputStreamSerializer#OSSERIALIZER_binaryFormat} setting. 997 * 998 * @param o The object to serialize. 999 * @return The output serialized to a string. 1000 * @throws SerializeException If a problem occurred trying to convert the output. 1001 */ 1002 public final String serializeToString(Object o) throws SerializeException { 1003 return createSession().serializeToString(o); 1004 } 1005 1006 //----------------------------------------------------------------------------------------------------------------- 1007 // Other methods 1008 //----------------------------------------------------------------------------------------------------------------- 1009 1010 /** 1011 * Returns the media types handled based on the value of the <c>accept</c> parameter passed into the constructor. 1012 * 1013 * <p> 1014 * Note that the order of these ranges are from high to low q-value. 1015 * 1016 * @return The list of media types. Never <jk>null</jk>. 1017 */ 1018 public final MediaRanges getMediaTypeRanges() { 1019 return accept; 1020 } 1021 1022 /** 1023 * Returns the first entry in the <c>accept</c> parameter passed into the constructor. 1024 * 1025 * <p> 1026 * This signifies the 'primary' media type for this serializer. 1027 * 1028 * @return The media type. Never <jk>null</jk>. 1029 */ 1030 public final MediaType getPrimaryMediaType() { 1031 return accepts[0]; 1032 } 1033 1034 /** 1035 * Returns the media types handled based on the value of the <c>accept</c> parameter passed into the constructor. 1036 * 1037 * <p> 1038 * The order of the media types are the same as those in the <c>accept</c> parameter. 1039 * 1040 * @return The list of media types. Never <jk>null</jk>. 1041 */ 1042 public final MediaType[] getAcceptMediaTypes() { 1043 return accepts; 1044 } 1045 1046 /** 1047 * Optional method that returns the response <c>Content-Type</c> for this serializer if it is different from 1048 * the matched media type. 1049 * 1050 * <p> 1051 * This method is specified to override the content type for this serializer. 1052 * For example, the {@link org.apache.juneau.json.SimpleJsonSerializer} class returns that it handles media type 1053 * <js>"text/json+simple"</js>, but returns <js>"text/json"</js> as the actual content type. 1054 * This allows clients to request specific 'flavors' of content using specialized <c>Accept</c> header values. 1055 * 1056 * <p> 1057 * This method is typically meaningless if the serializer is being used stand-alone (i.e. outside of a REST server 1058 * or client). 1059 * 1060 * @return The response content type. If <jk>null</jk>, then the matched media type is used. 1061 */ 1062 public final MediaType getResponseContentType() { 1063 return produces; 1064 } 1065 1066 //----------------------------------------------------------------------------------------------------------------- 1067 // Properties 1068 //----------------------------------------------------------------------------------------------------------------- 1069 1070 /** 1071 * Add <js>"_type"</js> properties when needed. 1072 * 1073 * @see #SERIALIZER_addBeanTypes 1074 * @return 1075 * <jk>true</jk> if <js>"_type"</js> properties added to beans if their type cannot be inferred 1076 * through reflection. 1077 */ 1078 protected boolean isAddBeanTypes() { 1079 return addBeanTypes; 1080 } 1081 1082 /** 1083 * Add type attribute to root nodes. 1084 * 1085 * @see #SERIALIZER_addRootType 1086 * @return 1087 * <jk>true</jk> if type property should be added to root node. 1088 */ 1089 protected final boolean isAddRootType() { 1090 return addRootType; 1091 } 1092 1093 /** 1094 * Serializer listener. 1095 * 1096 * @see #SERIALIZER_listener 1097 * @return 1098 * Class used to listen for errors and warnings that occur during serialization. 1099 */ 1100 protected final Class<? extends SerializerListener> getListener() { 1101 return listener; 1102 } 1103 1104 /** 1105 * Sort arrays and collections alphabetically. 1106 * 1107 * @see #SERIALIZER_sortCollections 1108 * @return 1109 * <jk>true</jk> if arrays and collections are copied and sorted before serialization. 1110 */ 1111 protected final boolean isSortCollections() { 1112 return sortCollections; 1113 } 1114 1115 /** 1116 * Sort maps alphabetically. 1117 * 1118 * @see #SERIALIZER_sortMaps 1119 * @return 1120 * <jk>true</jk> if maps are copied and sorted before serialization. 1121 */ 1122 protected final boolean isSortMaps() { 1123 return sortMaps; 1124 } 1125 1126 /** 1127 * Trim empty lists and arrays. 1128 * 1129 * @see #SERIALIZER_trimEmptyCollections 1130 * @return 1131 * <jk>true</jk> if empty lists and arrays are not serialized to the output. 1132 */ 1133 protected final boolean isTrimEmptyCollections() { 1134 return trimEmptyCollections; 1135 } 1136 1137 /** 1138 * Trim empty maps. 1139 * 1140 * @see #SERIALIZER_trimEmptyMaps 1141 * @return 1142 * <jk>true</jk> if empty map values are not serialized to the output. 1143 */ 1144 protected final boolean isTrimEmptyMaps() { 1145 return trimEmptyMaps; 1146 } 1147 1148 /** 1149 * Don't trim null bean property values. 1150 * 1151 * @see #SERIALIZER_keepNullProperties 1152 * @return 1153 * <jk>true</jk> if null bean values are serialized to the output. 1154 */ 1155 protected final boolean isKeepNullProperties() { 1156 return keepNullProperties; 1157 } 1158 1159 /** 1160 * Trim strings. 1161 * 1162 * @see #SERIALIZER_trimStrings 1163 * @return 1164 * <jk>true</jk> if string values will be trimmed of whitespace using {@link String#trim()} before being serialized. 1165 */ 1166 protected final boolean isTrimStrings() { 1167 return trimStrings; 1168 } 1169 1170 /** 1171 * URI context bean. 1172 * 1173 * @see #SERIALIZER_uriContext 1174 * @return 1175 * Bean used for resolution of URIs to absolute or root-relative form. 1176 */ 1177 protected final UriContext getUriContext() { 1178 return uriContext; 1179 } 1180 1181 /** 1182 * URI relativity. 1183 * 1184 * @see #SERIALIZER_uriRelativity 1185 * @return 1186 * Defines what relative URIs are relative to when serializing any of the following: 1187 */ 1188 protected final UriRelativity getUriRelativity() { 1189 return uriRelativity; 1190 } 1191 1192 /** 1193 * URI resolution. 1194 * 1195 * @see #SERIALIZER_uriResolution 1196 * @return 1197 * Defines the resolution level for URIs when serializing URIs. 1198 */ 1199 protected final UriResolution getUriResolution() { 1200 return uriResolution; 1201 } 1202 1203 //----------------------------------------------------------------------------------------------------------------- 1204 // Other methods 1205 //----------------------------------------------------------------------------------------------------------------- 1206 1207 @Override /* Context */ 1208 public OMap toMap() { 1209 return super.toMap() 1210 .a("Serializer", new DefaultFilteringOMap() 1211 .a("addBeanTypes", addBeanTypes) 1212 .a("keepNullProperties", keepNullProperties) 1213 .a("trimEmptyCollections", trimEmptyCollections) 1214 .a("trimEmptyMaps", trimEmptyMaps) 1215 .a("trimStrings", trimStrings) 1216 .a("sortCollections", sortCollections) 1217 .a("sortMaps", sortMaps) 1218 .a("addRootType", addRootType) 1219 .a("uriContext", uriContext) 1220 .a("uriResolution", uriResolution) 1221 .a("uriRelativity", uriRelativity) 1222 .a("listener", listener) 1223 ); 1224 } 1225}