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.html; 014 015import static org.apache.juneau.collections.JsonMap.*; 016import static org.apache.juneau.common.internal.ThrowableUtils.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018 019import java.lang.annotation.*; 020import java.lang.reflect.*; 021import java.nio.charset.*; 022import java.util.*; 023import java.util.function.*; 024import java.util.regex.*; 025 026import org.apache.juneau.*; 027import org.apache.juneau.collections.*; 028import org.apache.juneau.internal.*; 029import org.apache.juneau.svl.*; 030import org.apache.juneau.utils.*; 031import org.apache.juneau.xml.*; 032 033/** 034 * Serializes POJOs to HTTP responses as HTML documents. 035 * 036 * <h5 class='topic'>Media types</h5> 037 * <p> 038 * Handles <c>Accept</c> types: <bc>text/html</bc> 039 * <p> 040 * Produces <c>Content-Type</c> types: <bc>text/html</bc> 041 * 042 * <h5 class='topic'>Description</h5> 043 * <p> 044 * Same as {@link HtmlSerializer}, except wraps the response in <code><xt><html></code>, 045 * <code><xt><head></code>, and <code><xt><body></code> tags so that it can be rendered in a browser. 046 * 047 * <p> 048 * Configurable properties are typically specified via <ja>@HtmlDocConfig</ja>. 049 * 050 * <h5 class='section'>Example:</h5> 051 * <p class='bjava'> 052 * <ja>@Rest</ja>( 053 * messages=<js>"nls/AddressBookResource"</js>, 054 * title=<js>"$L{title}"</js>, 055 * description=<js>"$L{description}"</js> 056 * ) 057 * <ja>@HtmlDocConfig</ja>( 058 * navlinks={ 059 * <js>"api: servlet:/api"</js>, 060 * <js>"doc: doc"</js> 061 * } 062 * ) 063 * <jk>public class</jk> AddressBookResource <jk>extends</jk> BasicRestServlet { 064 * </p> 065 * 066 * <p> 067 * The <c>$L{...}</c> variable represent localized strings pulled from the resource bundle identified by the 068 * <c>messages</c> annotation. 069 * <br>These variables are replaced at runtime based on the HTTP request locale. 070 * <br>Several built-in runtime variable types are defined, and the API can be extended to include user-defined variables. 071 * 072 * <h5 class='section'>Notes:</h5><ul> 073 * <li class='note'>This class is thread safe and reusable. 074 * </ul> 075 * 076 * <h5 class='section'>See Also:</h5><ul> 077 * <li class='link'><a class="doclink" href="../../../../index.html#jm.HtmlDetails">HTML Details</a> 078 079 * </ul> 080 */ 081public class HtmlDocSerializer extends HtmlStrippedDocSerializer { 082 083 //------------------------------------------------------------------------------------------------------------------- 084 // Static 085 //------------------------------------------------------------------------------------------------------------------- 086 087 private static final String[] EMPTY_ARRAY = {}; 088 089 /** Default serializer, all default settings. */ 090 public static final HtmlDocSerializer DEFAULT = new HtmlDocSerializer(create()); 091 092 /** 093 * Creates a new builder for this object. 094 * 095 * @return A new builder. 096 */ 097 public static Builder create() { 098 return new Builder(); 099 } 100 101 //------------------------------------------------------------------------------------------------------------------- 102 // Builder 103 //------------------------------------------------------------------------------------------------------------------- 104 105 /** 106 * Builder class. 107 */ 108 @FluentSetters 109 public static class Builder extends HtmlStrippedDocSerializer.Builder { 110 111 private static final Cache<HashKey,HtmlDocSerializer> CACHE = Cache.of(HashKey.class, HtmlDocSerializer.class).build(); 112 113 List<String> aside, footer, head, header, nav, navlinks, script, style, stylesheet; 114 AsideFloat asideFloat; 115 String noResultsMessage; 116 boolean nowrap, resolveBodyVars; 117 Class<? extends HtmlDocTemplate> template; 118 List<Class<? extends HtmlWidget>> widgets; 119 120 /** 121 * Constructor, default settings. 122 */ 123 protected Builder() { 124 produces("text/html"); 125 accept("text/html"); 126 asideFloat = AsideFloat.RIGHT; 127 noResultsMessage = "<p>no results</p>"; 128 template = BasicHtmlDocTemplate.class; 129 } 130 131 /** 132 * Copy constructor. 133 * 134 * @param copyFrom The bean to copy from. 135 */ 136 protected Builder(HtmlDocSerializer copyFrom) { 137 super(copyFrom); 138 aside = copy(copyFrom.aside); 139 footer = copy(copyFrom.footer); 140 head = copy(copyFrom.head); 141 header = copy(copyFrom.header); 142 nav = copy(copyFrom.nav); 143 navlinks = copy(copyFrom.navlinks); 144 script = copy(copyFrom.script); 145 style = copy(copyFrom.style); 146 stylesheet = copy(copyFrom.stylesheet); 147 asideFloat = copyFrom.asideFloat; 148 noResultsMessage = copyFrom.noResultsMessage; 149 nowrap = copyFrom.nowrap; 150 resolveBodyVars = copyFrom.resolveBodyVars; 151 template = copyFrom.template; 152 widgets = copy(copyFrom.widgets); 153 } 154 155 /** 156 * Copy constructor. 157 * 158 * @param copyFrom The builder to copy from. 159 */ 160 protected Builder(Builder copyFrom) { 161 super(copyFrom); 162 aside = copy(copyFrom.aside); 163 footer = copy(copyFrom.footer); 164 head = copy(copyFrom.head); 165 header = copy(copyFrom.header); 166 nav = copy(copyFrom.nav); 167 navlinks = copy(copyFrom.navlinks); 168 script = copy(copyFrom.script); 169 style = copy(copyFrom.style); 170 stylesheet = copy(copyFrom.stylesheet); 171 asideFloat = copyFrom.asideFloat; 172 noResultsMessage = copyFrom.noResultsMessage; 173 nowrap = copyFrom.nowrap; 174 resolveBodyVars = copyFrom.resolveBodyVars; 175 template = copyFrom.template; 176 widgets = copy(copyFrom.widgets); 177 } 178 179 @Override /* Context.Builder */ 180 public Builder copy() { 181 return new Builder(this); 182 } 183 184 @Override /* Context.Builder */ 185 public HtmlDocSerializer build() { 186 return cache(CACHE).build(HtmlDocSerializer.class); 187 } 188 189 @Override /* Context.Builder */ 190 public HashKey hashKey() { 191 return HashKey.of( 192 super.hashKey(), 193 aside, 194 footer, 195 head, 196 header, 197 nav, 198 navlinks, 199 script, 200 style, 201 stylesheet, 202 asideFloat, 203 noResultsMessage, 204 nowrap, 205 resolveBodyVars, 206 template, 207 widgets 208 ); 209 } 210 211 //----------------------------------------------------------------------------------------------------------------- 212 // Properties 213 //----------------------------------------------------------------------------------------------------------------- 214 215 /** 216 * Aside section contents. 217 * 218 * <p> 219 * Allows you to specify the contents of the aside section on the HTML page. 220 * The aside section floats on the right of the page for providing content supporting the serialized content of 221 * the page. 222 * 223 * <p> 224 * By default, the aside section is empty. 225 * 226 * <h5 class='section'>Example:</h5> 227 * <p class='bjava'> 228 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 229 * .<jsm>create</jsm>() 230 * .aside( 231 * <js>"<ul>"</js>, 232 * <js>" <li>Item 1"</js>, 233 * <js>" <li>Item 2"</js>, 234 * <js>" <li>Item 3"</js>, 235 * <js>"</ul>"</js> 236 * ) 237 * .build(); 238 * </p> 239 * 240 * <h5 class='section'>Notes:</h5><ul> 241 * <li class='note'> 242 * Format: HTML 243 * <li class='note'> 244 * Supports <a class="doclink" href="../../../../index.html#jrs.SvlVariables">SVL Variables</a> 245 * (e.g. <js>"$L{my.localized.variable}"</js>). 246 * <li class='note'> 247 * A value of <js>"NONE"</js> can be used to force no value. 248 * <li class='note'> 249 * The parent value can be included by adding the literal <js>"INHERIT"</js> as a value. 250 * <li class='note'> 251 * Multiple values are combined with newlines into a single string. 252 * <li class='note'> 253 * On methods, this value is inherited from the <ja>@HtmlDocConfig</ja> annotation on the servlet/resource class. 254 * <li class='note'> 255 * On servlet/resource classes, this value is inherited from the <ja>@HtmlDocConfig</ja> annotation on the 256 * parent class. 257 * </ul> 258 * 259 * @param value 260 * The new value for this property. 261 * @return This object. 262 */ 263 @FluentSetter 264 public Builder aside(String...value) { 265 aside = merge(aside, value); 266 return this; 267 } 268 269 /** 270 * Returns the list of aside section contents. 271 * 272 * <p> 273 * Gives access to the inner list if you need to make more than simple additions via {@link #aside(String...)}. 274 * 275 * @return The list of aside section contents. 276 * @see #aside(String...) 277 */ 278 public List<String> aside() { 279 if (aside == null) 280 aside = list(); 281 return aside; 282 } 283 284 /** 285 * Float aside section contents. 286 * 287 * <p> 288 * Allows you to position the aside contents of the page around the main contents. 289 * 290 * <p> 291 * By default, the aside section is floated to the right. 292 * 293 * <h5 class='section'>Example:</h5> 294 * <p class='bjava'> 295 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 296 * .<jsm>create</jsm>() 297 * .aside( 298 * <js>"<ul>"</js>, 299 * <js>" <li>Item 1"</js>, 300 * <js>" <li>Item 2"</js>, 301 * <js>" <li>Item 3"</js>, 302 * <js>"</ul>"</js> 303 * ) 304 * .asideFloat(<jsf>RIGHT</jsf>) 305 * .build(); 306 * </p> 307 * 308 * @param value 309 * The new value for this property. 310 * @return This object. 311 */ 312 @FluentSetter 313 public Builder asideFloat(AsideFloat value) { 314 asideFloat = value; 315 return this; 316 } 317 318 /** 319 * Footer section contents. 320 * 321 * <p> 322 * Allows you to specify the contents of the footer section on the HTML page. 323 * 324 * <p> 325 * By default, the footer section is empty. 326 * 327 * <h5 class='section'>Example:</h5> 328 * <p class='bjava'> 329 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 330 * .<jsm>create</jsm>() 331 * .footer( 332 * <js>"<b>This interface is great!</b>"</js> 333 * ) 334 * .build(); 335 * </p> 336 * 337 * @param value 338 * The new value for this property. 339 * @return This object. 340 */ 341 @FluentSetter 342 public Builder footer(String...value) { 343 footer = merge(footer, value); 344 return this; 345 } 346 347 /** 348 * Returns the list of footer section contents. 349 * 350 * <p> 351 * Gives access to the inner list if you need to make more than simple additions via {@link #footer(String...)}. 352 * 353 * @return The list of footer section contents. 354 * @see #footer(String...) 355 */ 356 public List<String> footer() { 357 if (footer == null) 358 footer = list(); 359 return footer; 360 } 361 362 /** 363 * Additional head section content. 364 * 365 * <p> 366 * Adds the specified HTML content to the head section of the page. 367 * 368 * <h5 class='section'>Example:</h5> 369 * <p class='bjava'> 370 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 371 * .<jsm>create</jsm>() 372 * .head( 373 * <js>"<link rel='icon' href='$U{servlet:/htdocs/mypageicon.ico}'>"</js> 374 * ) 375 * .build(); 376 * </p> 377 * 378 * @param value 379 * The new value for this property. 380 * @return This object. 381 */ 382 @FluentSetter 383 public Builder head(String...value) { 384 head = merge(head, value); 385 return this; 386 } 387 388 /** 389 * Returns the list of head section contents. 390 * 391 * <p> 392 * Gives access to the inner list if you need to make more than simple additions via {@link #head(String...)}. 393 * 394 * @return The list of head section contents. 395 * @see #head(String...) 396 */ 397 public List<String> head() { 398 if (head == null) 399 head = list(); 400 return head; 401 } 402 403 /** 404 * Header section contents. 405 * 406 * <p> 407 * Allows you to override the contents of the header section on the HTML page. 408 * The header section normally contains the title and description at the top of the page. 409 * 410 * <h5 class='section'>Example:</h5> 411 * <p class='bjava'> 412 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 413 * .<jsm>create</jsm>() 414 * .header( 415 * <js>"<h1>My own header</h1>"</js> 416 * ) 417 * .build() 418 * </p> 419 * 420 * @param value 421 * The new value for this property. 422 * @return This object. 423 */ 424 @FluentSetter 425 public Builder header(String...value) { 426 header = merge(header, value); 427 return this; 428 } 429 430 /** 431 * Returns the list of header section contents. 432 * 433 * <p> 434 * Gives access to the inner list if you need to make more than simple additions via {@link #header(String...)}. 435 * 436 * @return The list of header section contents. 437 * @see #header(String...) 438 */ 439 public List<String> header() { 440 if (header == null) 441 header = list(); 442 return header; 443 } 444 445 /** 446 * Nav section contents. 447 * 448 * <p> 449 * Allows you to override the contents of the nav section on the HTML page. 450 * The nav section normally contains the page links at the top of the page. 451 * 452 * <h5 class='section'>Example:</h5> 453 * <p class='bjava'> 454 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 455 * .<jsm>create</jsm>() 456 * .nav( 457 * <js>"<p class='special-navigation'>This is my special navigation content</p>"</js> 458 * ) 459 * .build() 460 * </p> 461 * 462 * <p> 463 * When this property is specified, the {@link Builder#navlinks(String...)} property is ignored. 464 * 465 * @param value 466 * The new value for this property. 467 * @return This object. 468 */ 469 @FluentSetter 470 public Builder nav(String...value) { 471 nav = merge(nav, value); 472 return this; 473 } 474 475 /** 476 * Returns the list of nav section contents. 477 * 478 * <p> 479 * Gives access to the inner list if you need to make more than simple additions via {@link #nav(String...)}. 480 * 481 * @return The list of nav section contents. 482 * @see #nav(String...) 483 */ 484 public List<String> nav() { 485 if (nav == null) 486 nav = list(); 487 return nav; 488 } 489 490 /** 491 * Page navigation links. 492 * 493 * <p> 494 * Adds a list of hyperlinks immediately under the title and description but above the content of the page. 495 * 496 * <p> 497 * This can be used to provide convenient hyperlinks when viewing the REST interface from a browser. 498 * 499 * <p> 500 * The value is an array of strings with two possible values: 501 * <ul> 502 * <li>A key-value pair representing a hyperlink label and href: 503 * <br><js>"google: http://google.com"</js> 504 * <li>Arbitrary HTML. 505 * </ul> 506 * 507 * <p> 508 * Relative URLs are considered relative to the servlet path. 509 * For example, if the servlet path is <js>"http://localhost/myContext/myServlet"</js>, and the 510 * URL is <js>"foo"</js>, the link becomes <js>"http://localhost/myContext/myServlet/foo"</js>. 511 * Absolute (<js>"/myOtherContext/foo"</js>) and fully-qualified (<js>"http://localhost2/foo"</js>) URLs 512 * can also be used in addition to various other protocols specified by {@link UriResolver} such as 513 * <js>"servlet:/..."</js>. 514 * 515 * <h5 class='section'>Example:</h5> 516 * <p class='bjava'> 517 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 518 * .<jsm>create</jsm>() 519 * .navlinks( 520 * <js>"api: servlet:/api"</js>, 521 * <js>"stats: servlet:/stats"</js>, 522 * <js>"doc: doc"</js> 523 * ) 524 * .build(); 525 * </p> 526 * 527 * @param value 528 * The new value for this property. 529 * @return This object. 530 */ 531 @FluentSetter 532 public Builder navlinks(String...value) { 533 navlinks = mergeNavLinks(navlinks, value); 534 return this; 535 } 536 537 /** 538 * Returns the list of navlinks section contents. 539 * 540 * <p> 541 * Gives access to the inner list if you need to make more than simple additions via {@link #navlinks(String...)}. 542 * 543 * @return The list of navlinks section contents. 544 * @see #navlinks(String...) 545 */ 546 public List<String> navlinks() { 547 if (navlinks == null) 548 navlinks = list(); 549 return navlinks; 550 } 551 552 /** 553 * No-results message. 554 * 555 * <p> 556 * Allows you to specify the string message used when trying to serialize an empty array or empty list. 557 * 558 * <h5 class='section'>Example:</h5> 559 * <p class='bjava'> 560 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 561 * .<jsm>create</jsm>() 562 * .noResultsMessage(<js>"<b>This interface is great!</b>"</js>) 563 * .build(); 564 * </p> 565 * 566 * <p> 567 * A value of <js>"NONE"</js> can be used to represent no value to differentiate it from an empty string. 568 * 569 * @param value 570 * The new value for this property. 571 * @return This object. 572 */ 573 @FluentSetter 574 public Builder noResultsMessage(String value) { 575 noResultsMessage = value; 576 return this; 577 } 578 579 /** 580 * Prevent word wrap on page. 581 * 582 * <p> 583 * Adds <js>"* {white-space:nowrap}"</js> to the CSS instructions on the page to prevent word wrapping. 584 * 585 * @return This object. 586 */ 587 @FluentSetter 588 public Builder nowrap() { 589 return nowrap(true); 590 } 591 592 /** 593 * Same as {@link #nowrap()} but allows you to explicitly specify the boolean value. 594 * 595 * @param value 596 * The new value for this property. 597 * @return This object. 598 * @see #nowrap() 599 */ 600 @FluentSetter 601 public Builder nowrap(boolean value) { 602 nowrap = value; 603 return this; 604 } 605 606 /** 607 * Resolve $ variables in serialized POJO. 608 * 609 * @return This object. 610 */ 611 @FluentSetter 612 public Builder resolveBodyVars() { 613 return resolveBodyVars(true); 614 } 615 616 /** 617 * Same as {@link #resolveBodyVars()} but allows you to explicitly specify the boolean value. 618 * 619 * @param value 620 * The new value for this property. 621 * @return This object. 622 * @see #nowrap() 623 */ 624 @FluentSetter 625 public Builder resolveBodyVars(boolean value) { 626 resolveBodyVars = value; 627 return this; 628 } 629 630 /** 631 * Adds the specified Javascript code to the HTML page. 632 * 633 * <p> 634 * A shortcut on <ja>@Rest</ja> is also provided for this setting: 635 * <p class='bjava'> 636 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 637 * .<jsm>create</jsm>() 638 * .script(<js>"alert('hello!');"</js>) 639 * .build(); 640 * </p> 641 * 642 * @param value 643 * The value to add to this property. 644 * @return This object. 645 */ 646 @FluentSetter 647 public Builder script(String...value) { 648 script = merge(script, value); 649 return this; 650 } 651 652 /** 653 * Returns the list of page script contents. 654 * 655 * <p> 656 * Gives access to the inner list if you need to make more than simple additions via {@link #script(String...)}. 657 * 658 * @return The list of page script contents. 659 * @see #script(String...) 660 */ 661 public List<String> script() { 662 if (script == null) 663 script = list(); 664 return script; 665 } 666 667 /** 668 * Adds the specified CSS instructions to the HTML page. 669 * 670 * <p class='bjava'> 671 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 672 * .<jsm>create</jsm>() 673 * .style( 674 * <js>"h3 { color: red; }"</js>, 675 * <js>"h5 { font-weight: bold; }"</js> 676 * ) 677 * .build(); 678 * </p> 679 * 680 * @param value 681 * The value to add to this property. 682 * @return This object. 683 */ 684 @FluentSetter 685 public Builder style(String...value) { 686 style = merge(style, value); 687 return this; 688 } 689 690 /** 691 * Returns the list of page style contents. 692 * 693 * <p> 694 * Gives access to the inner list if you need to make more than simple additions via {@link #style(String...)}. 695 * 696 * @return The list of page style contents. 697 * @see #style(String...) 698 */ 699 public List<String> style() { 700 if (style == null) 701 style = list(); 702 return style; 703 } 704 705 /** 706 * Adds to the list of stylesheet URLs. 707 * 708 * <p> 709 * Note that this stylesheet is controlled by the <code><ja>@Rest</ja>.stylesheet()</code> annotation. 710 * 711 * @param value 712 * The value to add to this property. 713 * @return This object. 714 */ 715 @FluentSetter 716 public Builder stylesheet(String...value) { 717 stylesheet = merge(stylesheet, value); 718 return this; 719 } 720 721 /** 722 * Returns the list of stylesheet URLs. 723 * 724 * <p> 725 * Gives access to the inner list if you need to make more than simple additions via {@link #stylesheet(String...)}. 726 * 727 * @return The list of stylesheet URLs. 728 * @see #stylesheet(String...) 729 */ 730 public List<String> stylesheet() { 731 if (stylesheet == null) 732 stylesheet = list(); 733 return stylesheet; 734 } 735 736 /** 737 * HTML document template. 738 * 739 * <p> 740 * Specifies the template to use for serializing the page. 741 * 742 * <p> 743 * By default, the {@link BasicHtmlDocTemplate} class is used to construct the contents of the HTML page, but 744 * can be overridden with your own custom implementation class. 745 * 746 * <h5 class='section'>Example:</h5> 747 * <p class='bjava'> 748 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 749 * .<jsm>create</jsm>() 750 * .template(MySpecialDocTemplate.<jk>class</jk>) 751 * .build(); 752 * </p> 753 * 754 * @param value 755 * The new value for this property. 756 * @return This object. 757 */ 758 @FluentSetter 759 public Builder template(Class<? extends HtmlDocTemplate> value) { 760 template = value; 761 return this; 762 } 763 764 /** 765 * HTML Widgets. 766 * 767 * <p> 768 * Defines widgets that can be used in conjunction with string variables of the form <js>"$W{name}"</js>to quickly 769 * generate arbitrary replacement text. 770 * 771 * Widgets resolve the following variables: 772 * <ul class='spaced-list'> 773 * <li><js>"$W{name}"</js> - Contents returned by {@link HtmlWidget#getHtml(VarResolverSession)}. 774 * <li><js>"$W{name.script}"</js> - Contents returned by {@link HtmlWidget#getScript(VarResolverSession)}. 775 * <br>The script contents are automatically inserted into the <xt><head/script></xt> section 776 * in the HTML page. 777 * <li><js>"$W{name.style}"</js> - Contents returned by {@link HtmlWidget#getStyle(VarResolverSession)}. 778 * <br>The styles contents are automatically inserted into the <xt><head/style></xt> section 779 * in the HTML page. 780 * </ul> 781 * 782 * <p> 783 * The following examples shows how to associate a widget with a REST method and then have it rendered in the links 784 * and aside section of the page: 785 * 786 * <p class='bjava'> 787 * WriterSerializer <jv>serializer</jv> = HtmlDocSerializer 788 * .<jsm>create</jsm>() 789 * .widgets( 790 * MyWidget.<jk>class</jk> 791 * ) 792 * .navlinks( 793 * <js>"$W{MyWidget}"</js> 794 * ) 795 * .aside( 796 * <js>"Check out this widget: $W{MyWidget}"</js> 797 * ) 798 * .build(); 799 * </p> 800 * 801 * <h5 class='section'>Notes:</h5><ul> 802 * <li class='note'> 803 * Widgets are inherited from super classes, but can be overridden by reusing the widget name. 804 * </ul> 805 * 806 * <h5 class='section'>See Also:</h5><ul> 807 * <li class='link'><a class="doclink" href="../../../../index.html#jrs.HtmlWidgets">Widgets</a> 808 * </ul> 809 * 810 * @param values The values to add to this setting. 811 * @return This object. 812 */ 813 @FluentSetter 814 @SuppressWarnings("unchecked") 815 public Builder widgets(Class<? extends HtmlWidget>...values) { 816 addAll(widgets(), values); 817 return this; 818 } 819 820 /** 821 * Returns the list of page widgets. 822 * 823 * <p> 824 * Gives access to the inner list if you need to make more than simple additions via {@link #widgets(Class...)}. 825 * 826 * @return The list of page widgets. 827 * @see #widgets(Class...) 828 */ 829 public List<Class<? extends HtmlWidget>> widgets() { 830 if (widgets == null) 831 widgets = list(); 832 return widgets; 833 } 834 835 // <FluentSetters> 836 837 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 838 public Builder annotations(Annotation...values) { 839 super.annotations(values); 840 return this; 841 } 842 843 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 844 public Builder apply(AnnotationWorkList work) { 845 super.apply(work); 846 return this; 847 } 848 849 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 850 public Builder applyAnnotations(java.lang.Class<?>...fromClasses) { 851 super.applyAnnotations(fromClasses); 852 return this; 853 } 854 855 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 856 public Builder applyAnnotations(Method...fromMethods) { 857 super.applyAnnotations(fromMethods); 858 return this; 859 } 860 861 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 862 public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) { 863 super.cache(value); 864 return this; 865 } 866 867 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 868 public Builder debug() { 869 super.debug(); 870 return this; 871 } 872 873 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 874 public Builder debug(boolean value) { 875 super.debug(value); 876 return this; 877 } 878 879 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 880 public Builder impl(Context value) { 881 super.impl(value); 882 return this; 883 } 884 885 @Override /* GENERATED - org.apache.juneau.Context.Builder */ 886 public Builder type(Class<? extends org.apache.juneau.Context> value) { 887 super.type(value); 888 return this; 889 } 890 891 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 892 public Builder beanClassVisibility(Visibility value) { 893 super.beanClassVisibility(value); 894 return this; 895 } 896 897 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 898 public Builder beanConstructorVisibility(Visibility value) { 899 super.beanConstructorVisibility(value); 900 return this; 901 } 902 903 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 904 public Builder beanContext(BeanContext value) { 905 super.beanContext(value); 906 return this; 907 } 908 909 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 910 public Builder beanContext(BeanContext.Builder value) { 911 super.beanContext(value); 912 return this; 913 } 914 915 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 916 public Builder beanDictionary(java.lang.Class<?>...values) { 917 super.beanDictionary(values); 918 return this; 919 } 920 921 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 922 public Builder beanFieldVisibility(Visibility value) { 923 super.beanFieldVisibility(value); 924 return this; 925 } 926 927 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 928 public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) { 929 super.beanInterceptor(on, value); 930 return this; 931 } 932 933 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 934 public Builder beanMapPutReturnsOldValue() { 935 super.beanMapPutReturnsOldValue(); 936 return this; 937 } 938 939 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 940 public Builder beanMethodVisibility(Visibility value) { 941 super.beanMethodVisibility(value); 942 return this; 943 } 944 945 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 946 public Builder beanProperties(Map<String,Object> values) { 947 super.beanProperties(values); 948 return this; 949 } 950 951 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 952 public Builder beanProperties(Class<?> beanClass, String properties) { 953 super.beanProperties(beanClass, properties); 954 return this; 955 } 956 957 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 958 public Builder beanProperties(String beanClassName, String properties) { 959 super.beanProperties(beanClassName, properties); 960 return this; 961 } 962 963 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 964 public Builder beanPropertiesExcludes(Map<String,Object> values) { 965 super.beanPropertiesExcludes(values); 966 return this; 967 } 968 969 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 970 public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) { 971 super.beanPropertiesExcludes(beanClass, properties); 972 return this; 973 } 974 975 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 976 public Builder beanPropertiesExcludes(String beanClassName, String properties) { 977 super.beanPropertiesExcludes(beanClassName, properties); 978 return this; 979 } 980 981 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 982 public Builder beanPropertiesReadOnly(Map<String,Object> values) { 983 super.beanPropertiesReadOnly(values); 984 return this; 985 } 986 987 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 988 public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) { 989 super.beanPropertiesReadOnly(beanClass, properties); 990 return this; 991 } 992 993 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 994 public Builder beanPropertiesReadOnly(String beanClassName, String properties) { 995 super.beanPropertiesReadOnly(beanClassName, properties); 996 return this; 997 } 998 999 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1000 public Builder beanPropertiesWriteOnly(Map<String,Object> values) { 1001 super.beanPropertiesWriteOnly(values); 1002 return this; 1003 } 1004 1005 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1006 public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) { 1007 super.beanPropertiesWriteOnly(beanClass, properties); 1008 return this; 1009 } 1010 1011 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1012 public Builder beanPropertiesWriteOnly(String beanClassName, String properties) { 1013 super.beanPropertiesWriteOnly(beanClassName, properties); 1014 return this; 1015 } 1016 1017 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1018 public Builder beansRequireDefaultConstructor() { 1019 super.beansRequireDefaultConstructor(); 1020 return this; 1021 } 1022 1023 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1024 public Builder beansRequireSerializable() { 1025 super.beansRequireSerializable(); 1026 return this; 1027 } 1028 1029 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1030 public Builder beansRequireSettersForGetters() { 1031 super.beansRequireSettersForGetters(); 1032 return this; 1033 } 1034 1035 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1036 public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) { 1037 super.dictionaryOn(on, values); 1038 return this; 1039 } 1040 1041 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1042 public Builder disableBeansRequireSomeProperties() { 1043 super.disableBeansRequireSomeProperties(); 1044 return this; 1045 } 1046 1047 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1048 public Builder disableIgnoreMissingSetters() { 1049 super.disableIgnoreMissingSetters(); 1050 return this; 1051 } 1052 1053 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1054 public Builder disableIgnoreTransientFields() { 1055 super.disableIgnoreTransientFields(); 1056 return this; 1057 } 1058 1059 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1060 public Builder disableIgnoreUnknownNullBeanProperties() { 1061 super.disableIgnoreUnknownNullBeanProperties(); 1062 return this; 1063 } 1064 1065 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1066 public Builder disableInterfaceProxies() { 1067 super.disableInterfaceProxies(); 1068 return this; 1069 } 1070 1071 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1072 public <T> Builder example(Class<T> pojoClass, T o) { 1073 super.example(pojoClass, o); 1074 return this; 1075 } 1076 1077 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1078 public <T> Builder example(Class<T> pojoClass, String json) { 1079 super.example(pojoClass, json); 1080 return this; 1081 } 1082 1083 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1084 public Builder findFluentSetters() { 1085 super.findFluentSetters(); 1086 return this; 1087 } 1088 1089 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1090 public Builder findFluentSetters(Class<?> on) { 1091 super.findFluentSetters(on); 1092 return this; 1093 } 1094 1095 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1096 public Builder ignoreInvocationExceptionsOnGetters() { 1097 super.ignoreInvocationExceptionsOnGetters(); 1098 return this; 1099 } 1100 1101 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1102 public Builder ignoreInvocationExceptionsOnSetters() { 1103 super.ignoreInvocationExceptionsOnSetters(); 1104 return this; 1105 } 1106 1107 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1108 public Builder ignoreUnknownBeanProperties() { 1109 super.ignoreUnknownBeanProperties(); 1110 return this; 1111 } 1112 1113 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1114 public Builder ignoreUnknownEnumValues() { 1115 super.ignoreUnknownEnumValues(); 1116 return this; 1117 } 1118 1119 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1120 public Builder implClass(Class<?> interfaceClass, Class<?> implClass) { 1121 super.implClass(interfaceClass, implClass); 1122 return this; 1123 } 1124 1125 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1126 public Builder implClasses(Map<Class<?>,Class<?>> values) { 1127 super.implClasses(values); 1128 return this; 1129 } 1130 1131 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1132 public Builder interfaceClass(Class<?> on, Class<?> value) { 1133 super.interfaceClass(on, value); 1134 return this; 1135 } 1136 1137 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1138 public Builder interfaces(java.lang.Class<?>...value) { 1139 super.interfaces(value); 1140 return this; 1141 } 1142 1143 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1144 public Builder locale(Locale value) { 1145 super.locale(value); 1146 return this; 1147 } 1148 1149 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1150 public Builder mediaType(MediaType value) { 1151 super.mediaType(value); 1152 return this; 1153 } 1154 1155 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1156 public Builder notBeanClasses(java.lang.Class<?>...values) { 1157 super.notBeanClasses(values); 1158 return this; 1159 } 1160 1161 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1162 public Builder notBeanPackages(String...values) { 1163 super.notBeanPackages(values); 1164 return this; 1165 } 1166 1167 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1168 public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) { 1169 super.propertyNamer(value); 1170 return this; 1171 } 1172 1173 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1174 public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) { 1175 super.propertyNamer(on, value); 1176 return this; 1177 } 1178 1179 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1180 public Builder sortProperties() { 1181 super.sortProperties(); 1182 return this; 1183 } 1184 1185 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1186 public Builder sortProperties(java.lang.Class<?>...on) { 1187 super.sortProperties(on); 1188 return this; 1189 } 1190 1191 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1192 public Builder stopClass(Class<?> on, Class<?> value) { 1193 super.stopClass(on, value); 1194 return this; 1195 } 1196 1197 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1198 public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) { 1199 super.swap(normalClass, swappedClass, swapFunction); 1200 return this; 1201 } 1202 1203 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1204 public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) { 1205 super.swap(normalClass, swappedClass, swapFunction, unswapFunction); 1206 return this; 1207 } 1208 1209 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1210 public Builder swaps(java.lang.Class<?>...values) { 1211 super.swaps(values); 1212 return this; 1213 } 1214 1215 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1216 public Builder timeZone(TimeZone value) { 1217 super.timeZone(value); 1218 return this; 1219 } 1220 1221 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1222 public Builder typeName(Class<?> on, String value) { 1223 super.typeName(on, value); 1224 return this; 1225 } 1226 1227 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1228 public Builder typePropertyName(String value) { 1229 super.typePropertyName(value); 1230 return this; 1231 } 1232 1233 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1234 public Builder typePropertyName(Class<?> on, String value) { 1235 super.typePropertyName(on, value); 1236 return this; 1237 } 1238 1239 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1240 public Builder useEnumNames() { 1241 super.useEnumNames(); 1242 return this; 1243 } 1244 1245 @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */ 1246 public Builder useJavaBeanIntrospector() { 1247 super.useJavaBeanIntrospector(); 1248 return this; 1249 } 1250 1251 @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */ 1252 public Builder detectRecursions() { 1253 super.detectRecursions(); 1254 return this; 1255 } 1256 1257 @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */ 1258 public Builder detectRecursions(boolean value) { 1259 super.detectRecursions(value); 1260 return this; 1261 } 1262 1263 @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */ 1264 public Builder ignoreRecursions() { 1265 super.ignoreRecursions(); 1266 return this; 1267 } 1268 1269 @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */ 1270 public Builder ignoreRecursions(boolean value) { 1271 super.ignoreRecursions(value); 1272 return this; 1273 } 1274 1275 @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */ 1276 public Builder initialDepth(int value) { 1277 super.initialDepth(value); 1278 return this; 1279 } 1280 1281 @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */ 1282 public Builder maxDepth(int value) { 1283 super.maxDepth(value); 1284 return this; 1285 } 1286 1287 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1288 public Builder accept(String value) { 1289 super.accept(value); 1290 return this; 1291 } 1292 1293 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1294 public Builder addBeanTypes() { 1295 super.addBeanTypes(); 1296 return this; 1297 } 1298 1299 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1300 public Builder addBeanTypes(boolean value) { 1301 super.addBeanTypes(value); 1302 return this; 1303 } 1304 1305 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1306 public Builder addRootType() { 1307 super.addRootType(); 1308 return this; 1309 } 1310 1311 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1312 public Builder addRootType(boolean value) { 1313 super.addRootType(value); 1314 return this; 1315 } 1316 1317 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1318 public Builder keepNullProperties() { 1319 super.keepNullProperties(); 1320 return this; 1321 } 1322 1323 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1324 public Builder keepNullProperties(boolean value) { 1325 super.keepNullProperties(value); 1326 return this; 1327 } 1328 1329 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1330 public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) { 1331 super.listener(value); 1332 return this; 1333 } 1334 1335 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1336 public Builder produces(String value) { 1337 super.produces(value); 1338 return this; 1339 } 1340 1341 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1342 public Builder sortCollections() { 1343 super.sortCollections(); 1344 return this; 1345 } 1346 1347 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1348 public Builder sortCollections(boolean value) { 1349 super.sortCollections(value); 1350 return this; 1351 } 1352 1353 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1354 public Builder sortMaps() { 1355 super.sortMaps(); 1356 return this; 1357 } 1358 1359 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1360 public Builder sortMaps(boolean value) { 1361 super.sortMaps(value); 1362 return this; 1363 } 1364 1365 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1366 public Builder trimEmptyCollections() { 1367 super.trimEmptyCollections(); 1368 return this; 1369 } 1370 1371 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1372 public Builder trimEmptyCollections(boolean value) { 1373 super.trimEmptyCollections(value); 1374 return this; 1375 } 1376 1377 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1378 public Builder trimEmptyMaps() { 1379 super.trimEmptyMaps(); 1380 return this; 1381 } 1382 1383 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1384 public Builder trimEmptyMaps(boolean value) { 1385 super.trimEmptyMaps(value); 1386 return this; 1387 } 1388 1389 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1390 public Builder trimStrings() { 1391 super.trimStrings(); 1392 return this; 1393 } 1394 1395 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1396 public Builder trimStrings(boolean value) { 1397 super.trimStrings(value); 1398 return this; 1399 } 1400 1401 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1402 public Builder uriContext(UriContext value) { 1403 super.uriContext(value); 1404 return this; 1405 } 1406 1407 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1408 public Builder uriRelativity(UriRelativity value) { 1409 super.uriRelativity(value); 1410 return this; 1411 } 1412 1413 @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */ 1414 public Builder uriResolution(UriResolution value) { 1415 super.uriResolution(value); 1416 return this; 1417 } 1418 1419 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1420 public Builder fileCharset(Charset value) { 1421 super.fileCharset(value); 1422 return this; 1423 } 1424 1425 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1426 public Builder maxIndent(int value) { 1427 super.maxIndent(value); 1428 return this; 1429 } 1430 1431 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1432 public Builder quoteChar(char value) { 1433 super.quoteChar(value); 1434 return this; 1435 } 1436 1437 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1438 public Builder quoteCharOverride(char value) { 1439 super.quoteCharOverride(value); 1440 return this; 1441 } 1442 1443 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1444 public Builder sq() { 1445 super.sq(); 1446 return this; 1447 } 1448 1449 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1450 public Builder streamCharset(Charset value) { 1451 super.streamCharset(value); 1452 return this; 1453 } 1454 1455 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1456 public Builder useWhitespace() { 1457 super.useWhitespace(); 1458 return this; 1459 } 1460 1461 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1462 public Builder useWhitespace(boolean value) { 1463 super.useWhitespace(value); 1464 return this; 1465 } 1466 1467 @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */ 1468 public Builder ws() { 1469 super.ws(); 1470 return this; 1471 } 1472 1473 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1474 public Builder addBeanTypesXml() { 1475 super.addBeanTypesXml(); 1476 return this; 1477 } 1478 1479 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1480 public Builder addBeanTypesXml(boolean value) { 1481 super.addBeanTypesXml(value); 1482 return this; 1483 } 1484 1485 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1486 public Builder addNamespaceUrisToRoot() { 1487 super.addNamespaceUrisToRoot(); 1488 return this; 1489 } 1490 1491 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1492 public Builder addNamespaceUrisToRoot(boolean value) { 1493 super.addNamespaceUrisToRoot(value); 1494 return this; 1495 } 1496 1497 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1498 public Builder defaultNamespace(Namespace value) { 1499 super.defaultNamespace(value); 1500 return this; 1501 } 1502 1503 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1504 public Builder disableAutoDetectNamespaces() { 1505 super.disableAutoDetectNamespaces(); 1506 return this; 1507 } 1508 1509 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1510 public Builder disableAutoDetectNamespaces(boolean value) { 1511 super.disableAutoDetectNamespaces(value); 1512 return this; 1513 } 1514 1515 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1516 public Builder enableNamespaces() { 1517 super.enableNamespaces(); 1518 return this; 1519 } 1520 1521 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1522 public Builder enableNamespaces(boolean value) { 1523 super.enableNamespaces(value); 1524 return this; 1525 } 1526 1527 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1528 public Builder namespaces(Namespace...values) { 1529 super.namespaces(values); 1530 return this; 1531 } 1532 1533 @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */ 1534 public Builder ns() { 1535 super.ns(); 1536 return this; 1537 } 1538 1539 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1540 public Builder addBeanTypesHtml() { 1541 super.addBeanTypesHtml(); 1542 return this; 1543 } 1544 1545 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1546 public Builder addBeanTypesHtml(boolean value) { 1547 super.addBeanTypesHtml(value); 1548 return this; 1549 } 1550 1551 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1552 public Builder addKeyValueTableHeaders() { 1553 super.addKeyValueTableHeaders(); 1554 return this; 1555 } 1556 1557 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1558 public Builder addKeyValueTableHeaders(boolean value) { 1559 super.addKeyValueTableHeaders(value); 1560 return this; 1561 } 1562 1563 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1564 public Builder disableDetectLabelParameters() { 1565 super.disableDetectLabelParameters(); 1566 return this; 1567 } 1568 1569 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1570 public Builder disableDetectLabelParameters(boolean value) { 1571 super.disableDetectLabelParameters(value); 1572 return this; 1573 } 1574 1575 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1576 public Builder disableDetectLinksInStrings() { 1577 super.disableDetectLinksInStrings(); 1578 return this; 1579 } 1580 1581 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1582 public Builder disableDetectLinksInStrings(boolean value) { 1583 super.disableDetectLinksInStrings(value); 1584 return this; 1585 } 1586 1587 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1588 public Builder labelParameter(String value) { 1589 super.labelParameter(value); 1590 return this; 1591 } 1592 1593 @Override /* GENERATED - org.apache.juneau.html.HtmlSerializer.Builder */ 1594 public Builder uriAnchorText(AnchorText value) { 1595 super.uriAnchorText(value); 1596 return this; 1597 } 1598 1599 // </FluentSetters> 1600 1601 //----------------------------------------------------------------------------------------------------------------- 1602 // Helpers 1603 //----------------------------------------------------------------------------------------------------------------- 1604 1605 private static <T> List<T> copy(List<T> s) { 1606 return s == null || s.isEmpty() ? null : copyOf(s); 1607 } 1608 1609 private static <T> List<T> copy(T[] s) { 1610 return s.length == 0 ? null : list(s); 1611 } 1612 1613 private List<String> merge(List<String> old, String[] newValues) { 1614 List<String> x = list(newValues.length); 1615 for (String s : newValues) { 1616 if ("NONE".equals(s)) { 1617 if (old != null) 1618 old.clear(); 1619 } else if ("INHERIT".equals(s)) { 1620 if (old != null) 1621 x.addAll(old); 1622 } else { 1623 x.add(s); 1624 } 1625 } 1626 return x; 1627 } 1628 1629 private List<String> mergeNavLinks(List<String> old, String[] newValues) { 1630 List<String> x = list(newValues.length); 1631 for (String s : newValues) { 1632 if ("NONE".equals(s)) { 1633 if (old != null) 1634 old.clear(); 1635 } else if ("INHERIT".equals(s)) { 1636 if (old != null) 1637 x.addAll(old); 1638 } else if (s.indexOf('[') != -1 && INDEXED_LINK_PATTERN.matcher(s).matches()) { 1639 Matcher lm = INDEXED_LINK_PATTERN.matcher(s); 1640 lm.matches(); 1641 String key = lm.group(1); 1642 int index = Math.min(x.size(), Integer.parseInt(lm.group(2))); 1643 String remainder = lm.group(3); 1644 x.add(index, key.isEmpty() ? remainder : key + ":" + remainder); 1645 } else { 1646 x.add(s); 1647 } 1648 } 1649 return x; 1650 } 1651 1652 private static final Pattern INDEXED_LINK_PATTERN = Pattern.compile("(?s)(\\S*)\\[(\\d+)\\]\\:(.*)"); 1653 } 1654 1655 //------------------------------------------------------------------------------------------------------------------- 1656 // Instance 1657 //------------------------------------------------------------------------------------------------------------------- 1658 1659 final String[] style, stylesheet, script, navlinks, head, header, nav, aside, footer; 1660 final AsideFloat asideFloat; 1661 final String noResultsMessage; 1662 final boolean nowrap, resolveBodyVars; 1663 final Class<? extends HtmlDocTemplate> template; 1664 final List<Class<? extends HtmlWidget>> widgets; 1665 1666 private final HtmlWidgetMap widgetMap; 1667 private final HtmlWidget[] widgetArray; 1668 private final HtmlDocTemplate templateBean; 1669 1670 private volatile HtmlSchemaDocSerializer schemaSerializer; 1671 1672 /** 1673 * Constructor. 1674 * 1675 * @param builder The builder for this object. 1676 */ 1677 public HtmlDocSerializer(Builder builder) { 1678 super(builder); 1679 style = builder.style != null ? toArray(builder.style) : EMPTY_ARRAY; 1680 stylesheet = builder.stylesheet != null ? toArray(builder.stylesheet) : EMPTY_ARRAY; 1681 script = builder.script != null ? toArray(builder.script) : EMPTY_ARRAY; 1682 head = builder.head != null ? toArray(builder.head) : EMPTY_ARRAY; 1683 header = builder.header != null ? toArray(builder.header) : EMPTY_ARRAY; 1684 nav = builder.nav != null ? toArray(builder.nav) : EMPTY_ARRAY; 1685 aside = builder.aside != null ? toArray(builder.aside) : EMPTY_ARRAY; 1686 footer = builder.footer != null ? toArray(builder.footer) : EMPTY_ARRAY; 1687 navlinks = builder.navlinks != null ? toArray(builder.navlinks) : EMPTY_ARRAY; 1688 asideFloat = builder.asideFloat; 1689 noResultsMessage = builder.noResultsMessage; 1690 nowrap = builder.nowrap; 1691 resolveBodyVars = builder.resolveBodyVars; 1692 template = builder.template; 1693 widgets = builder.widgets == null ? emptyList() : copyOf(builder.widgets); 1694 1695 templateBean = newInstance(template); 1696 widgetMap = new HtmlWidgetMap(); 1697 widgets.stream().map(this::newInstance).forEach(x -> widgetMap.append(x)); 1698 widgetArray = array(widgetMap.values(), HtmlWidget.class); 1699 } 1700 1701 @Override /* Context */ 1702 public Builder copy() { 1703 return new Builder(this); 1704 } 1705 1706 @Override /* Context */ 1707 public HtmlDocSerializerSession.Builder createSession() { 1708 return HtmlDocSerializerSession.create(this); 1709 } 1710 1711 @Override /* Context */ 1712 public HtmlDocSerializerSession getSession() { 1713 return createSession().build(); 1714 } 1715 1716 @Override /* XmlSerializer */ 1717 public HtmlSerializer getSchemaSerializer() { 1718 if (schemaSerializer == null) 1719 schemaSerializer = HtmlSchemaDocSerializer.create().beanContext(getBeanContext()).build(); 1720 return schemaSerializer; 1721 } 1722 1723 //----------------------------------------------------------------------------------------------------------------- 1724 // Properties 1725 //----------------------------------------------------------------------------------------------------------------- 1726 1727 /** 1728 * Aside section contents. 1729 * 1730 * @see Builder#aside(String...) 1731 * @return 1732 * The overridden contents of the aside section on the HTML page. 1733 */ 1734 protected final String[] getAside() { 1735 return aside; 1736 } 1737 1738 /** 1739 * Float side section contents. 1740 * 1741 * @see Builder#asideFloat(AsideFloat) 1742 * @return 1743 * How to float the aside contents on the page. 1744 */ 1745 protected final AsideFloat getAsideFloat() { 1746 return asideFloat; 1747 } 1748 1749 /** 1750 * Footer section contents. 1751 * 1752 * @see Builder#footer(String...) 1753 * @return 1754 * The overridden contents of the footer section on the HTML page. 1755 */ 1756 protected final String[] getFooter() { 1757 return footer; 1758 } 1759 1760 /** 1761 * Additional head section content. 1762 * 1763 * @see Builder#head(String...) 1764 * @return 1765 * HTML content to add to the head section of the HTML page. 1766 */ 1767 protected final String[] getHead() { 1768 return head; 1769 } 1770 1771 /** 1772 * Header section contents. 1773 * 1774 * @see Builder#header(String...) 1775 * @return 1776 * The overridden contents of the header section on the HTML page. 1777 */ 1778 protected final String[] getHeader() { 1779 return header; 1780 } 1781 1782 /** 1783 * Nav section contents. 1784 * 1785 * @see Builder#nav(String...) 1786 * @return 1787 * The overridden contents of the nav section on the HTML page. 1788 */ 1789 protected final String[] getNav() { 1790 return nav; 1791 } 1792 1793 /** 1794 * Page navigation links. 1795 * 1796 * @see Builder#navlinks(String...) 1797 * @return 1798 * Navigation links to add to the HTML page. 1799 */ 1800 protected final String[] getNavlinks() { 1801 return navlinks; 1802 } 1803 1804 /** 1805 * No-results message. 1806 * 1807 * @see Builder#noResultsMessage(String) 1808 * @return 1809 * The message used when serializing an empty array or empty list. 1810 */ 1811 protected final String getNoResultsMessage() { 1812 return noResultsMessage; 1813 } 1814 1815 /** 1816 * Prevent word wrap on page. 1817 * 1818 * @see Builder#nowrap() 1819 * @return 1820 * <jk>true</jk> if <js>"* {white-space:nowrap}"</js> shoudl be added to the CSS instructions on the page to prevent word wrapping. 1821 */ 1822 protected final boolean isNowrap() { 1823 return nowrap; 1824 } 1825 1826 /** 1827 * Javascript code. 1828 * 1829 * @see Builder#script(String...) 1830 * @return 1831 * Arbitrary Javascript to add to the HTML page. 1832 */ 1833 protected final String[] getScript() { 1834 return script; 1835 } 1836 1837 /** 1838 * CSS style code. 1839 * 1840 * @see Builder#style(String...) 1841 * @return 1842 * The CSS instructions to add to the HTML page. 1843 */ 1844 protected final String[] getStyle() { 1845 return style; 1846 } 1847 1848 /** 1849 * Stylesheet import URLs. 1850 * 1851 * @see Builder#stylesheet(String...) 1852 * @return 1853 * The link to the stylesheet of the HTML page. 1854 */ 1855 protected final String[] getStylesheet() { 1856 return stylesheet; 1857 } 1858 1859 /** 1860 * HTML document template. 1861 * 1862 * @see Builder#template(Class) 1863 * @return 1864 * The template to use for serializing the page. 1865 */ 1866 protected final HtmlDocTemplate getTemplate() { 1867 return templateBean; 1868 } 1869 1870 /** 1871 * HTML widgets. 1872 * 1873 * @see Builder#widgets(Class...) 1874 * @return 1875 * Widgets defined on this serializers. 1876 */ 1877 protected final HtmlWidgetMap getWidgets() { 1878 return widgetMap; 1879 } 1880 1881 /** 1882 * Performs an action on all widgets defined on this serializer. 1883 * 1884 * @param action The action to perform. 1885 * @return This object. 1886 */ 1887 protected final HtmlDocSerializer forEachWidget(Consumer<HtmlWidget> action) { 1888 for (HtmlWidget w : widgetArray) 1889 action.accept(w); 1890 return this; 1891 } 1892 1893 //----------------------------------------------------------------------------------------------------------------- 1894 // Other methods 1895 //----------------------------------------------------------------------------------------------------------------- 1896 1897 private String[] toArray(List<String> x) { 1898 return x.toArray(new String[x.size()]); 1899 } 1900 1901 private <T> T newInstance(Class<T> c) { 1902 try { 1903 return c.getDeclaredConstructor().newInstance(); 1904 } catch (Exception e) { 1905 throw asRuntimeException(e); 1906 } 1907 } 1908 1909 @Override /* Context */ 1910 protected JsonMap properties() { 1911 return filteredMap() 1912 .append("header", header) 1913 .append("nav", nav) 1914 .append("navlinks", navlinks) 1915 .append("aside", aside) 1916 .append("asideFloat", asideFloat) 1917 .append("footer", footer) 1918 .append("style", style) 1919 .append("head", head) 1920 .append("stylesheet", stylesheet) 1921 .append("nowrap", nowrap) 1922 .append("template", template) 1923 .append("noResultsMessage", noResultsMessage) 1924 .append("widgets", widgets); 1925 } 1926}