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.serializer; 018 019import static org.apache.juneau.collections.JsonMap.*; 020import static org.apache.juneau.common.utils.Utils.*; 021 022import java.io.*; 023import java.lang.annotation.*; 024import java.util.*; 025import java.util.function.*; 026 027import org.apache.juneau.*; 028import org.apache.juneau.annotation.*; 029import org.apache.juneau.collections.*; 030import org.apache.juneau.internal.*; 031import org.apache.juneau.soap.*; 032import org.apache.juneau.utils.*; 033 034/** 035 * Parent class for all Juneau serializers. 036 * 037 * <h5 class='topic'>Description</h5> 038 * <p> 039 * Base serializer class that serves as the parent class for all serializers. 040 * 041 * <p> 042 * The purpose of this class is: 043 * <ul> 044 * <li>Maintain a read-only configuration state of a serializer. 045 * <li>Create session objects used for serializing POJOs (i.e. {@link SerializerSession}). 046 * <li>Provide convenience methods for serializing POJOs without having to construct session objects. 047 * </ul> 048 * 049 * <p> 050 * Subclasses should (but are not required to) extend directly from {@link OutputStreamSerializer} or {@link WriterSerializer} depending on 051 * whether it's a stream or character based serializer. 052 * 053 * <p> 054 * Subclasses must implement parsing via one of the following methods: 055 * <ul class='javatree'> 056 * <li class='jmp'>{@link #doSerialize(SerializerSession, SerializerPipe, Object)} 057 * <li class='jmp'>{@link SerializerSession#doSerialize(SerializerPipe, Object)} 058 * </ul> 059 * <br> 060 * 061 * <h5 class='section'>Notes:</h5><ul> 062 * <li class='note'>This class is thread safe and reusable. 063 * </ul> 064 * 065 * <h5 class='section'>See Also:</h5><ul> 066 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a> 067 068 * </ul> 069 */ 070public class Serializer extends BeanTraverseContext { 071 072 //------------------------------------------------------------------------------------------------------------------- 073 // Static 074 //------------------------------------------------------------------------------------------------------------------- 075 076 /** 077 * Creates a new builder for this object. 078 * 079 * @return A new builder. 080 */ 081 public static Builder create() { 082 return new Builder(); 083 } 084 085 /** 086 * Represents no Serializer. 087 */ 088 public static abstract class Null extends Serializer { 089 private Null(Builder builder) { 090 super(builder); 091 } 092 } 093 094 /** 095 * Instantiates a builder of the specified serializer class. 096 * 097 * <p> 098 * Looks for a public static method called <c>create</c> that returns an object that can be passed into a public 099 * or protected constructor of the class. 100 * 101 * @param c The builder to create. 102 * @return A new builder. 103 */ 104 public static Builder createSerializerBuilder(Class<? extends Serializer> c) { 105 return (Builder)Context.createBuilder(c); 106 } 107 108 //------------------------------------------------------------------------------------------------------------------- 109 // Builder 110 //------------------------------------------------------------------------------------------------------------------- 111 112 /** 113 * Builder class. 114 */ 115 public static class Builder extends BeanTraverseContext.Builder { 116 117 boolean addBeanTypes, addRootType, keepNullProperties, sortCollections, sortMaps, trimEmptyCollections, 118 trimEmptyMaps, trimStrings; 119 String produces, accept; 120 UriContext uriContext; 121 UriRelativity uriRelativity; 122 UriResolution uriResolution; 123 Class<? extends SerializerListener> listener; 124 125 /** 126 * Constructor, default settings. 127 */ 128 protected Builder() { 129 produces = null; 130 accept = null; 131 addBeanTypes = env("Serializer.addBeanTypes", false); 132 addRootType = env("Serializer.addRootType", false); 133 keepNullProperties = env("Serializer.keepNullProperties", false); 134 sortCollections = env("Serializer.sortCollections", false); 135 sortMaps = env("Serializer.sortMaps", false); 136 trimEmptyCollections = env("Serializer.trimEmptyCollections", false); 137 trimEmptyMaps = env("Serializer.trimEmptyMaps", false); 138 trimStrings = env("Serializer.trimStrings", false); 139 uriContext = UriContext.DEFAULT; 140 uriRelativity = UriRelativity.RESOURCE; 141 uriResolution = UriResolution.NONE; 142 listener = null; 143 } 144 145 /** 146 * Copy constructor. 147 * 148 * @param copyFrom The bean to copy from. 149 */ 150 protected Builder(Serializer copyFrom) { 151 super(copyFrom); 152 produces = copyFrom.produces; 153 accept = copyFrom.accept; 154 addBeanTypes = copyFrom.addBeanTypes; 155 addRootType = copyFrom.addRootType; 156 keepNullProperties = copyFrom.keepNullProperties; 157 sortCollections = copyFrom.sortCollections; 158 sortMaps = copyFrom.sortMaps; 159 trimEmptyCollections = copyFrom.trimEmptyCollections; 160 trimEmptyMaps = copyFrom.trimEmptyMaps; 161 trimStrings = copyFrom.trimStrings; 162 uriContext = copyFrom.uriContext; 163 uriRelativity = copyFrom.uriRelativity; 164 uriResolution = copyFrom.uriResolution; 165 listener = copyFrom.listener; 166 } 167 168 /** 169 * Copy constructor. 170 * 171 * @param copyFrom The builder to copy from. 172 */ 173 protected Builder(Builder copyFrom) { 174 super(copyFrom); 175 produces = copyFrom.produces; 176 accept = copyFrom.accept; 177 addBeanTypes = copyFrom.addBeanTypes; 178 addRootType = copyFrom.addRootType; 179 keepNullProperties = copyFrom.keepNullProperties; 180 sortCollections = copyFrom.sortCollections; 181 sortMaps = copyFrom.sortMaps; 182 trimEmptyCollections = copyFrom.trimEmptyCollections; 183 trimEmptyMaps = copyFrom.trimEmptyMaps; 184 trimStrings = copyFrom.trimStrings; 185 uriContext = copyFrom.uriContext; 186 uriRelativity = copyFrom.uriRelativity; 187 uriResolution = copyFrom.uriResolution; 188 listener = copyFrom.listener; 189 } 190 191 @Override /* Context.Builder */ 192 public Builder copy() { 193 return new Builder(this); 194 } 195 196 @Override /* Context.Builder */ 197 public Serializer build() { 198 return build(Serializer.class); 199 } 200 201 @Override /* Context.Builder */ 202 public HashKey hashKey() { 203 return HashKey.of( 204 super.hashKey(), 205 produces, 206 accept, 207 addBeanTypes, 208 addRootType, 209 keepNullProperties, 210 sortCollections, 211 sortMaps, 212 trimEmptyCollections, 213 trimEmptyMaps, 214 trimStrings, 215 uriContext, 216 uriRelativity, 217 uriResolution, 218 listener 219 ); 220 } 221 222 //----------------------------------------------------------------------------------------------------------------- 223 // Properties 224 //----------------------------------------------------------------------------------------------------------------- 225 226 /** 227 * Specifies the media type that this serializer produces. 228 * 229 * @param value The value for this setting. 230 * @return This object. 231 */ 232 public Builder produces(String value) { 233 this.produces = value; 234 return this; 235 } 236 237 /** 238 * Returns the current value for the 'produces' property. 239 * 240 * @return The current value for the 'produces' property. 241 */ 242 public String getProduces() { 243 return produces; 244 } 245 246 /** 247 * Specifies the accept media types that the serializer can handle. 248 * 249 * <p> 250 * Can contain meta-characters per the <c>media-type</c> specification of <a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">RFC2616/14.1</a> 251 * <p> 252 * If empty, then assumes the only media type supported is <c>produces</c>. 253 * <p> 254 * For example, if this serializer produces <js>"application/json"</js> but should handle media types of 255 * <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be: 256 * <p class='bjava'> 257 * <jv>builder</jv>.produces(<js>"application/json"</js>); 258 * <jv>builder</jv>.accept(<js>"application/json,text/json"</js>); 259 * </p> 260 * <p> 261 * The accept value can also contain q-values. 262 * 263 * @param value The value for this setting. 264 * @return This object. 265 */ 266 public Builder accept(String value) { 267 this.accept = value; 268 return this; 269 } 270 271 /** 272 * Returns the current value for the 'accept' property. 273 * 274 * @return The current value for the 'accept' property. 275 */ 276 public String getAccept() { 277 return accept; 278 } 279 280 /** 281 * Add <js>"_type"</js> properties when needed. 282 * 283 * <p> 284 * When enabled, <js>"_type"</js> properties will be added to beans if their type cannot be inferred 285 * through reflection. 286 * 287 * <p> 288 * This is used to recreate the correct objects during parsing if the object types cannot be inferred. 289 * <br>For example, when serializing a <c>Map<String,Object></c> field where the bean class cannot be determined from 290 * the type of the values. 291 * 292 * <p> 293 * Note the differences between the following settings: 294 * <ul class='javatree'> 295 * <li class='jf'>{@link #addRootType()} - Affects whether <js>'_type'</js> is added to root node. 296 * <li class='jf'>{@link #addBeanTypes()} - Affects whether <js>'_type'</js> is added to any nodes. 297 * </ul> 298 * 299 * <h5 class='section'>Example:</h5> 300 * <p class='bjava'> 301 * <jc>// Create a serializer that adds _type to nodes.</jc> 302 * WriterSerializer <jv>serializer</jv> = JsonSerializer 303 * .<jsm>create</jsm>() 304 * .addBeanTypes() 305 * .build(); 306 * 307 * <jc>// Our map of beans to serialize.</jc> 308 * <ja>@Bean</ja>(typeName=<js>"mybean"</js>) 309 * <jk>public class</jk> MyBean { 310 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 311 * } 312 * JsonMap <jv>myMap</jv> = JsonMap.of(<js>"foo"</js>, <jk>new</jk> MyBean()); 313 * 314 * <jc>// Will contain: {"foo":{"_type":"mybean","foo":"bar"}}</jc> 315 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>myMap</jv>); 316 * </p> 317 * 318 * @return This object. 319 */ 320 public Builder addBeanTypes() { 321 return addBeanTypes(true); 322 } 323 324 /** 325 * Same as {@link #addBeanTypes()} but allows you to explicitly specify the value. 326 * 327 * @param value The value for this setting. 328 * @return This object. 329 */ 330 public Builder addBeanTypes(boolean value) { 331 addBeanTypes = value; 332 return this; 333 } 334 335 /** 336 * Add type attribute to root nodes. 337 * 338 * <p> 339 * When enabled, <js>"_type"</js> properties will be added to top-level beans. 340 * 341 * <p> 342 * When disabled, it is assumed that the parser knows the exact Java POJO type being parsed, and therefore top-level 343 * type information that might normally be included to determine the data type will not be serialized. 344 * 345 * <p> 346 * For example, when serializing a top-level POJO with a {@link Bean#typeName() @Bean(typeName)} value, a 347 * <js>'_type'</js> attribute will only be added when this setting is enabled. 348 * 349 * <p> 350 * Note the differences between the following settings: 351 * <ul class='javatree'> 352 * <li class='jf'>{@link #addRootType()} - Affects whether <js>'_type'</js> is added to root node. 353 * <li class='jf'>{@link #addBeanTypes()} - Affects whether <js>'_type'</js> is added to any nodes. 354 * </ul> 355 * 356 * <h5 class='section'>Example:</h5> 357 * <p class='bjava'> 358 * <jc>// Create a serializer that adds _type to root node.</jc> 359 * WriterSerializer <jv>serializer</jv>= JsonSerializer 360 * .<jsm>create</jsm>() 361 * .addRootType() 362 * .build(); 363 * 364 * <jc>// Our bean to serialize.</jc> 365 * <ja>@Bean</ja>(typeName=<js>"mybean"</js>) 366 * <jk>public class</jk> MyBean { 367 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 368 * } 369 * 370 * <jc>// Will contain: {"_type":"mybean","foo":"bar"}</jc> 371 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 372 * </p> 373 * 374 * @return This object. 375 */ 376 public Builder addRootType() { 377 return addRootType(true); 378 } 379 380 /** 381 * Same as {@link #addRootType()} but allows you to explicitly specify the value. 382 * 383 * @param value The value for this setting. 384 * @return This object. 385 */ 386 public Builder addRootType(boolean value) { 387 addRootType = value; 388 return this; 389 } 390 391 /** 392 * Don't trim null bean property values. 393 * 394 * <p> 395 * When enabled, null bean values will be serialized to the output. 396 * 397 * <h5 class='section'>Notes:</h5><ul> 398 * <li class='note'>Not enabling this setting will cause <c>Map</c>s with <jk>null</jk> values to be lost during parsing. 399 * </ul> 400 * 401 * <h5 class='section'>Example:</h5> 402 * <p class='bjava'> 403 * <jc>// Create a serializer that serializes null properties.</jc> 404 * WriterSerializer <jv>serializer</jv> = JsonSerializer 405 * .<jsm>create</jsm>() 406 * .keepNullProperties() 407 * .build(); 408 * 409 * <jc>// Our bean to serialize.</jc> 410 * <jk>public class</jk> MyBean { 411 * <jk>public</jk> String <jf>foo</jf> = <jk>null</jk>; 412 * } 413 * 414 * <jc>// Will contain "{foo:null}".</jc> 415 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 416 * </p> 417 * 418 * @return This object. 419 */ 420 public Builder keepNullProperties() { 421 return keepNullProperties(true); 422 } 423 424 /** 425 * Same as {@link #keepNullProperties()} but allows you to explicitly specify the value. 426 * 427 * @param value The value for this setting. 428 * @return This object. 429 */ 430 public Builder keepNullProperties(boolean value) { 431 keepNullProperties = value; 432 return this; 433 } 434 435 /** 436 * Serializer listener. 437 * 438 * <p> 439 * Class used to listen for errors and warnings that occur during serialization. 440 * 441 * <h5 class='section'>Example:</h5> 442 * <p class='bjava'> 443 * <jc>// Define our serializer listener.</jc> 444 * <jc>// Simply captures all errors.</jc> 445 * <jk>public class</jk> MySerializerListener <jk>extends</jk> SerializerListener { 446 * 447 * <jc>// A simple property to store our events.</jc> 448 * <jk>public</jk> List<String> <jf>events</jf> = <jk>new</jk> LinkedList<>(); 449 * 450 * <ja>@Override</ja> 451 * <jk>public</jk> <T> <jk>void</jk> onError(SerializerSession <jv>session</jv>, Throwable <jv>throwable</jv>, String <jv>msg</jv>) { 452 * <jf>events</jf>.add(<jv>session</jv>.getLastLocation() + <js>","</js> + <jv>msg</jv> + <js>","</js> + <jv>throwable</jv>); 453 * } 454 * } 455 * 456 * <jc>// Create a serializer using our listener.</jc> 457 * WriterSerializer <jv>serializer</jv> = JsonSerializer 458 * .<jsm>create</jsm>() 459 * .listener(MySerializerListener.<jk>class</jk>) 460 * .build(); 461 * 462 * <jc>// Create a session object.</jc> 463 * <jc>// Needed because listeners are created per-session.</jc> 464 * <jk>try</jk> (WriterSerializerSession <jv>session</jv> = <jv>serializer</jv>.createSession()) { 465 * 466 * <jc>// Serialize a bean.</jc> 467 * String <jv>json</jv> = <jv>session</jv>.serialize(<jk>new</jk> MyBean()); 468 * 469 * <jc>// Get the listener.</jc> 470 * MySerializerListener <jv>listener</jv> = <jv>session</jv>.getListener(MySerializerListener.<jk>class</jk>); 471 * 472 * <jc>// Dump the results to the console.</jc> 473 * Json5.<jsf>DEFAULT</jsf>.println(<jv>listener</jv>.<jf>events</jf>); 474 * } 475 * </p> 476 * 477 * @param value 478 * The new value for this property. 479 * @return This object. 480 */ 481 public Builder listener(Class<? extends SerializerListener> value) { 482 listener = value; 483 return this; 484 } 485 486 /** 487 * Sort arrays and collections alphabetically. 488 * 489 * <p> 490 * When enabled, copies and sorts the contents of arrays and collections before serializing them. 491 * 492 * <p> 493 * Note that this introduces a performance penalty since it requires copying the existing collection. 494 * 495 * <h5 class='section'>Example:</h5> 496 * <p class='bjava'> 497 * <jc>// Create a serializer that sorts arrays and collections before serialization.</jc> 498 * WriterSerializer <jv>serializer</jv> = JsonSerializer 499 * .<jsm>create</jsm>() 500 * .sortCollections() 501 * .build(); 502 * 503 * <jc>// An unsorted array</jc> 504 * String[] <jv>myArray</jv> = {<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>}; 505 * 506 * <jc>// Produces ["bar","baz","foo"]</jc> 507 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>myArray</jv>); 508 * </p> 509 * 510 * @return This object. 511 */ 512 public Builder sortCollections() { 513 return sortCollections(true); 514 } 515 516 /** 517 * Same as {@link #sortCollections()} but allows you to explicitly specify the value. 518 * 519 * @param value The value for this setting. 520 * @return This object. 521 */ 522 public Builder sortCollections(boolean value) { 523 sortCollections = value; 524 return this; 525 } 526 527 /** 528 * Sort maps alphabetically. 529 * 530 * <p> 531 * When enabled, copies and sorts the contents of maps by their keys before serializing them. 532 * 533 * <p> 534 * Note that this introduces a performance penalty. 535 * 536 * <h5 class='section'>Example:</h5> 537 * <p class='bjava'> 538 * <jc>// Create a serializer that sorts maps before serialization.</jc> 539 * WriterSerializer <jv>serializer</jv> = JsonSerializer 540 * .<jsm>create</jsm>() 541 * .sortMaps() 542 * .build(); 543 * 544 * <jc>// An unsorted map.</jc> 545 * JsonMap <jv>myMap</jv> = JsonMap.<jsm>of</jsm>(<js>"foo"</js>,1,<js>"bar"</js>,2,<js>"baz"</js>,3); 546 * 547 * <jc>// Produces {"bar":2,"baz":3,"foo":1}</jc> 548 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>myMap</jv>); 549 * </p> 550 * 551 * @return This object. 552 */ 553 public Builder sortMaps() { 554 return sortMaps(true); 555 } 556 557 /** 558 * Same as {@link #sortMaps()} but allows you to explicitly specify the value. 559 * 560 * @param value The value for this setting. 561 * @return This object. 562 */ 563 public Builder sortMaps(boolean value) { 564 sortMaps = value; 565 return this; 566 } 567 568 /** 569 * Trim empty lists and arrays. 570 * 571 * <p> 572 * When enabled, empty lists and arrays will not be serialized. 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 empty list values will be lost. 579 * <li> 580 * Bean properties with empty list values will not be set. 581 * </ul> 582 * 583 * <h5 class='section'>Example:</h5> 584 * <p class='bjava'> 585 * <jc>// Create a serializer that skips empty arrays and collections.</jc> 586 * WriterSerializer <jv>serializer</jv> = JsonSerializer 587 * .<jsm>create</jsm>() 588 * .trimEmptyCollections() 589 * .build(); 590 * 591 * <jc>// A bean with a field with an empty array.</jc> 592 * <jk>public class</jk> MyBean { 593 * <jk>public</jk> String[] <jf>foo</jf> = {}; 594 * } 595 * 596 * <jc>// Produces {}</jc> 597 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 598 * </p> 599 * 600 * @return This object. 601 */ 602 public Builder trimEmptyCollections() { 603 return trimEmptyCollections(true); 604 } 605 606 /** 607 * Same as {@link #trimEmptyCollections()} but allows you to explicitly specify the value. 608 * 609 * @param value The value for this setting. 610 * @return This object. 611 */ 612 public Builder trimEmptyCollections(boolean value) { 613 trimEmptyCollections = value; 614 return this; 615 } 616 617 /** 618 * Trim empty maps. 619 * 620 * <p> 621 * When enabled, empty map values will not be serialized to the output. 622 * 623 * <p> 624 * Note that enabling this setting has the following effects on parsing: 625 * <ul class='spaced-list'> 626 * <li> 627 * Bean properties with empty map values will not be set. 628 * </ul> 629 * 630 * <h5 class='section'>Example:</h5> 631 * <p class='bjava'> 632 * <jc>// Create a serializer that skips empty maps.</jc> 633 * WriterSerializer <jv>serializer</jv> = JsonSerializer 634 * .<jsm>create</jsm>() 635 * .trimEmptyMaps() 636 * .build(); 637 * 638 * <jc>// A bean with a field with an empty map.</jc> 639 * <jk>public class</jk> MyBean { 640 * <jk>public</jk> JsonMap <jf>foo</jf> = JsonMap.<jsm>of</jsm>(); 641 * } 642 * 643 * <jc>// Produces {}</jc> 644 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean()); 645 * </p> 646 * 647 * @return This object. 648 */ 649 public Builder trimEmptyMaps() { 650 return trimEmptyMaps(true); 651 } 652 653 /** 654 * Same as {@link #trimEmptyMaps()} but allows you to explicitly specify the value. 655 * 656 * @param value The value for this setting. 657 * @return This object. 658 */ 659 public Builder trimEmptyMaps(boolean value) { 660 trimEmptyMaps = value; 661 return this; 662 } 663 664 /** 665 * Trim strings. 666 * 667 * <p> 668 * When enabled, string values will be trimmed of whitespace using {@link String#trim()} before being serialized. 669 * 670 * <h5 class='section'>Example:</h5> 671 * <p class='bjava'> 672 * <jc>// Create a serializer that trims strings before serialization.</jc> 673 * WriterSerializer <jv>serializer</jv> = JsonSerializer 674 * .<jsm>create</jsm>() 675 * .trimStrings() 676 * .build(); 677 * 678 * <jc>// A map with space-padded keys/values</jc> 679 * JsonMap <jv>myMap</jv> = JsonMap.<jsm>of</jsm>(<js>" foo "</js>, <js>" bar "</js>); 680 * 681 * <jc>// Produces "{foo:'bar'}"</jc> 682 * String <jv>json</jv> = <jv>serializer</jv>.toString(<jv>myMap</jv>); 683 * </p> 684 * 685 * @return This object. 686 */ 687 public Builder trimStrings() { 688 return trimStrings(true); 689 } 690 691 /** 692 * Same as {@link #trimStrings()} but allows you to explicitly specify the value. 693 * 694 * @param value The value for this setting. 695 * @return This object. 696 */ 697 public Builder trimStrings(boolean value) { 698 trimStrings = value; 699 return this; 700 } 701 702 /** 703 * URI context bean. 704 * 705 * <p> 706 * Bean used for resolution of URIs to absolute or root-relative form. 707 * 708 * <h5 class='section'>Example:</h5> 709 * <p class='bjava'> 710 * <jc>// Our URI contextual information.</jc> 711 * String <jv>authority</jv> = <js>"http://localhost:10000"</js>; 712 * String <jv>contextRoot</jv> = <js>"/myContext"</js>; 713 * String <jv>servletPath</jv> = <js>"/myServlet"</js>; 714 * String <jv>pathInfo</jv> = <js>"/foo"</js>; 715 * 716 * <jc>// Create a UriContext object.</jc> 717 * UriContext <jv>uriContext</jv> = <jk>new</jk> UriContext(<jv>authority</jv>, <jv>contextRoot</jv>, <jv>servletPath</jv>, <jv>pathInfo</jv>); 718 * 719 * <jc>// Associate it with our serializer.</jc> 720 * WriterSerializer <jv>serializer</jv> = JsonSerializer 721 * .<jsm>create</jsm>() 722 * .uriContext(<jv>uriContext</jv>) 723 * .uriRelativity(<jsf>RESOURCE</jsf>) <jc>// Assume relative paths are relative to servlet.</jc> 724 * .uriResolution(<jsf>ABSOLUTE</jsf>) <jc>// Serialize URLs as absolute paths.</jc> 725 * .build(); 726 * 727 * <jc>// A relative URL</jc> 728 * URL <jv>myUrl</jv> = <jk>new</jk> URL(<js>"bar"</js>); 729 * 730 * <jc>// Produces "http://localhost:10000/myContext/myServlet/foo/bar"</jc> 731 * String <jv>json</jv> = <jv>serializer</jv>.toString(<jv>myUrl</jv>); 732 * </p> 733 * 734 * <h5 class='section'>See Also:</h5><ul> 735 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a> 736 * </ul> 737 * 738 * @param value The new value for this property. 739 * @return This object. 740 */ 741 public Builder uriContext(UriContext value) { 742 uriContext = value; 743 return this; 744 } 745 746 /** 747 * URI relativity. 748 * 749 * <p> 750 * Defines what relative URIs are relative to when serializing any of the following: 751 * <ul> 752 * <li>{@link java.net.URI} 753 * <li>{@link java.net.URL} 754 * <li>Properties and classes annotated with {@link Uri @Uri} 755 * </ul> 756 * 757 * <p> 758 * See {@link #uriContext(UriContext)} for examples. 759 * 760 * <ul class='values javatree'> 761 * <li class='jf'>{@link org.apache.juneau.UriRelativity#RESOURCE} 762 * - Relative URIs should be considered relative to the servlet URI. 763 * <li class='jf'>{@link org.apache.juneau.UriRelativity#PATH_INFO} 764 * - Relative URIs should be considered relative to the request URI. 765 * </ul> 766 * 767 * <h5 class='section'>See Also:</h5><ul> 768 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a> 769 * </ul> 770 * 771 * @param value 772 * The new value for this property. 773 * <br>The default is {@link UriRelativity#RESOURCE} 774 * @return This object. 775 */ 776 public Builder uriRelativity(UriRelativity value) { 777 uriRelativity = value; 778 return this; 779 } 780 781 /** 782 * URI resolution. 783 * 784 * <p> 785 * Defines the resolution level for URIs when serializing any of the following: 786 * <ul> 787 * <li>{@link java.net.URI} 788 * <li>{@link java.net.URL} 789 * <li>Properties and classes annotated with {@link Uri @Uri} 790 * </ul> 791 * 792 * <p> 793 * See {@link #uriContext(UriContext)} for examples. 794 * 795 * <ul class='values javatree'> 796 * <li class='jf'>{@link UriResolution#ABSOLUTE} 797 * - Resolve to an absolute URL (e.g. <js>"http://host:port/context-root/servlet-path/path-info"</js>). 798 * <li class='jf'>{@link UriResolution#ROOT_RELATIVE} 799 * - Resolve to a root-relative URL (e.g. <js>"/context-root/servlet-path/path-info"</js>). 800 * <li class='jf'>{@link UriResolution#NONE} 801 * - Don't do any URL resolution. 802 * </ul> 803 * 804 * <h5 class='section'>See Also:</h5><ul> 805 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a> 806 * </ul> 807 * 808 * @param value 809 * The new value for this property. 810 * <br>The default is {@link UriResolution#NONE} 811 * @return This object. 812 */ 813 public Builder uriResolution(UriResolution value) { 814 uriResolution = value; 815 return this; 816 } 817 @Override /* Overridden from Builder */ 818 public Builder annotations(Annotation...values) { 819 super.annotations(values); 820 return this; 821 } 822 823 @Override /* Overridden from Builder */ 824 public Builder apply(AnnotationWorkList work) { 825 super.apply(work); 826 return this; 827 } 828 829 @Override /* Overridden from Builder */ 830 public Builder applyAnnotations(Object...from) { 831 super.applyAnnotations(from); 832 return this; 833 } 834 835 @Override /* Overridden from Builder */ 836 public Builder applyAnnotations(Class<?>...from) { 837 super.applyAnnotations(from); 838 return this; 839 } 840 841 @Override /* Overridden from Builder */ 842 public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) { 843 super.cache(value); 844 return this; 845 } 846 847 @Override /* Overridden from Builder */ 848 public Builder debug() { 849 super.debug(); 850 return this; 851 } 852 853 @Override /* Overridden from Builder */ 854 public Builder debug(boolean value) { 855 super.debug(value); 856 return this; 857 } 858 859 @Override /* Overridden from Builder */ 860 public Builder impl(Context value) { 861 super.impl(value); 862 return this; 863 } 864 865 @Override /* Overridden from Builder */ 866 public Builder type(Class<? extends org.apache.juneau.Context> value) { 867 super.type(value); 868 return this; 869 } 870 871 @Override /* Overridden from Builder */ 872 public Builder beanClassVisibility(Visibility value) { 873 super.beanClassVisibility(value); 874 return this; 875 } 876 877 @Override /* Overridden from Builder */ 878 public Builder beanConstructorVisibility(Visibility value) { 879 super.beanConstructorVisibility(value); 880 return this; 881 } 882 883 @Override /* Overridden from Builder */ 884 public Builder beanContext(BeanContext value) { 885 super.beanContext(value); 886 return this; 887 } 888 889 @Override /* Overridden from Builder */ 890 public Builder beanContext(BeanContext.Builder value) { 891 super.beanContext(value); 892 return this; 893 } 894 895 @Override /* Overridden from Builder */ 896 public Builder beanDictionary(java.lang.Class<?>...values) { 897 super.beanDictionary(values); 898 return this; 899 } 900 901 @Override /* Overridden from Builder */ 902 public Builder beanFieldVisibility(Visibility value) { 903 super.beanFieldVisibility(value); 904 return this; 905 } 906 907 @Override /* Overridden from Builder */ 908 public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) { 909 super.beanInterceptor(on, value); 910 return this; 911 } 912 913 @Override /* Overridden from Builder */ 914 public Builder beanMapPutReturnsOldValue() { 915 super.beanMapPutReturnsOldValue(); 916 return this; 917 } 918 919 @Override /* Overridden from Builder */ 920 public Builder beanMethodVisibility(Visibility value) { 921 super.beanMethodVisibility(value); 922 return this; 923 } 924 925 @Override /* Overridden from Builder */ 926 public Builder beanProperties(Map<String,Object> values) { 927 super.beanProperties(values); 928 return this; 929 } 930 931 @Override /* Overridden from Builder */ 932 public Builder beanProperties(Class<?> beanClass, String properties) { 933 super.beanProperties(beanClass, properties); 934 return this; 935 } 936 937 @Override /* Overridden from Builder */ 938 public Builder beanProperties(String beanClassName, String properties) { 939 super.beanProperties(beanClassName, properties); 940 return this; 941 } 942 943 @Override /* Overridden from Builder */ 944 public Builder beanPropertiesExcludes(Map<String,Object> values) { 945 super.beanPropertiesExcludes(values); 946 return this; 947 } 948 949 @Override /* Overridden from Builder */ 950 public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) { 951 super.beanPropertiesExcludes(beanClass, properties); 952 return this; 953 } 954 955 @Override /* Overridden from Builder */ 956 public Builder beanPropertiesExcludes(String beanClassName, String properties) { 957 super.beanPropertiesExcludes(beanClassName, properties); 958 return this; 959 } 960 961 @Override /* Overridden from Builder */ 962 public Builder beanPropertiesReadOnly(Map<String,Object> values) { 963 super.beanPropertiesReadOnly(values); 964 return this; 965 } 966 967 @Override /* Overridden from Builder */ 968 public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) { 969 super.beanPropertiesReadOnly(beanClass, properties); 970 return this; 971 } 972 973 @Override /* Overridden from Builder */ 974 public Builder beanPropertiesReadOnly(String beanClassName, String properties) { 975 super.beanPropertiesReadOnly(beanClassName, properties); 976 return this; 977 } 978 979 @Override /* Overridden from Builder */ 980 public Builder beanPropertiesWriteOnly(Map<String,Object> values) { 981 super.beanPropertiesWriteOnly(values); 982 return this; 983 } 984 985 @Override /* Overridden from Builder */ 986 public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) { 987 super.beanPropertiesWriteOnly(beanClass, properties); 988 return this; 989 } 990 991 @Override /* Overridden from Builder */ 992 public Builder beanPropertiesWriteOnly(String beanClassName, String properties) { 993 super.beanPropertiesWriteOnly(beanClassName, properties); 994 return this; 995 } 996 997 @Override /* Overridden from Builder */ 998 public Builder beansRequireDefaultConstructor() { 999 super.beansRequireDefaultConstructor(); 1000 return this; 1001 } 1002 1003 @Override /* Overridden from Builder */ 1004 public Builder beansRequireSerializable() { 1005 super.beansRequireSerializable(); 1006 return this; 1007 } 1008 1009 @Override /* Overridden from Builder */ 1010 public Builder beansRequireSettersForGetters() { 1011 super.beansRequireSettersForGetters(); 1012 return this; 1013 } 1014 1015 @Override /* Overridden from Builder */ 1016 public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) { 1017 super.dictionaryOn(on, values); 1018 return this; 1019 } 1020 1021 @Override /* Overridden from Builder */ 1022 public Builder disableBeansRequireSomeProperties() { 1023 super.disableBeansRequireSomeProperties(); 1024 return this; 1025 } 1026 1027 @Override /* Overridden from Builder */ 1028 public Builder disableIgnoreMissingSetters() { 1029 super.disableIgnoreMissingSetters(); 1030 return this; 1031 } 1032 1033 @Override /* Overridden from Builder */ 1034 public Builder disableIgnoreTransientFields() { 1035 super.disableIgnoreTransientFields(); 1036 return this; 1037 } 1038 1039 @Override /* Overridden from Builder */ 1040 public Builder disableIgnoreUnknownNullBeanProperties() { 1041 super.disableIgnoreUnknownNullBeanProperties(); 1042 return this; 1043 } 1044 1045 @Override /* Overridden from Builder */ 1046 public Builder disableInterfaceProxies() { 1047 super.disableInterfaceProxies(); 1048 return this; 1049 } 1050 1051 @Override /* Overridden from Builder */ 1052 public <T> Builder example(Class<T> pojoClass, T o) { 1053 super.example(pojoClass, o); 1054 return this; 1055 } 1056 1057 @Override /* Overridden from Builder */ 1058 public <T> Builder example(Class<T> pojoClass, String json) { 1059 super.example(pojoClass, json); 1060 return this; 1061 } 1062 1063 @Override /* Overridden from Builder */ 1064 public Builder findFluentSetters() { 1065 super.findFluentSetters(); 1066 return this; 1067 } 1068 1069 @Override /* Overridden from Builder */ 1070 public Builder findFluentSetters(Class<?> on) { 1071 super.findFluentSetters(on); 1072 return this; 1073 } 1074 1075 @Override /* Overridden from Builder */ 1076 public Builder ignoreInvocationExceptionsOnGetters() { 1077 super.ignoreInvocationExceptionsOnGetters(); 1078 return this; 1079 } 1080 1081 @Override /* Overridden from Builder */ 1082 public Builder ignoreInvocationExceptionsOnSetters() { 1083 super.ignoreInvocationExceptionsOnSetters(); 1084 return this; 1085 } 1086 1087 @Override /* Overridden from Builder */ 1088 public Builder ignoreUnknownBeanProperties() { 1089 super.ignoreUnknownBeanProperties(); 1090 return this; 1091 } 1092 1093 @Override /* Overridden from Builder */ 1094 public Builder ignoreUnknownEnumValues() { 1095 super.ignoreUnknownEnumValues(); 1096 return this; 1097 } 1098 1099 @Override /* Overridden from Builder */ 1100 public Builder implClass(Class<?> interfaceClass, Class<?> implClass) { 1101 super.implClass(interfaceClass, implClass); 1102 return this; 1103 } 1104 1105 @Override /* Overridden from Builder */ 1106 public Builder implClasses(Map<Class<?>,Class<?>> values) { 1107 super.implClasses(values); 1108 return this; 1109 } 1110 1111 @Override /* Overridden from Builder */ 1112 public Builder interfaceClass(Class<?> on, Class<?> value) { 1113 super.interfaceClass(on, value); 1114 return this; 1115 } 1116 1117 @Override /* Overridden from Builder */ 1118 public Builder interfaces(java.lang.Class<?>...value) { 1119 super.interfaces(value); 1120 return this; 1121 } 1122 1123 @Override /* Overridden from Builder */ 1124 public Builder locale(Locale value) { 1125 super.locale(value); 1126 return this; 1127 } 1128 1129 @Override /* Overridden from Builder */ 1130 public Builder mediaType(MediaType value) { 1131 super.mediaType(value); 1132 return this; 1133 } 1134 1135 @Override /* Overridden from Builder */ 1136 public Builder notBeanClasses(java.lang.Class<?>...values) { 1137 super.notBeanClasses(values); 1138 return this; 1139 } 1140 1141 @Override /* Overridden from Builder */ 1142 public Builder notBeanPackages(String...values) { 1143 super.notBeanPackages(values); 1144 return this; 1145 } 1146 1147 @Override /* Overridden from Builder */ 1148 public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) { 1149 super.propertyNamer(value); 1150 return this; 1151 } 1152 1153 @Override /* Overridden from Builder */ 1154 public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) { 1155 super.propertyNamer(on, value); 1156 return this; 1157 } 1158 1159 @Override /* Overridden from Builder */ 1160 public Builder sortProperties() { 1161 super.sortProperties(); 1162 return this; 1163 } 1164 1165 @Override /* Overridden from Builder */ 1166 public Builder sortProperties(java.lang.Class<?>...on) { 1167 super.sortProperties(on); 1168 return this; 1169 } 1170 1171 @Override /* Overridden from Builder */ 1172 public Builder stopClass(Class<?> on, Class<?> value) { 1173 super.stopClass(on, value); 1174 return this; 1175 } 1176 1177 @Override /* Overridden from Builder */ 1178 public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) { 1179 super.swap(normalClass, swappedClass, swapFunction); 1180 return this; 1181 } 1182 1183 @Override /* Overridden from Builder */ 1184 public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) { 1185 super.swap(normalClass, swappedClass, swapFunction, unswapFunction); 1186 return this; 1187 } 1188 1189 @Override /* Overridden from Builder */ 1190 public Builder swaps(Object...values) { 1191 super.swaps(values); 1192 return this; 1193 } 1194 1195 @Override /* Overridden from Builder */ 1196 public Builder swaps(Class<?>...values) { 1197 super.swaps(values); 1198 return this; 1199 } 1200 1201 @Override /* Overridden from Builder */ 1202 public Builder timeZone(TimeZone value) { 1203 super.timeZone(value); 1204 return this; 1205 } 1206 1207 @Override /* Overridden from Builder */ 1208 public Builder typeName(Class<?> on, String value) { 1209 super.typeName(on, value); 1210 return this; 1211 } 1212 1213 @Override /* Overridden from Builder */ 1214 public Builder typePropertyName(String value) { 1215 super.typePropertyName(value); 1216 return this; 1217 } 1218 1219 @Override /* Overridden from Builder */ 1220 public Builder typePropertyName(Class<?> on, String value) { 1221 super.typePropertyName(on, value); 1222 return this; 1223 } 1224 1225 @Override /* Overridden from Builder */ 1226 public Builder useEnumNames() { 1227 super.useEnumNames(); 1228 return this; 1229 } 1230 1231 @Override /* Overridden from Builder */ 1232 public Builder useJavaBeanIntrospector() { 1233 super.useJavaBeanIntrospector(); 1234 return this; 1235 } 1236 1237 @Override /* Overridden from Builder */ 1238 public Builder detectRecursions() { 1239 super.detectRecursions(); 1240 return this; 1241 } 1242 1243 @Override /* Overridden from Builder */ 1244 public Builder detectRecursions(boolean value) { 1245 super.detectRecursions(value); 1246 return this; 1247 } 1248 1249 @Override /* Overridden from Builder */ 1250 public Builder ignoreRecursions() { 1251 super.ignoreRecursions(); 1252 return this; 1253 } 1254 1255 @Override /* Overridden from Builder */ 1256 public Builder ignoreRecursions(boolean value) { 1257 super.ignoreRecursions(value); 1258 return this; 1259 } 1260 1261 @Override /* Overridden from Builder */ 1262 public Builder initialDepth(int value) { 1263 super.initialDepth(value); 1264 return this; 1265 } 1266 1267 @Override /* Overridden from Builder */ 1268 public Builder maxDepth(int value) { 1269 super.maxDepth(value); 1270 return this; 1271 } 1272 } 1273 1274 //------------------------------------------------------------------------------------------------------------------- 1275 // Instance 1276 //------------------------------------------------------------------------------------------------------------------- 1277 1278 final String produces, accept; 1279 final boolean 1280 addBeanTypes, 1281 keepNullProperties, 1282 trimEmptyCollections, 1283 trimEmptyMaps, 1284 trimStrings, 1285 sortCollections, 1286 sortMaps, 1287 addRootType; 1288 final UriContext uriContext; 1289 final UriResolution uriResolution; 1290 final UriRelativity uriRelativity; 1291 final Class<? extends SerializerListener> listener; 1292 1293 private final MediaRanges acceptRanges; 1294 private final MediaType[] acceptMediaTypes; 1295 private final MediaType producesMediaType; 1296 1297 /** 1298 * Constructor 1299 * 1300 * @param builder The builder this object. 1301 */ 1302 protected Serializer(Builder builder) { 1303 super(builder); 1304 1305 produces = builder.produces; 1306 accept = builder.accept; 1307 addBeanTypes = builder.addBeanTypes; 1308 keepNullProperties = builder.keepNullProperties; 1309 trimEmptyCollections = builder.trimEmptyCollections; 1310 trimEmptyMaps = builder.trimEmptyMaps; 1311 trimStrings = builder.trimStrings; 1312 sortCollections = builder.sortCollections; 1313 sortMaps = builder.sortMaps; 1314 addRootType = builder.addRootType; 1315 uriContext = builder.uriContext; 1316 uriResolution = builder.uriResolution; 1317 uriRelativity = builder.uriRelativity; 1318 listener = builder.listener; 1319 1320 this.producesMediaType = MediaType.of(produces); 1321 this.acceptRanges = accept != null ? MediaRanges.of(accept) : MediaRanges.of(produces); 1322 this.acceptMediaTypes = builder.accept != null ? MediaType.ofAll(splita(builder.accept)) : new MediaType[] {this.producesMediaType}; 1323 } 1324 1325 @Override /* Context */ 1326 public Builder copy() { 1327 return new Builder(this); 1328 } 1329 1330 @Override /* Context */ 1331 public SerializerSession.Builder createSession() { 1332 return SerializerSession.create(this); 1333 } 1334 1335 @Override /* Context */ 1336 public SerializerSession getSession() { 1337 return createSession().build(); 1338 } 1339 1340 /** 1341 * Returns <jk>true</jk> if this serializer subclasses from {@link WriterSerializer}. 1342 * 1343 * @return <jk>true</jk> if this serializer subclasses from {@link WriterSerializer}. 1344 */ 1345 public boolean isWriterSerializer() { 1346 return false; 1347 } 1348 1349 //----------------------------------------------------------------------------------------------------------------- 1350 // Convenience methods 1351 //----------------------------------------------------------------------------------------------------------------- 1352 1353 /** 1354 * Serializes a POJO to the specified output stream or writer. 1355 * 1356 * <p> 1357 * Equivalent to calling <c>serializer.createSession().serialize(o, output);</c> 1358 * 1359 * @param o The object to serialize. 1360 * @param output 1361 * The output object. 1362 * <br>Character-based serializers can handle the following output class types: 1363 * <ul> 1364 * <li>{@link Writer} 1365 * <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream. 1366 * <li>{@link File} - Output will be written as system-default encoded stream. 1367 * <li>{@link StringBuilder} - Output will be written to the specified string builder. 1368 * </ul> 1369 * <br>Stream-based serializers can handle the following output class types: 1370 * <ul> 1371 * <li>{@link OutputStream} 1372 * <li>{@link File} 1373 * </ul> 1374 * @throws SerializeException If a problem occurred trying to convert the output. 1375 * @throws IOException Thrown by the underlying stream. 1376 */ 1377 public final void serialize(Object o, Object output) throws SerializeException, IOException { 1378 getSession().serialize(o, output); 1379 } 1380 1381 /** 1382 * Shortcut method for serializing objects directly to either a <c>String</c> or <code><jk>byte</jk>[]</code> 1383 * depending on the serializer type. 1384 * 1385 * @param o The object to serialize. 1386 * @return 1387 * The serialized object. 1388 * <br>Character-based serializers will return a <c>String</c> 1389 * <br>Stream-based serializers will return a <code><jk>byte</jk>[]</code> 1390 * @throws SerializeException If a problem occurred trying to convert the output. 1391 */ 1392 public Object serialize(Object o) throws SerializeException { 1393 return getSession().serialize(o); 1394 } 1395 1396 /** 1397 * Convenience method for serializing an object to a String. 1398 * 1399 * <p> 1400 * For writer-based serializers, this is identical to calling {@link #serialize(Object)}. 1401 * <br>For stream-based serializers, this converts the returned byte array to a string based on 1402 * the {@link OutputStreamSerializer.Builder#binaryFormat(BinaryFormat)} setting. 1403 * 1404 * @param o The object to serialize. 1405 * @return The output serialized to a string. 1406 * @throws SerializeException If a problem occurred trying to convert the output. 1407 */ 1408 public final String serializeToString(Object o) throws SerializeException { 1409 return getSession().serializeToString(o); 1410 } 1411 1412 //----------------------------------------------------------------------------------------------------------------- 1413 // Other methods 1414 //----------------------------------------------------------------------------------------------------------------- 1415 1416 /** 1417 * Serializes a POJO to the specified pipe. 1418 * 1419 * @param session The current session. 1420 * @param pipe Where to send the output from the serializer. 1421 * @param o The object to serialize. 1422 * @throws IOException Thrown by underlying stream. 1423 * @throws SerializeException Problem occurred trying to serialize object. 1424 */ 1425 protected void doSerialize(SerializerSession session, SerializerPipe pipe, Object o) throws IOException, SerializeException { 1426 throw new UnsupportedOperationException(); 1427 } 1428 1429 /** 1430 * Optional method that specifies HTTP request headers for this serializer. 1431 * 1432 * <p> 1433 * For example, {@link SoapXmlSerializer} needs to set a <c>SOAPAction</c> header. 1434 * 1435 * <p> 1436 * This method is typically meaningless if the serializer is being used stand-alone (i.e. outside of a REST server 1437 * or client). 1438 * 1439 * @param session The current session. 1440 * @return 1441 * The HTTP headers to set on HTTP requests. 1442 * Never <jk>null</jk>. 1443 */ 1444 public Map<String,String> getResponseHeaders(SerializerSession session) { 1445 return Collections.emptyMap(); 1446 } 1447 1448 /** 1449 * Returns the media types handled based on the value of the <c>accept</c> parameter passed into the constructor. 1450 * 1451 * <p> 1452 * Note that the order of these ranges are from high to low q-value. 1453 * 1454 * @return The list of media types. Never <jk>null</jk>. 1455 */ 1456 public final MediaRanges getMediaTypeRanges() { 1457 return acceptRanges; 1458 } 1459 1460 /** 1461 * Returns the first entry in the <c>accept</c> parameter passed into the constructor. 1462 * 1463 * <p> 1464 * This signifies the 'primary' media type for this serializer. 1465 * 1466 * @return The media type. Never <jk>null</jk>. 1467 */ 1468 public final MediaType getPrimaryMediaType() { 1469 return acceptMediaTypes[0]; 1470 } 1471 1472 /** 1473 * Performs an action on the media types handled based on the value of the <c>accept</c> parameter passed into the constructor. 1474 * 1475 * <p> 1476 * The order of the media types are the same as those in the <c>accept</c> parameter. 1477 * 1478 * @param action The action to perform on the media types. 1479 * @return This object. 1480 */ 1481 public final Serializer forEachAcceptMediaType(Consumer<MediaType> action) { 1482 for (MediaType m : acceptMediaTypes) 1483 action.accept(m); 1484 return this; 1485 } 1486 1487 /** 1488 * Optional method that returns the response <c>Content-Type</c> for this serializer if it is different from 1489 * the matched media type. 1490 * 1491 * <p> 1492 * This method is specified to override the content type for this serializer. 1493 * For example, the {@link org.apache.juneau.json.Json5Serializer} class returns that it handles media type 1494 * <js>"text/json5"</js>, but returns <js>"text/json"</js> as the actual content type. 1495 * This allows clients to request specific 'flavors' of content using specialized <c>Accept</c> header values. 1496 * 1497 * <p> 1498 * This method is typically meaningless if the serializer is being used stand-alone (i.e. outside of a REST server 1499 * or client). 1500 * 1501 * @return The response content type. If <jk>null</jk>, then the matched media type is used. 1502 */ 1503 public final MediaType getResponseContentType() { 1504 return producesMediaType; 1505 } 1506 1507 //----------------------------------------------------------------------------------------------------------------- 1508 // Properties 1509 //----------------------------------------------------------------------------------------------------------------- 1510 1511 /** 1512 * Add <js>"_type"</js> properties when needed. 1513 * 1514 * @see Serializer.Builder#addBeanTypes() 1515 * @return 1516 * <jk>true</jk> if <js>"_type"</js> properties added to beans if their type cannot be inferred 1517 * through reflection. 1518 */ 1519 protected boolean isAddBeanTypes() { 1520 return addBeanTypes; 1521 } 1522 1523 /** 1524 * Add type attribute to root nodes. 1525 * 1526 * @see Serializer.Builder#addRootType() 1527 * @return 1528 * <jk>true</jk> if type property should be added to root node. 1529 */ 1530 protected final boolean isAddRootType() { 1531 return addRootType; 1532 } 1533 1534 /** 1535 * Serializer listener. 1536 * 1537 * @see Serializer.Builder#listener(Class) 1538 * @return 1539 * Class used to listen for errors and warnings that occur during serialization. 1540 */ 1541 protected final Class<? extends SerializerListener> getListener() { 1542 return listener; 1543 } 1544 1545 /** 1546 * Sort arrays and collections alphabetically. 1547 * 1548 * @see Serializer.Builder#sortCollections() 1549 * @return 1550 * <jk>true</jk> if arrays and collections are copied and sorted before serialization. 1551 */ 1552 protected final boolean isSortCollections() { 1553 return sortCollections; 1554 } 1555 1556 /** 1557 * Sort maps alphabetically. 1558 * 1559 * @see Serializer.Builder#sortMaps() 1560 * @return 1561 * <jk>true</jk> if maps are copied and sorted before serialization. 1562 */ 1563 protected final boolean isSortMaps() { 1564 return sortMaps; 1565 } 1566 1567 /** 1568 * Trim empty lists and arrays. 1569 * 1570 * @see Serializer.Builder#trimEmptyCollections() 1571 * @return 1572 * <jk>true</jk> if empty lists and arrays are not serialized to the output. 1573 */ 1574 protected final boolean isTrimEmptyCollections() { 1575 return trimEmptyCollections; 1576 } 1577 1578 /** 1579 * Trim empty maps. 1580 * 1581 * @see Serializer.Builder#trimEmptyMaps() 1582 * @return 1583 * <jk>true</jk> if empty map values are not serialized to the output. 1584 */ 1585 protected final boolean isTrimEmptyMaps() { 1586 return trimEmptyMaps; 1587 } 1588 1589 /** 1590 * Don't trim null bean property values. 1591 * 1592 * @see Serializer.Builder#keepNullProperties() 1593 * @return 1594 * <jk>true</jk> if null bean values are serialized to the output. 1595 */ 1596 protected final boolean isKeepNullProperties() { 1597 return keepNullProperties; 1598 } 1599 1600 /** 1601 * Trim strings. 1602 * 1603 * @see Serializer.Builder#trimStrings() 1604 * @return 1605 * <jk>true</jk> if string values will be trimmed of whitespace using {@link String#trim()} before being serialized. 1606 */ 1607 protected final boolean isTrimStrings() { 1608 return trimStrings; 1609 } 1610 1611 /** 1612 * URI context bean. 1613 * 1614 * @see Serializer.Builder#uriContext(UriContext) 1615 * @return 1616 * Bean used for resolution of URIs to absolute or root-relative form. 1617 */ 1618 protected final UriContext getUriContext() { 1619 return uriContext; 1620 } 1621 1622 /** 1623 * URI relativity. 1624 * 1625 * @see Serializer.Builder#uriRelativity(UriRelativity) 1626 * @return 1627 * Defines what relative URIs are relative to when serializing any of the following: 1628 */ 1629 protected final UriRelativity getUriRelativity() { 1630 return uriRelativity; 1631 } 1632 1633 /** 1634 * URI resolution. 1635 * 1636 * @see Serializer.Builder#uriResolution(UriResolution) 1637 * @return 1638 * Defines the resolution level for URIs when serializing URIs. 1639 */ 1640 protected final UriResolution getUriResolution() { 1641 return uriResolution; 1642 } 1643 1644 //----------------------------------------------------------------------------------------------------------------- 1645 // Other methods 1646 //----------------------------------------------------------------------------------------------------------------- 1647 1648 @Override /* Context */ 1649 protected JsonMap properties() { 1650 return filteredMap() 1651 .append("addBeanTypes", addBeanTypes) 1652 .append("keepNullProperties", keepNullProperties) 1653 .append("trimEmptyCollections", trimEmptyCollections) 1654 .append("trimEmptyMaps", trimEmptyMaps) 1655 .append("trimStrings", trimStrings) 1656 .append("sortCollections", sortCollections) 1657 .append("sortMaps", sortMaps) 1658 .append("addRootType", addRootType) 1659 .append("uriContext", uriContext) 1660 .append("uriResolution", uriResolution) 1661 .append("uriRelativity", uriRelativity) 1662 .append("listener", listener); 1663 } 1664}