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.urlencoding; 018 019import static org.apache.juneau.commons.utils.Utils.*; 020 021import java.lang.annotation.*; 022import java.nio.charset.*; 023import java.util.*; 024import java.util.concurrent.*; 025 026import org.apache.juneau.*; 027import org.apache.juneau.commons.collections.*; 028import org.apache.juneau.commons.function.*; 029import org.apache.juneau.commons.reflect.*; 030import org.apache.juneau.uon.*; 031 032/** 033 * Serializes POJO models to URL-encoded notation with UON-encoded values (a notation for URL-encoded query paramter values). 034 * 035 * <h5 class='section'>Media types:</h5> 036 * <p> 037 * Handles <c>Accept</c> types: <bc>application/x-www-form-urlencoded</bc> 038 * <p> 039 * Produces <c>Content-Type</c> types: <bc>application/x-www-form-urlencoded</bc> 040 * 041 * <h5 class='topic'>Description</h5> 042 * 043 * This serializer provides several serialization options. 044 * <br>Typically, one of the predefined DEFAULT serializers will be sufficient. 045 * <br>However, custom serializers can be constructed to fine-tune behavior. 046 * 047 * <p> 048 * The following shows a sample object defined in Javascript: 049 * <p class='bjson'> 050 * { 051 * id: 1, 052 * name: <js>'John Smith'</js>, 053 * uri: <js>'http://sample/addressBook/person/1'</js>, 054 * addressBookUri: <js>'http://sample/addressBook'</js>, 055 * birthDate: <js>'1946-08-12T00:00:00Z'</js>, 056 * otherIds: <jk>null</jk>, 057 * addresses: [ 058 * { 059 * uri: <js>'http://sample/addressBook/address/1'</js>, 060 * personUri: <js>'http://sample/addressBook/person/1'</js>, 061 * id: 1, 062 * street: <js>'100 Main Street'</js>, 063 * city: <js>'Anywhereville'</js>, 064 * state: <js>'NY'</js>, 065 * zip: 12345, 066 * isCurrent: <jk>true</jk>, 067 * } 068 * ] 069 * } 070 * </p> 071 * 072 * <p> 073 * Using the "strict" syntax defined in this document, the equivalent URL-encoded notation would be as follows: 074 * <p class='burlenc'> 075 * <ua>id</ua>=<un>1</un> 076 * &<ua>name</ua>=<us>'John+Smith'</us>, 077 * &<ua>uri</ua>=<us>http://sample/addressBook/person/1</us>, 078 * &<ua>addressBookUri</ua>=<us>http://sample/addressBook</us>, 079 * &<ua>birthDate</ua>=<us>1946-08-12T00:00:00Z</us>, 080 * &<ua>otherIds</ua>=<uk>null</uk>, 081 * &<ua>addresses</ua>=@( 082 * ( 083 * <ua>uri</ua>=<us>http://sample/addressBook/address/1</us>, 084 * <ua>personUri</ua>=<us>http://sample/addressBook/person/1</us>, 085 * <ua>id</ua>=<un>1</un>, 086 * <ua>street</ua>=<us>'100+Main+Street'</us>, 087 * <ua>city</ua>=<us>Anywhereville</us>, 088 * <ua>state</ua>=<us>NY</us>, 089 * <ua>zip</ua>=<un>12345</un>, 090 * <ua>isCurrent</ua>=<uk>true</uk> 091 * ) 092 * ) 093 * </p> 094 * 095 * <h5 class='section'>Example:</h5> 096 * <p class='bjava'> 097 * <jc>// Serialize a Map</jc> 098 * Map <jv>map</jv> = JsonMap.<jsm>ofJson</jsm>(<js>"{a:'b',c:1,d:false,e:['f',1,false],g:{h:'i'}}"</js>); 099 * 100 * <jc>// Serialize to value equivalent to JSON.</jc> 101 * <jc>// Produces "a=b&c=1&d=false&e=@(f,1,false)&g=(h=i)"</jc> 102 * String <jv>uenc</jv> = UrlEncodingSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>map</jv>); 103 * 104 * <jc>// Serialize a bean</jc> 105 * <jk>public class</jk> Person { 106 * <jk>public</jk> Person(String <jv>name</jv>); 107 * <jk>public</jk> String getName(); 108 * <jk>public int</jk> getAge(); 109 * <jk>public</jk> Address getAddress(); 110 * <jk>public boolean</jk> deceased; 111 * } 112 * 113 * <jk>public class</jk> Address { 114 * <jk>public</jk> String getStreet(); 115 * <jk>public</jk> String getCity(); 116 * <jk>public</jk> String getState(); 117 * <jk>public int</jk> getZip(); 118 * } 119 * 120 * Person <jv>person</jv> = <jk>new</jk> Person(<js>"John Doe"</js>, 23, <js>"123 Main St"</js>, <js>"Anywhere"</js>, <js>"NY"</js>, 12345, <jk>false</jk>); 121 * 122 * <jc>// Produces "name=John+Doe&age=23&address=(street='123+Main+St',city=Anywhere,state=NY,zip=12345)&deceased=false"</jc> 123 * String <jv>uenc</jv> = UrlEncodingSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>person</jv>); 124 * </p> 125 * 126 * <h5 class='section'>Notes:</h5><ul> 127 * <li class='note'>This class is thread safe and reusable. 128 * </ul> 129 * 130 * <h5 class='section'>See Also:</h5><ul> 131 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/UrlEncodingBasics">URL-Encoding Basics</a> 132 * </ul> 133 */ 134public class UrlEncodingSerializer extends UonSerializer implements UrlEncodingMetaProvider { 135 /** 136 * Builder class. 137 */ 138 public static class Builder extends UonSerializer.Builder { 139 140 private static final Cache<HashKey,UrlEncodingSerializer> CACHE = Cache.of(HashKey.class, UrlEncodingSerializer.class).build(); 141 142 boolean expandedParams; 143 144 /** 145 * Constructor, default settings. 146 */ 147 protected Builder() { 148 produces("application/x-www-form-urlencoded"); 149 expandedParams = env("UrlEncoding.expandedParams", false); 150 } 151 152 /** 153 * Copy constructor. 154 * 155 * @param copyFrom The builder to copy from. 156 */ 157 protected Builder(Builder copyFrom) { 158 super(copyFrom); 159 expandedParams = copyFrom.expandedParams; 160 } 161 162 /** 163 * Copy constructor. 164 * 165 * @param copyFrom The bean to copy from. 166 */ 167 protected Builder(UrlEncodingSerializer copyFrom) { 168 super(copyFrom); 169 expandedParams = copyFrom.expandedParams; 170 } 171 172 @Override /* Overridden from Builder */ 173 public Builder accept(String value) { 174 super.accept(value); 175 return this; 176 } 177 178 @Override /* Overridden from Builder */ 179 public Builder addBeanTypes() { 180 super.addBeanTypes(); 181 return this; 182 } 183 184 @Override /* Overridden from Builder */ 185 public Builder addBeanTypes(boolean value) { 186 super.addBeanTypes(value); 187 return this; 188 } 189 190 @Override /* Overridden from Builder */ 191 public Builder addBeanTypesUon() { 192 super.addBeanTypesUon(); 193 return this; 194 } 195 196 @Override /* Overridden from Builder */ 197 public Builder addBeanTypesUon(boolean value) { 198 super.addBeanTypesUon(value); 199 return this; 200 } 201 202 @Override /* Overridden from Builder */ 203 public Builder addRootType() { 204 super.addRootType(); 205 return this; 206 } 207 208 @Override /* Overridden from Builder */ 209 public Builder addRootType(boolean value) { 210 super.addRootType(value); 211 return this; 212 } 213 214 @Override /* Overridden from Builder */ 215 public Builder annotations(Annotation...values) { 216 super.annotations(values); 217 return this; 218 } 219 220 @Override /* Overridden from Builder */ 221 public Builder apply(AnnotationWorkList work) { 222 super.apply(work); 223 return this; 224 } 225 226 @Override /* Overridden from Builder */ 227 public Builder applyAnnotations(Class<?>...from) { 228 super.applyAnnotations(from); 229 return this; 230 } 231 232 @Override /* Overridden from Builder */ 233 public Builder applyAnnotations(Object...from) { 234 super.applyAnnotations(from); 235 return this; 236 } 237 238 @Override /* Overridden from Builder */ 239 public Builder beanClassVisibility(Visibility value) { 240 super.beanClassVisibility(value); 241 return this; 242 } 243 244 @Override /* Overridden from Builder */ 245 public Builder beanConstructorVisibility(Visibility value) { 246 super.beanConstructorVisibility(value); 247 return this; 248 } 249 250 @Override /* Overridden from Builder */ 251 public Builder beanContext(BeanContext value) { 252 super.beanContext(value); 253 return this; 254 } 255 256 @Override /* Overridden from Builder */ 257 public Builder beanContext(BeanContext.Builder value) { 258 super.beanContext(value); 259 return this; 260 } 261 262 @Override /* Overridden from Builder */ 263 public Builder beanDictionary(java.lang.Class<?>...values) { 264 super.beanDictionary(values); 265 return this; 266 } 267 268 @Override /* Overridden from Builder */ 269 public Builder beanFieldVisibility(Visibility value) { 270 super.beanFieldVisibility(value); 271 return this; 272 } 273 274 @Override /* Overridden from Builder */ 275 public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) { 276 super.beanInterceptor(on, value); 277 return this; 278 } 279 280 @Override /* Overridden from Builder */ 281 public Builder beanMapPutReturnsOldValue() { 282 super.beanMapPutReturnsOldValue(); 283 return this; 284 } 285 286 @Override /* Overridden from Builder */ 287 public Builder beanMethodVisibility(Visibility value) { 288 super.beanMethodVisibility(value); 289 return this; 290 } 291 292 @Override /* Overridden from Builder */ 293 public Builder beanProperties(Class<?> beanClass, String properties) { 294 super.beanProperties(beanClass, properties); 295 return this; 296 } 297 298 @Override /* Overridden from Builder */ 299 public Builder beanProperties(Map<String,Object> values) { 300 super.beanProperties(values); 301 return this; 302 } 303 304 @Override /* Overridden from Builder */ 305 public Builder beanProperties(String beanClassName, String properties) { 306 super.beanProperties(beanClassName, properties); 307 return this; 308 } 309 310 @Override /* Overridden from Builder */ 311 public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) { 312 super.beanPropertiesExcludes(beanClass, properties); 313 return this; 314 } 315 316 @Override /* Overridden from Builder */ 317 public Builder beanPropertiesExcludes(Map<String,Object> values) { 318 super.beanPropertiesExcludes(values); 319 return this; 320 } 321 322 @Override /* Overridden from Builder */ 323 public Builder beanPropertiesExcludes(String beanClassName, String properties) { 324 super.beanPropertiesExcludes(beanClassName, properties); 325 return this; 326 } 327 328 @Override /* Overridden from Builder */ 329 public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) { 330 super.beanPropertiesReadOnly(beanClass, properties); 331 return this; 332 } 333 334 @Override /* Overridden from Builder */ 335 public Builder beanPropertiesReadOnly(Map<String,Object> values) { 336 super.beanPropertiesReadOnly(values); 337 return this; 338 } 339 340 @Override /* Overridden from Builder */ 341 public Builder beanPropertiesReadOnly(String beanClassName, String properties) { 342 super.beanPropertiesReadOnly(beanClassName, properties); 343 return this; 344 } 345 346 @Override /* Overridden from Builder */ 347 public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) { 348 super.beanPropertiesWriteOnly(beanClass, properties); 349 return this; 350 } 351 352 @Override /* Overridden from Builder */ 353 public Builder beanPropertiesWriteOnly(Map<String,Object> values) { 354 super.beanPropertiesWriteOnly(values); 355 return this; 356 } 357 358 @Override /* Overridden from Builder */ 359 public Builder beanPropertiesWriteOnly(String beanClassName, String properties) { 360 super.beanPropertiesWriteOnly(beanClassName, properties); 361 return this; 362 } 363 364 @Override /* Overridden from Builder */ 365 public Builder beansRequireDefaultConstructor() { 366 super.beansRequireDefaultConstructor(); 367 return this; 368 } 369 370 @Override /* Overridden from Builder */ 371 public Builder beansRequireSerializable() { 372 super.beansRequireSerializable(); 373 return this; 374 } 375 376 @Override /* Overridden from Builder */ 377 public Builder beansRequireSettersForGetters() { 378 super.beansRequireSettersForGetters(); 379 return this; 380 } 381 382 @Override /* Overridden from Context.Builder */ 383 public UrlEncodingSerializer build() { 384 return cache(CACHE).build(UrlEncodingSerializer.class); 385 } 386 387 @Override /* Overridden from Builder */ 388 public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) { 389 super.cache(value); 390 return this; 391 } 392 393 @Override /* Overridden from Context.Builder */ 394 public Builder copy() { 395 return new Builder(this); 396 } 397 398 @Override /* Overridden from Builder */ 399 public Builder debug() { 400 super.debug(); 401 return this; 402 } 403 404 @Override /* Overridden from Builder */ 405 public Builder debug(boolean value) { 406 super.debug(value); 407 return this; 408 } 409 410 @Override /* Overridden from Builder */ 411 public Builder detectRecursions() { 412 super.detectRecursions(); 413 return this; 414 } 415 416 @Override /* Overridden from Builder */ 417 public Builder detectRecursions(boolean value) { 418 super.detectRecursions(value); 419 return this; 420 } 421 422 @Override /* Overridden from Builder */ 423 public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) { 424 super.dictionaryOn(on, values); 425 return this; 426 } 427 428 @Override /* Overridden from Builder */ 429 public Builder disableBeansRequireSomeProperties() { 430 super.disableBeansRequireSomeProperties(); 431 return this; 432 } 433 434 @Override /* Overridden from Builder */ 435 public Builder disableIgnoreMissingSetters() { 436 super.disableIgnoreMissingSetters(); 437 return this; 438 } 439 440 @Override /* Overridden from Builder */ 441 public Builder disableIgnoreTransientFields() { 442 super.disableIgnoreTransientFields(); 443 return this; 444 } 445 446 @Override /* Overridden from Builder */ 447 public Builder disableIgnoreUnknownNullBeanProperties() { 448 super.disableIgnoreUnknownNullBeanProperties(); 449 return this; 450 } 451 452 @Override /* Overridden from Builder */ 453 public Builder disableInterfaceProxies() { 454 super.disableInterfaceProxies(); 455 return this; 456 } 457 458 @Override /* Overridden from Builder */ 459 public Builder encoding() { 460 super.encoding(); 461 return this; 462 } 463 464 @Override /* Overridden from Builder */ 465 public <T> Builder example(Class<T> pojoClass, String json) { 466 super.example(pojoClass, json); 467 return this; 468 } 469 470 @Override /* Overridden from Builder */ 471 public <T> Builder example(Class<T> pojoClass, T o) { 472 super.example(pojoClass, o); 473 return this; 474 } 475 476 /** 477 * Serialize bean property collections/arrays as separate key/value pairs. 478 * 479 * <p> 480 * By default, serializing the array <c>[1,2,3]</c> results in <c>?key=$a(1,2,3)</c>. 481 * <br>When enabled, serializing the same array results in <c>?key=1&key=2&key=3</c>. 482 * 483 * <p> 484 * This option only applies to beans. 485 * 486 * <h5 class='section'>Notes:</h5><ul> 487 * <li class='note'> 488 * If parsing multi-part parameters, it's highly recommended to use <c>Collections</c> or <c>Lists</c> 489 * as bean property types instead of arrays since arrays have to be recreated from scratch every time a value 490 * is added to it. 491 * </ul> 492 * 493 * <h5 class='section'>Example:</h5> 494 * <p class='bjava'> 495 * <jc>// A sample bean.</jc> 496 * <jk>public class</jk> A { 497 * <jk>public</jk> String[] <jf>f1</jf> = {<js>"a"</js>,<js>"b"</js>}; 498 * <jk>public</jk> List<String> <jf>f2</jf> = Arrays.<jsm>asList</jsm>(<jk>new</jk> String[]{<js>"c"</js>,<js>"d"</js>}); 499 * } 500 * 501 * <jc>// Normal serializer.</jc> 502 * WriterSerializer <jv>serializer1</jv> = UrlEncodingSerializer.<jsf>DEFAULT</jsf>; 503 * 504 * <jc>// Expanded-params serializer.</jc> 505 * WriterSerializer <jv>serializer2</jv> = UrlEncodingSerializer.<jsm>create</jsm>().expandedParams().build(); 506 * 507 * <jc>// Produces "f1=(a,b)&f2=(c,d)"</jc> 508 * String <jv>out1</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> A()); 509 * 510 * <jc>// Produces "f1=a&f1=b&f2=c&f2=d"</jc> 511 * String <jv>out2</jv> = <jv>serializer2</jv>.serialize(<jk>new</jk> A()); 512 * </p> 513 * 514 * @return This object. 515 */ 516 public Builder expandedParams() { 517 return expandedParams(true); 518 } 519 520 /** 521 * Same as {@link #expandedParams()} but allows you to explicitly specify the value. 522 * 523 * @param value The value for this setting. 524 * @return This object. 525 */ 526 public Builder expandedParams(boolean value) { 527 expandedParams = value; 528 return this; 529 } 530 531 @Override /* Overridden from Builder */ 532 public Builder fileCharset(Charset value) { 533 super.fileCharset(value); 534 return this; 535 } 536 537 @Override /* Overridden from Builder */ 538 public Builder findFluentSetters() { 539 super.findFluentSetters(); 540 return this; 541 } 542 543 @Override /* Overridden from Builder */ 544 public Builder findFluentSetters(Class<?> on) { 545 super.findFluentSetters(on); 546 return this; 547 } 548 549 @Override /* Overridden from Context.Builder */ 550 public HashKey hashKey() { 551 // @formatter:off 552 return HashKey.of( 553 super.hashKey(), 554 expandedParams 555 ); 556 // @formatter:on 557 } 558 559 @Override /* Overridden from Builder */ 560 public Builder ignoreInvocationExceptionsOnGetters() { 561 super.ignoreInvocationExceptionsOnGetters(); 562 return this; 563 } 564 565 @Override /* Overridden from Builder */ 566 public Builder ignoreInvocationExceptionsOnSetters() { 567 super.ignoreInvocationExceptionsOnSetters(); 568 return this; 569 } 570 571 @Override /* Overridden from Builder */ 572 public Builder ignoreRecursions() { 573 super.ignoreRecursions(); 574 return this; 575 } 576 577 @Override /* Overridden from Builder */ 578 public Builder ignoreRecursions(boolean value) { 579 super.ignoreRecursions(value); 580 return this; 581 } 582 583 @Override /* Overridden from Builder */ 584 public Builder ignoreUnknownBeanProperties() { 585 super.ignoreUnknownBeanProperties(); 586 return this; 587 } 588 589 @Override /* Overridden from Builder */ 590 public Builder ignoreUnknownEnumValues() { 591 super.ignoreUnknownEnumValues(); 592 return this; 593 } 594 595 @Override /* Overridden from Builder */ 596 public Builder impl(Context value) { 597 super.impl(value); 598 return this; 599 } 600 601 @Override /* Overridden from Builder */ 602 public Builder implClass(Class<?> interfaceClass, Class<?> implClass) { 603 super.implClass(interfaceClass, implClass); 604 return this; 605 } 606 607 @Override /* Overridden from Builder */ 608 public Builder implClasses(Map<Class<?>,Class<?>> values) { 609 super.implClasses(values); 610 return this; 611 } 612 613 @Override /* Overridden from Builder */ 614 public Builder initialDepth(int value) { 615 super.initialDepth(value); 616 return this; 617 } 618 619 @Override /* Overridden from Builder */ 620 public Builder interfaceClass(Class<?> on, Class<?> value) { 621 super.interfaceClass(on, value); 622 return this; 623 } 624 625 @Override /* Overridden from Builder */ 626 public Builder interfaces(java.lang.Class<?>...value) { 627 super.interfaces(value); 628 return this; 629 } 630 631 @Override /* Overridden from Builder */ 632 public Builder keepNullProperties() { 633 super.keepNullProperties(); 634 return this; 635 } 636 637 @Override /* Overridden from Builder */ 638 public Builder keepNullProperties(boolean value) { 639 super.keepNullProperties(value); 640 return this; 641 } 642 643 @Override /* Overridden from Builder */ 644 public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) { 645 super.listener(value); 646 return this; 647 } 648 649 @Override /* Overridden from Builder */ 650 public Builder locale(Locale value) { 651 super.locale(value); 652 return this; 653 } 654 655 @Override /* Overridden from Builder */ 656 public Builder maxDepth(int value) { 657 super.maxDepth(value); 658 return this; 659 } 660 661 @Override /* Overridden from Builder */ 662 public Builder maxIndent(int value) { 663 super.maxIndent(value); 664 return this; 665 } 666 667 @Override /* Overridden from Builder */ 668 public Builder mediaType(MediaType value) { 669 super.mediaType(value); 670 return this; 671 } 672 673 @Override /* Overridden from Builder */ 674 public Builder notBeanClasses(java.lang.Class<?>...values) { 675 super.notBeanClasses(values); 676 return this; 677 } 678 679 @Override /* Overridden from Builder */ 680 public Builder notBeanPackages(String...values) { 681 super.notBeanPackages(values); 682 return this; 683 } 684 685 @Override /* Overridden from Builder */ 686 public Builder paramFormat(ParamFormat value) { 687 super.paramFormat(value); 688 return this; 689 } 690 691 @Override /* Overridden from Builder */ 692 public Builder paramFormatPlain() { 693 super.paramFormatPlain(); 694 return this; 695 } 696 697 @Override /* Overridden from Builder */ 698 public Builder produces(String value) { 699 super.produces(value); 700 return this; 701 } 702 703 @Override /* Overridden from Builder */ 704 public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) { 705 super.propertyNamer(on, value); 706 return this; 707 } 708 709 @Override /* Overridden from Builder */ 710 public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) { 711 super.propertyNamer(value); 712 return this; 713 } 714 715 @Override /* Overridden from Builder */ 716 public Builder quoteChar(char value) { 717 super.quoteChar(value); 718 return this; 719 } 720 721 @Override /* Overridden from Builder */ 722 public Builder quoteCharOverride(char value) { 723 super.quoteCharOverride(value); 724 return this; 725 } 726 727 @Override /* Overridden from Builder */ 728 public Builder quoteCharUon(char value) { 729 super.quoteCharUon(value); 730 return this; 731 } 732 733 @Override /* Overridden from Builder */ 734 public Builder sortCollections() { 735 super.sortCollections(); 736 return this; 737 } 738 739 @Override /* Overridden from Builder */ 740 public Builder sortCollections(boolean value) { 741 super.sortCollections(value); 742 return this; 743 } 744 745 @Override /* Overridden from Builder */ 746 public Builder sortMaps() { 747 super.sortMaps(); 748 return this; 749 } 750 751 @Override /* Overridden from Builder */ 752 public Builder sortMaps(boolean value) { 753 super.sortMaps(value); 754 return this; 755 } 756 757 @Override /* Overridden from Builder */ 758 public Builder sortProperties() { 759 super.sortProperties(); 760 return this; 761 } 762 763 @Override /* Overridden from Builder */ 764 public Builder sortProperties(java.lang.Class<?>...on) { 765 super.sortProperties(on); 766 return this; 767 } 768 769 @Override /* Overridden from Builder */ 770 public Builder sq() { 771 super.sq(); 772 return this; 773 } 774 775 @Override /* Overridden from Builder */ 776 public Builder stopClass(Class<?> on, Class<?> value) { 777 super.stopClass(on, value); 778 return this; 779 } 780 781 @Override /* Overridden from Builder */ 782 public Builder streamCharset(Charset value) { 783 super.streamCharset(value); 784 return this; 785 } 786 787 @Override /* Overridden from Builder */ 788 public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) { 789 super.swap(normalClass, swappedClass, swapFunction); 790 return this; 791 } 792 793 @Override /* Overridden from Builder */ 794 public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) { 795 super.swap(normalClass, swappedClass, swapFunction, unswapFunction); 796 return this; 797 } 798 799 @Override /* Overridden from Builder */ 800 public Builder swaps(Class<?>...values) { 801 super.swaps(values); 802 return this; 803 } 804 805 @Override /* Overridden from Builder */ 806 public Builder swaps(Object...values) { 807 super.swaps(values); 808 return this; 809 } 810 811 @Override /* Overridden from Builder */ 812 public Builder timeZone(TimeZone value) { 813 super.timeZone(value); 814 return this; 815 } 816 817 @Override /* Overridden from Builder */ 818 public Builder trimEmptyCollections() { 819 super.trimEmptyCollections(); 820 return this; 821 } 822 823 @Override /* Overridden from Builder */ 824 public Builder trimEmptyCollections(boolean value) { 825 super.trimEmptyCollections(value); 826 return this; 827 } 828 829 @Override /* Overridden from Builder */ 830 public Builder trimEmptyMaps() { 831 super.trimEmptyMaps(); 832 return this; 833 } 834 835 @Override /* Overridden from Builder */ 836 public Builder trimEmptyMaps(boolean value) { 837 super.trimEmptyMaps(value); 838 return this; 839 } 840 841 @Override /* Overridden from Builder */ 842 public Builder trimStrings() { 843 super.trimStrings(); 844 return this; 845 } 846 847 @Override /* Overridden from Builder */ 848 public Builder trimStrings(boolean value) { 849 super.trimStrings(value); 850 return this; 851 } 852 853 @Override /* Overridden from Builder */ 854 public Builder type(Class<? extends org.apache.juneau.Context> value) { 855 super.type(value); 856 return this; 857 } 858 859 @Override /* Overridden from Builder */ 860 public Builder typeName(Class<?> on, String value) { 861 super.typeName(on, value); 862 return this; 863 } 864 865 @Override /* Overridden from Builder */ 866 public Builder typePropertyName(Class<?> on, String value) { 867 super.typePropertyName(on, value); 868 return this; 869 } 870 871 @Override /* Overridden from Builder */ 872 public Builder typePropertyName(String value) { 873 super.typePropertyName(value); 874 return this; 875 } 876 877 @Override /* Overridden from Builder */ 878 public Builder uriContext(UriContext value) { 879 super.uriContext(value); 880 return this; 881 } 882 883 @Override /* Overridden from Builder */ 884 public Builder uriRelativity(UriRelativity value) { 885 super.uriRelativity(value); 886 return this; 887 } 888 889 @Override /* Overridden from Builder */ 890 public Builder uriResolution(UriResolution value) { 891 super.uriResolution(value); 892 return this; 893 } 894 895 @Override /* Overridden from Builder */ 896 public Builder useEnumNames() { 897 super.useEnumNames(); 898 return this; 899 } 900 901 @Override /* Overridden from Builder */ 902 public Builder useJavaBeanIntrospector() { 903 super.useJavaBeanIntrospector(); 904 return this; 905 } 906 907 @Override /* Overridden from Builder */ 908 public Builder useWhitespace() { 909 super.useWhitespace(); 910 return this; 911 } 912 913 @Override /* Overridden from Builder */ 914 public Builder useWhitespace(boolean value) { 915 super.useWhitespace(value); 916 return this; 917 } 918 919 @Override /* Overridden from Builder */ 920 public Builder ws() { 921 super.ws(); 922 return this; 923 } 924 } 925 926 /** 927 * Equivalent to <code>UrlEncodingSerializer.<jsm>create</jsm>().expandedParams().build();</code>. 928 */ 929 public static class Expanded extends UrlEncodingSerializer { 930 931 /** 932 * Constructor. 933 * 934 * @param builder The builder for this object. 935 */ 936 public Expanded(Builder builder) { 937 super(builder.expandedParams()); 938 } 939 } 940 941 /** 942 * Equivalent to <code>UrlEncodingSerializer.<jsm>create</jsm>().plainTextParts().build();</code>. 943 */ 944 public static class PlainText extends UrlEncodingSerializer { 945 946 /** 947 * Constructor. 948 * 949 * @param builder The builder for this object. 950 */ 951 public PlainText(Builder builder) { 952 super(builder.paramFormatPlain()); 953 } 954 } 955 956 /** 957 * Equivalent to <code>UrlEncodingSerializer.<jsm>create</jsm>().useWhitespace().build();</code>. 958 */ 959 public static class Readable extends UrlEncodingSerializer { 960 961 /** 962 * Constructor. 963 * 964 * @param builder The builder for this object. 965 */ 966 public Readable(Builder builder) { 967 super(builder.useWhitespace()); 968 } 969 } 970 971 /** Reusable instance of {@link UrlEncodingSerializer}, all default settings. */ 972 public static final UrlEncodingSerializer DEFAULT = new UrlEncodingSerializer(create()); 973 /** Reusable instance of {@link UrlEncodingSerializer.PlainText}. */ 974 public static final UrlEncodingSerializer DEFAULT_PLAINTEXT = new PlainText(create()); 975 976 /** Reusable instance of {@link UrlEncodingSerializer.Expanded}. */ 977 public static final UrlEncodingSerializer DEFAULT_EXPANDED = new Expanded(create()); 978 979 /** Reusable instance of {@link UrlEncodingSerializer.Readable}. */ 980 public static final UrlEncodingSerializer DEFAULT_READABLE = new Readable(create()); 981 982 /** 983 * Creates a new builder for this object. 984 * 985 * @return A new builder. 986 */ 987 public static Builder create() { 988 return new Builder(); 989 } 990 991 final boolean expandedParams; 992 993 private final Map<ClassMeta<?>,UrlEncodingClassMeta> urlEncodingClassMetas = new ConcurrentHashMap<>(); 994 private final Map<BeanPropertyMeta,UrlEncodingBeanPropertyMeta> urlEncodingBeanPropertyMetas = new ConcurrentHashMap<>(); 995 996 /** 997 * Constructor. 998 * 999 * @param builder The builder for this object. 1000 */ 1001 public UrlEncodingSerializer(Builder builder) { 1002 super(builder.encoding()); 1003 expandedParams = builder.expandedParams; 1004 } 1005 1006 @Override /* Overridden from Context */ 1007 public Builder copy() { 1008 return new Builder(this); 1009 } 1010 1011 @Override /* Overridden from Context */ 1012 public UrlEncodingSerializerSession.Builder createSession() { 1013 return UrlEncodingSerializerSession.create(this); 1014 } 1015 1016 @Override /* Overridden from Context */ 1017 public UrlEncodingSerializerSession getSession() { return createSession().build(); } 1018 1019 @Override /* Overridden from UrlEncodingMetaProvider */ 1020 public UrlEncodingBeanPropertyMeta getUrlEncodingBeanPropertyMeta(BeanPropertyMeta bpm) { 1021 if (bpm == null) 1022 return UrlEncodingBeanPropertyMeta.DEFAULT; 1023 UrlEncodingBeanPropertyMeta m = urlEncodingBeanPropertyMetas.get(bpm); 1024 if (m == null) { 1025 m = new UrlEncodingBeanPropertyMeta(bpm.getDelegateFor(), this); 1026 urlEncodingBeanPropertyMetas.put(bpm, m); 1027 } 1028 return m; 1029 } 1030 1031 @Override /* Overridden from UrlEncodingMetaProvider */ 1032 public UrlEncodingClassMeta getUrlEncodingClassMeta(ClassMeta<?> cm) { 1033 UrlEncodingClassMeta m = urlEncodingClassMetas.get(cm); 1034 if (m == null) { 1035 m = new UrlEncodingClassMeta(cm, this); 1036 urlEncodingClassMetas.put(cm, m); 1037 } 1038 return m; 1039 } 1040 1041 /** 1042 * Serialize bean property collections/arrays as separate key/value pairs. 1043 * 1044 * @see Builder#expandedParams() 1045 * @return 1046 * <jk>false</jk> if serializing the array <c>[1,2,3]</c> results in <c>?key=$a(1,2,3)</c>. 1047 * <br><jk>true</jk> if serializing the same array results in <c>?key=1&key=2&key=3</c>. 1048 */ 1049 protected final boolean isExpandedParams() { return expandedParams; } 1050 1051 @Override /* Overridden from UonSerializer */ 1052 protected FluentMap<String,Object> properties() { 1053 return super.properties() 1054 .a("expandedParams", expandedParams); 1055 } 1056}