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 java.lang.annotation.*;
017import java.lang.reflect.*;
018import java.nio.charset.*;
019import java.util.*;
020import java.util.concurrent.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.collections.*;
024import org.apache.juneau.html.annotation.*;
025import org.apache.juneau.internal.*;
026import org.apache.juneau.serializer.*;
027import org.apache.juneau.utils.*;
028import org.apache.juneau.xml.*;
029
030/**
031 * Serializes POJO models to HTML.
032 *
033 * <h5 class='topic'>Media types</h5>
034 * <p>
035 * Handles <c>Accept</c> types:  <bc>text/html</bc>
036 * <p>
037 * Produces <c>Content-Type</c> types:  <bc>text/html</bc>
038 *
039 * <h5 class='topic'>Description</h5>
040 * <p>
041 * The conversion is as follows...
042 * <ul class='spaced-list'>
043 *    <li>
044 *       {@link Map Maps} (e.g. {@link HashMap}, {@link TreeMap}) and beans are converted to HTML tables with
045 *       'key' and 'value' columns.
046 *    <li>
047 *       {@link Collection Collections} (e.g. {@link HashSet}, {@link LinkedList}) and Java arrays are converted
048 *       to HTML ordered lists.
049 *    <li>
050 *       {@code Collections} of {@code Maps} and beans are converted to HTML tables with keys as headers.
051 *    <li>
052 *       Everything else is converted to text.
053 * </ul>
054 *
055 * <p>
056 * This serializer provides several serialization options.  Typically, one of the predefined <jsf>DEFAULT</jsf>
057 * serializers will be sufficient.
058 * However, custom serializers can be constructed to fine-tune behavior.
059 *
060 * <p>
061 * The {@link HtmlLink} annotation can be used on beans to add hyperlinks to the output.
062 *
063 * <h5 class='topic'>Behavior-specific subclasses</h5>
064 * <p>
065 * The following direct subclasses are provided for convenience:
066 * <ul class='spaced-list'>
067 *    <li>
068 *       {@link Sq} - Default serializer, single quotes.
069 *    <li>
070 *       {@link SqReadable} - Default serializer, single quotes, whitespace added.
071 * </ul>
072 *
073 * <h5 class='section'>Example:</h5>
074 * <p class='bjava'>
075 *    <jc>// Use one of the default serializers to serialize a POJO</jc>
076 *    String <jv>html</jv> = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>someObject</jv>);
077 *
078 *    <jc>// Create a custom serializer that doesn't use whitespace and newlines</jc>
079 *    HtmlSerializer <jv>serializer</jv> = HtmlSerializer.<jsm>create</jsm>().ws().build();
080 *
081 *    <jc>// Same as above, except uses cloning</jc>
082 *    HtmlSerializer <jv>serializer</jv> = HtmlSerializer.<jsf>DEFAULT</jsf>.copy().ws().build();
083 *
084 *    <jc>// Serialize POJOs to HTML</jc>
085 *
086 *    <jc>// Produces: </jc>
087 *    <jc>// &lt;ul&gt;&lt;li&gt;1&lt;li&gt;2&lt;li&gt;3&lt;/ul&gt;</jc>
088 *    List <jv>list</jv> = JsonList.<jsm>of</jsm>(1, 2, 3);
089 *    String <jv>html</jv> = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>list</jv>);
090 *
091 *    <jc>// Produces: </jc>
092 *    <jc>//    &lt;table&gt; </jc>
093 *    <jc>//       &lt;tr&gt;&lt;th&gt;firstName&lt;/th&gt;&lt;th&gt;lastName&lt;/th&gt;&lt;/tr&gt; </jc>
094 *    <jc>//       &lt;tr&gt;&lt;td&gt;Bob&lt;/td&gt;&lt;td&gt;Costas&lt;/td&gt;&lt;/tr&gt; </jc>
095 *    <jc>//       &lt;tr&gt;&lt;td&gt;Billy&lt;/td&gt;&lt;td&gt;TheKid&lt;/td&gt;&lt;/tr&gt; </jc>
096 *    <jc>//       &lt;tr&gt;&lt;td&gt;Barney&lt;/td&gt;&lt;td&gt;Miller&lt;/td&gt;&lt;/tr&gt; </jc>
097 *    <jc>//    &lt;/table&gt; </jc>
098 *    <jv>html</jv> = JsonList.<jsm>of</jsm>(
099 *       JsonMap.<jsm>ofJson</jsm>(<js>"{firstName:'Bob',lastName:'Costas'}"</js>),
100 *       JsonMap.<jsm>ofJson</jsm>(<js>"{firstName:'Billy',lastName:'TheKid'}"</js>),
101 *       JsonMap.<jsm>ofJson</jsm>(<js>"{firstName:'Barney',lastName:'Miller'}"</js>)
102 *    );
103 *    String <jv>html</jv> = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>list</jv>);
104 *
105 *    <jc>// Produces: </jc>
106 *    <jc>//    &lt;table&gt; </jc>
107 *    <jc>//       &lt;tr&gt;&lt;th&gt;key&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;/tr&gt; </jc>
108 *    <jc>//       &lt;tr&gt;&lt;td&gt;foo&lt;/td&gt;&lt;td&gt;bar&lt;/td&gt;&lt;/tr&gt; </jc>
109 *    <jc>//       &lt;tr&gt;&lt;td&gt;baz&lt;/td&gt;&lt;td&gt;123&lt;/td&gt;&lt;/tr&gt; </jc>
110 *    <jc>//    &lt;/table&gt; </jc>
111 *    Map <jv>map</jv> = JsonMap.<jsm>ofJson</jsm>(<js>"{foo:'bar',baz:123}"</js>);
112 *    String <jv>html</jv> = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>map</jv>);
113 *
114 *    <jc>// HTML elements can be nested arbitrarily deep</jc>
115 *    <jc>// Produces: </jc>
116 *    <jc>//   &lt;table&gt; </jc>
117 *    <jc>//      &lt;tr&gt;&lt;th&gt;key&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;/tr&gt; </jc>
118 *    <jc>//      &lt;tr&gt;&lt;td&gt;foo&lt;/td&gt;&lt;td&gt;bar&lt;/td&gt;&lt;/tr&gt; </jc>
119 *    <jc>//      &lt;tr&gt;&lt;td&gt;baz&lt;/td&gt;&lt;td&gt;123&lt;/td&gt;&lt;/tr&gt; </jc>
120 *    <jc>//      &lt;tr&gt;&lt;td&gt;someNumbers&lt;/td&gt;&lt;td&gt;&lt;ul&gt;&lt;li&gt;1&lt;li&gt;2&lt;li&gt;3&lt;/ul&gt;&lt;/td&gt;&lt;/tr&gt; </jc>
121 *    <jc>//      &lt;tr&gt;&lt;td&gt;someSubMap&lt;/td&gt;&lt;td&gt; </jc>
122 *    <jc>//         &lt;table&gt; </jc>
123 *    <jc>//            &lt;tr&gt;&lt;th&gt;key&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;/tr&gt; </jc>
124 *    <jc>//            &lt;tr&gt;&lt;td&gt;a&lt;/td&gt;&lt;td&gt;b&lt;/td&gt;&lt;/tr&gt; </jc>
125 *    <jc>//         &lt;/table&gt; </jc>
126 *    <jc>//      &lt;/td&gt;&lt;/tr&gt; </jc>
127 *    <jc>//   &lt;/table&gt; </jc>
128 *    Map <jv>map</jv> = JsonMap.<jsm>ofJson</jsm>(<js>"{foo:'bar',baz:123}"</js>);
129 *    <jv>map</jv>.put(<js>"someNumbers"</js>, JsonList.<jsm>of</jsm>(1, 2, 3));
130 *    <jv>map</jv>.put(<js>"someSubMap"</js>, JsonMap.<jsm>ofJson</jsm>(<js>"{a:'b'}"</js>));
131 *    String <jv>html</jv> = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>map</jv>);
132 * </p>
133 *
134 * <h5 class='section'>Notes:</h5><ul>
135 *    <li class='note'>This class is thread safe and reusable.
136 * </ul>
137 *
138 * <h5 class='section'>See Also:</h5><ul>
139 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.HtmlDetails">HTML Details</a>
140
141 * </ul>
142 */
143public class HtmlSerializer extends XmlSerializer implements HtmlMetaProvider {
144
145   //-------------------------------------------------------------------------------------------------------------------
146   // Static
147   //-------------------------------------------------------------------------------------------------------------------
148
149   /** Default serializer, all default settings. */
150   public static final HtmlSerializer DEFAULT = new HtmlSerializer(create());
151
152   /** Default serializer, single quotes. */
153   public static final HtmlSerializer DEFAULT_SQ = new HtmlSerializer.Sq(create());
154
155   /** Default serializer, single quotes, whitespace added. */
156   public static final HtmlSerializer DEFAULT_SQ_READABLE = new HtmlSerializer.SqReadable(create());
157
158   /**
159    * Creates a new builder for this object.
160    *
161    * @return A new builder.
162    */
163   public static Builder create() {
164      return new Builder();
165   }
166
167   //-------------------------------------------------------------------------------------------------------------------
168   // Static subclasses
169   //-------------------------------------------------------------------------------------------------------------------
170
171   /** Default serializer, single quotes. */
172   public static class Sq extends HtmlSerializer {
173
174      /**
175       * Constructor.
176       *
177       * @param builder The builder for this object.
178       */
179      public Sq(Builder builder) {
180         super(builder.quoteChar('\''));
181      }
182   }
183
184   /** Default serializer, single quotes, whitespace added. */
185   public static class SqReadable extends HtmlSerializer {
186
187      /**
188       * Constructor.
189       *
190       * @param builder The builder for this object.
191       */
192      public SqReadable(Builder builder) {
193         super(builder.quoteChar('\'').useWhitespace());
194      }
195   }
196
197   //-------------------------------------------------------------------------------------------------------------------
198   // Instance
199   //-------------------------------------------------------------------------------------------------------------------
200
201   /**
202    * Builder class.
203    */
204   @FluentSetters
205   public static class Builder extends XmlSerializer.Builder {
206
207      private static final Cache<HashKey,HtmlSerializer> CACHE = Cache.of(HashKey.class, HtmlSerializer.class).build();
208
209      boolean addBeanTypesHtml, addKeyValueTableHeaders, disableDetectLabelParameters, disableDetectLinksInStrings;
210      String labelParameter;
211      AnchorText uriAnchorText;
212
213      /**
214       * Constructor, default settings.
215       */
216      protected Builder() {
217         produces("text/html");
218         addBeanTypesHtml = env("HtmlSerializer.addBeanTypesHtml", false);
219         addKeyValueTableHeaders = env("HtmlSerializer.addKeyValueTableHeaders", false);
220         disableDetectLabelParameters = env("HtmlSerializer.disableDetectLabelParameters", false);
221         disableDetectLinksInStrings = env("HtmlSerializer.disableDetectLinksInStrings", false);
222         uriAnchorText = env("HtmlSerializer.uriAnchorText", AnchorText.TO_STRING);
223         labelParameter =  env("HtmlSerializer.labelParameter", "label");
224      }
225
226      /**
227       * Copy constructor.
228       *
229       * @param copyFrom The bean to copy from.
230       */
231      protected Builder(HtmlSerializer copyFrom) {
232         super(copyFrom);
233         addBeanTypesHtml = copyFrom.addBeanTypesHtml;
234         addKeyValueTableHeaders = copyFrom.addKeyValueTableHeaders;
235         disableDetectLabelParameters = ! copyFrom.detectLabelParameters;
236         disableDetectLinksInStrings = ! copyFrom.detectLinksInStrings;
237         labelParameter = copyFrom.labelParameter;
238         uriAnchorText = copyFrom.uriAnchorText;
239      }
240
241      /**
242       * Copy constructor.
243       *
244       * @param copyFrom The builder to copy from.
245       */
246      protected Builder(Builder copyFrom) {
247         super(copyFrom);
248         addBeanTypesHtml = copyFrom.addBeanTypesHtml;
249         addKeyValueTableHeaders = copyFrom.addKeyValueTableHeaders;
250         disableDetectLabelParameters = copyFrom.disableDetectLabelParameters;
251         disableDetectLinksInStrings = copyFrom.disableDetectLinksInStrings;
252         labelParameter = copyFrom.labelParameter;
253         uriAnchorText = copyFrom.uriAnchorText;
254      }
255
256      @Override /* Context.Builder */
257      public Builder copy() {
258         return new Builder(this);
259      }
260
261      @Override /* Context.Builder */
262      public HtmlSerializer build() {
263         return cache(CACHE).build(HtmlSerializer.class);
264      }
265
266      @Override /* Context.Builder */
267      public HashKey hashKey() {
268         return HashKey.of(
269            super.hashKey(),
270            addBeanTypesHtml,
271            addKeyValueTableHeaders,
272            disableDetectLabelParameters,
273            disableDetectLinksInStrings,
274            labelParameter,
275            uriAnchorText
276         );
277      }
278
279      //-----------------------------------------------------------------------------------------------------------------
280      // Properties
281      //-----------------------------------------------------------------------------------------------------------------
282
283      /**
284       * Add <js>"_type"</js> properties when needed.
285       *
286       * <p>
287       * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
288       * through reflection.
289       *
290       * <p>
291       * When present, this value overrides the {@link org.apache.juneau.serializer.Serializer.Builder#addBeanTypes()} setting and is
292       * provided to customize the behavior of specific serializers in a {@link SerializerSet}.
293       *
294       * @return This object.
295       */
296      @FluentSetter
297      public Builder addBeanTypesHtml() {
298         return addBeanTypesHtml(true);
299      }
300
301      /**
302       * Same as {@link #addBeanTypesHtml()} but allows you to explicitly specify the value.
303       *
304       * @param value The value for this setting.
305       * @return This object.
306       */
307      @FluentSetter
308      public Builder addBeanTypesHtml(boolean value) {
309         addBeanTypesHtml = value;
310         return this;
311      }
312
313      /**
314       * <i><l>HtmlSerializer</l> configuration property:&emsp;</i>  Add key/value headers on bean/map tables.
315       *
316       * <p>
317       * When enabled, <bc>key</bc> and <bc>value</bc> column headers are added to tables.
318       *
319       * <h5 class='section'>Example:</h5>
320       * <p class='bjson'>
321       *    <jc>// Our bean class.</jc>
322       *    <jk>public class</jk> MyBean {
323       *       <jk>public</jk> String <jf>f1</jf> = <js>"foo"</js>;
324       *       <jk>public</jk> String <jf>f2</jf> = <js>"bar"</js>;
325       *    }
326       *
327       *  <jc>// Serializer without headers.</jc>
328       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer.<jsf>DEFAULT</jsf>;
329       *
330       *  <jc>// Serializer with headers.</jc>
331       *    WriterSerializer <jv>serializer2</jv> = HtmlSerializer
332       *       .<jsm>create</jsm>()
333       *       .addKeyValueTableHeaders()
334       *       .build();
335       *
336       *    String <jv>withoutHeaders</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
337       *    String <jv>withHeaders</jv> = <jv>serializer2</jv>.serialize(<jk>new</jk> MyBean());
338       * </p>
339       *
340       * <p>
341       * The following shows the difference between the two generated outputs:
342       *
343       * <table class='styled'>
344       *    <tr>
345       *       <th><c>withoutHeaders</c></th>
346       *       <th><c>withHeaders</c></th>
347       *    </tr>
348       *    <tr>
349       *       <td>
350       *          <table class='unstyled'>
351       *             <tr><td>f1</td><td>foo</td></tr>
352       *             <tr><td>f2</td><td>bar</td></tr>
353       *          </table>
354       *       </td>
355       *       <td>
356       *          <table class='unstyled'>
357       *             <tr><th>key</th><th>value</th></tr>
358       *             <tr><td>f1</td><td>foo</td></tr>
359       *             <tr><td>f2</td><td>bar</td></tr>
360       *          </table>
361       *       </td>
362       *    </tr>
363       * </table>
364       *
365       * @return This object.
366       */
367      @FluentSetter
368      public Builder addKeyValueTableHeaders() {
369         return addKeyValueTableHeaders(true);
370      }
371
372      /**
373       * Same as {@link #addKeyValueTableHeaders()} but allows you to explicitly specify the value.
374       *
375       * @param value The value for this setting.
376       * @return This object.
377       */
378      @FluentSetter
379      public Builder addKeyValueTableHeaders(boolean value) {
380         addKeyValueTableHeaders = value;
381         return this;
382      }
383
384      /**
385       * <i><l>HtmlSerializer</l> configuration property:&emsp;</i>  Don't look for URLs in {@link String Strings}.
386       *
387       * <p>
388       * Disables the feature where if a string looks like a URL (i.e. starts with <js>"http://"</js> or <js>"https://"</js>, then treat it like a URL
389       * and make it into a hyperlink based on the rules specified by {@link Builder#uriAnchorText(AnchorText)}.
390       *
391       * <h5 class='section'>Example:</h5>
392       * <p class='bjson'>
393       *    <jc>// Our bean class with a property containing what looks like a URL.</jc>
394       *    <jk>public class</jk> MyBean {
395       *       <jk>public</jk> String <jf>f1</jf> = <js>"http://www.apache.org"</js>;
396       *    }
397       *
398       *  <jc>// Serializer with link detection.</jc>
399       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer
400       *       .<jsm>create</jsm>()
401       *       .addKeyValueTableHeaders()
402       *       .build();
403       *
404       *  <jc>// Serializer without link detection.</jc>
405       *    WriterSerializer <jv>serializer2</jv> = HtmlSerializer
406       *       .<jsm>create</jsm>()
407       *       .addKeyValueTableHeaders()
408       *       .disableDetectLinksInStrings()
409       *       .build();
410       *
411       *    String <jv>withLinks</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
412       *    String <jv>withoutLinks</jv> = <jv>serializer2</jv>.serialize(<jk>new</jk> MyBean());
413       * </p>
414       *
415       * <p>
416       * The following shows the difference between the two generated outputs:
417       *
418       * <table class='styled'>
419       *    <tr>
420       *       <th><c>withLinks</c></th>
421       *       <th><c>withoutLinks</c></th>
422       *    </tr>
423       *    <tr>
424       *       <td>
425       *          <table class='unstyled'>
426       *             <tr><th>key</th><th>value</th></tr>
427       *             <tr><td>f1</td><td><a href='http://www.apache.org'>http://www.apache.org</a></td></tr>
428       *          </table>
429       *       </td>
430       *       <td>
431       *          <table class='unstyled'>
432       *             <tr><th>key</th><th>value</th></tr>
433       *             <tr><td>f1</td><td>http://www.apache.org</td></tr>
434       *          </table>
435       *       </td>
436       *    </tr>
437       * </table>
438       *
439       * @return This object.
440       */
441      @FluentSetter
442      public Builder disableDetectLinksInStrings() {
443         return disableDetectLinksInStrings(true);
444      }
445
446      /**
447       * Same as {@link #disableDetectLinksInStrings()} but allows you to explicitly specify the value.
448       *
449       * @param value The value for this setting.
450       * @return This object.
451       */
452      @FluentSetter
453      public Builder disableDetectLinksInStrings(boolean value) {
454         disableDetectLinksInStrings = value;
455         return this;
456      }
457
458      /**
459       * <i><l>HtmlSerializer</l> configuration property:&emsp;</i>  Link label parameter name.
460       *
461       * <p>
462       * The parameter name to look for when resolving link labels}.
463       *
464       * @param value
465       *    The new value for this property.
466       *    <br>The default is <js>"label"</js>.
467       * @return This object.
468       */
469      @FluentSetter
470      public Builder labelParameter(String value) {
471         labelParameter = value;
472         return this;
473      }
474
475      /**
476       * <i><l>HtmlSerializer</l> configuration property:&emsp;</i>  Dont look for link labels in URIs.
477       *
478       * <p>
479       * Disables the feature where if the URL has a label parameter (e.g. <js>"?label=foobar"</js>), then use that as the anchor text of the link.
480       *
481       * <p>
482       * The parameter name can be changed via the {@link #labelParameter(String)} property.
483       *
484       * <h5 class='section'>Example:</h5>
485       * <p class='bjson'>
486       *    <jc>// Our bean class with a property containing what looks like a URL.</jc>
487       *    <jk>public class</jk> MyBean {
488       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"http://www.apache.org?label=Apache%20Foundation"</js>);
489       *    }
490       *
491       *  <jc>// Serializer with label detection.</jc>
492       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer
493       *       .<jsm>create</jsm>()
494       *       .addKeyValueTableHeaders()
495       *       .build();
496       *
497       *  <jc>// Serializer without label detection.</jc>
498       *    WriterSerializer <jv>serializer2</jv> = HtmlSerializer
499       *       .<jsm>create</jsm>()
500       *       .addKeyValueTableHeaders()
501       *       .disableDetectLabelParameters()
502       *       .build();
503       *
504       *    String <jv>withLabels</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
505       *    String <jv>withoutLabels</jv> = <jv>serializer2</jv>.serialize(<jk>new</jk> MyBean());
506       * </p>
507       *
508       * <p>
509       * The following shows the difference between the two generated outputs.
510       * <br>Note that they're both hyperlinks, but the anchor text differs:
511       *
512       * <table class='styled'>
513       *    <tr>
514       *       <th><c>withLabels</c></th>
515       *       <th><c>withoutLabels</c></th>
516       *    </tr>
517       *    <tr>
518       *       <td>
519       *          <table class='unstyled'>
520       *             <tr><th>key</th><th>value</th></tr>
521       *             <tr><td>f1</td><td><a href='http://www.apache.org?label=Apache%20Foundation'>Apache Foundation</a></td></tr>
522       *          </table>
523       *       </td>
524       *       <td>
525       *          <table class='unstyled'>
526       *             <tr><th>key</th><th>value</th></tr>
527       *             <tr><td>f1</td><td><a href='http://www.apache.org?label=Apache%20Foundation'>http://www.apache.org?label=Apache%20Foundation</a></td></tr>
528       *          </table>
529       *       </td>
530       *    </tr>
531       * </table>
532       *
533       * @return This object.
534       */
535      @FluentSetter
536      public Builder disableDetectLabelParameters() {
537         return disableDetectLabelParameters(true);
538      }
539
540      /**
541       * Same as {@link #disableDetectLabelParameters()} but allows you to explicitly specify the value.
542       *
543       * @param value The value for this setting.
544       * @return This object.
545       */
546      @FluentSetter
547      public Builder disableDetectLabelParameters(boolean value) {
548         disableDetectLabelParameters = value;
549         return this;
550      }
551
552      /**
553       * <i><l>HtmlSerializer</l> configuration property:&emsp;</i>  Anchor text source.
554       *
555       * <p>
556       * When creating anchor tags (e.g. <code><xt>&lt;a</xt> <xa>href</xa>=<xs>'...'</xs>
557       * <xt>&gt;</xt>text<xt>&lt;/a&gt;</xt></code>) in HTML, this setting defines what to set the inner text to.
558       *
559       * <p>
560       * The possible values are:
561       * <ul>
562       *    <li class='jc'>{@link AnchorText}
563       *    <ul>
564       *       <li class='jf'>{@link AnchorText#TO_STRING TO_STRING} (default) - Set to whatever is returned by {@link #toString()} on the object.
565       *          <br>
566       *          <h5 class='section'>Example:</h5>
567       *          <p class='bjson'>
568       *    <jc>// Our bean class with a URI property.</jc>
569       *    <jk>public class</jk> MyBean {
570       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"http://www.apache.org?foo=bar#myAnchor"</js>);
571       *    }
572       *
573       *    <jc>// Serializer with TO_STRING anchor text.</jc>
574       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer.<jsm>create</jsm>().anchorText(<jsf>TO_STRING</jsf>).build();
575       *
576       *    <jc>// Produces: &lt;a href='http://www.apache.org?foo=bar#myAnchor'&gt;http://www.apache.org?foo=bar#myAnchor&lt;/a&gt;</jc>
577       *    String <jv>html</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
578       *          </p>
579       *       <li class='jf'>{@link AnchorText#PROPERTY_NAME PROPERTY_NAME} - Set to the bean property name.
580       *          <br>
581       *          <h5 class='section'>Example:</h5>
582       *          <p class='bjson'>
583       *    <jc>// Our bean class with a URI property.</jc>
584       *    <jk>public class</jk> MyBean {
585       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"http://www.apache.org?foo=bar#myAnchor"</js>);
586       *    }
587       *
588       *    <jc>// Serializer with PROPERTY_NAME anchor text.</jc>
589       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer.<jsm>create</jsm>().anchorText(<jsf>PROPERTY_NAME</jsf>).build();
590       *
591       *    <jc>// Produces: &lt;a href='http://www.apache.org?foo=bar#myAnchor'&gt;f1&lt;/a&gt;</jc>
592       *    String <jv>html</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
593       *          </p>
594       *       <li class='jf'>{@link AnchorText#URI URI} - Set to the URI value.
595       *          <br>
596       *          <h5 class='section'>Example:</h5>
597       *          <p class='bjson'>
598       *    <jc>// Our bean class with a URI property.</jc>
599       *    <jk>public class</jk> MyBean {
600       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"http://www.apache.org?foo=bar#myAnchor"</js>);
601       *    }
602       *
603       *    <jc>// Serializer with URI anchor text.</jc>
604       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer.<jsm>create</jsm>().anchorText(<jsf>URI</jsf>).build();
605       *
606       *    <jc>// Produces: &lt;a href='http://www.apache.org?foo=bar#myAnchor'&gt;http://www.apache.org?foo=bar&lt;/a&gt;</jc>
607       *    String <jv>html</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
608       *          </p>
609       *       <li class='jf'>{@link AnchorText#LAST_TOKEN LAST_TOKEN} - Set to the last token of the URI value.
610       *          <br>
611       *          <h5 class='section'>Example:</h5>
612       *          <p class='bjson'>
613       *    <jc>// Our bean class with a URI property.</jc>
614       *    <jk>public class</jk> MyBean {
615       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"http://www.apache.org/foo/bar?baz=qux#myAnchor"</js>);
616       *    }
617       *
618       *    <jc>// Serializer with LAST_TOKEN anchor text.</jc>
619       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer.<jsm>create</jsm>().anchorText(<jsf>LAST_TOKEN</jsf>).build();
620       *
621       *    <jc>// Produces: &lt;a href='http://www.apache.org/foo/bar?baz=qux#myAnchor'&gt;bar&lt;/a&gt;</jc>
622       *    String <jv>html</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
623       *          </p>
624       *       <li class='jf'>{@link AnchorText#URI_ANCHOR URI_ANCHOR} - Set to the anchor of the URL.
625       *          <br>
626       *          <h5 class='section'>Example:</h5>
627       *          <p class='bjson'>
628       *    <jc>// Our bean class with a URI property.</jc>
629       *    <jk>public class</jk> MyBean {
630       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"http://www.apache.org/foo/bar?baz=qux#myAnchor"</js>);
631       *    }
632       *
633       *    <jc>// Serializer with URI_ANCHOR anchor text.</jc>
634       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer.<jsm>create</jsm>().anchorText(<jsf>URI_ANCHOR</jsf>).build();
635       *
636       *    <jc>// Produces: &lt;a href='http://www.apache.org/foo/bar?baz=qux#myAnchor'&gt;myAnchor&lt;/a&gt;</jc>
637       *    String <jv>html</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
638       *          </p>
639       *       <li class='jf'>{@link AnchorText#CONTEXT_RELATIVE CONTEXT_RELATIVE} - Same as {@link AnchorText#TO_STRING TO_STRING} but assumes it's a context-relative path.
640       *          <br>
641       *          <h5 class='section'>Example:</h5>
642       *          <p class='bjson'>
643       *    <jc>// Our bean class with a URI property.</jc>
644       *    <jk>public class</jk> MyBean {
645       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"bar/baz"</js>);
646       *    }
647       *
648       *    <jc>// Serializer with CONTEXT_RELATIVE anchor text.</jc>
649       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer
650       *       .<jsm>create</jsm>()
651       *       .anchorText(<jsf>CONTEXT_RELATIVE</jsf>)
652       *       .uriResolution(<jsf>ROOT_RELATIVE</jsf>)
653       *       .uriRelativity(<jsf>RESOURCE</jsf>)
654       *       .uriContext(<js>"{authority:'http://localhost:10000',contextRoot:'/myContext',servletPath:'/myServlet',pathInfo:'/foo'}"</js>)
655       *       .build();
656       *
657       *    <jc>// Produces: &lt;a href&#61;'/myContext/myServlet/bar/baz'&gt;myServlet/bar/baz&lt;/a&gt;</jc>
658       *    String <jv>html</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
659       *          </p>
660       *       <li class='jf'>{@link AnchorText#SERVLET_RELATIVE SERVLET_RELATIVE} - Same as {@link AnchorText#TO_STRING TO_STRING} but assumes it's a servlet-relative path.
661       *          <br>
662       *          <h5 class='section'>Example:</h5>
663       *          <p class='bjson'>
664       *    <jc>// Our bean class with a URI property.</jc>
665       *    <jk>public class</jk> MyBean {
666       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"bar/baz"</js>);
667       *    }
668       *
669       *    <jc>// Serializer with SERVLET_RELATIVE anchor text.</jc>
670       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer
671       *       .<jsm>create</jsm>()
672       *       .anchorText(<jsf>SERVLET_RELATIVE</jsf>)
673       *       .uriResolution(<jsf>ROOT_RELATIVE</jsf>)
674       *       .uriRelativity(<jsf>RESOURCE</jsf>)
675       *       .uriContext(<js>"{authority:'http://localhost:10000',contextRoot:'/myContext',servletPath:'/myServlet',pathInfo:'/foo'}"</js>)
676       *       .build();
677       *
678       *    <jc>// Produces: &lt;a href&#61;'/myContext/myServlet/bar/baz'&gt;bar/baz&lt;/a&gt;</jc>
679       *    String <jv>html</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
680       *          </p>
681       *       <li class='jf'>{@link AnchorText#PATH_RELATIVE PATH_RELATIVE} - Same as {@link AnchorText#TO_STRING TO_STRING} but assumes it's a path-relative path.
682       *          <br>
683       *          <h5 class='section'>Example:</h5>
684       *          <p class='bjson'>
685       *    <jc>// Our bean class with a URI property.</jc>
686       *    <jk>public class</jk> MyBean {
687       *       <jk>public</jk> URI <jf>f1</jf> = URI.<jsm>create</jsm>(<js>"bar/baz"</js>);
688       *    }
689       *
690       *    <jc>// Serializer with PATH_RELATIVE anchor text.</jc>
691       *    WriterSerializer <jv>serializer1</jv> = HtmlSerializer
692       *       .<jsm>create</jsm>()
693       *       .anchorText(<jsf>PATH_RELATIVE</jsf>)
694       *       .uriResolution(<jsf>ROOT_RELATIVE</jsf>)
695       *       .uriRelativity(<jsf>PATH_INFO</jsf>)
696       *       .uriContext(<js>"{authority:'http://localhost:10000',contextRoot:'/myContext',servletPath:'/myServlet',pathInfo:'/foo'}"</js>)
697       *       .build();
698       *
699       *    <jc>// Produces: &lt;a href&#61;'/myContext/myServlet/foo/bar/baz'&gt;bar/baz&lt;/a&gt;</jc>
700       *    String <jv>html</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> MyBean());
701       *          </p>
702       *    </ul>
703       * </ul>
704       *
705       * @param value
706       *    The new value for this property.
707       *    <br>The default is {@link AnchorText#TO_STRING}.
708       * @return This object.
709       */
710      @FluentSetter
711      public Builder uriAnchorText(AnchorText value) {
712         uriAnchorText = value;
713         return this;
714      }
715
716      // <FluentSetters>
717
718      @Override /* GENERATED - org.apache.juneau.Context.Builder */
719      public Builder annotations(Annotation...values) {
720         super.annotations(values);
721         return this;
722      }
723
724      @Override /* GENERATED - org.apache.juneau.Context.Builder */
725      public Builder apply(AnnotationWorkList work) {
726         super.apply(work);
727         return this;
728      }
729
730      @Override /* GENERATED - org.apache.juneau.Context.Builder */
731      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
732         super.applyAnnotations(fromClasses);
733         return this;
734      }
735
736      @Override /* GENERATED - org.apache.juneau.Context.Builder */
737      public Builder applyAnnotations(Method...fromMethods) {
738         super.applyAnnotations(fromMethods);
739         return this;
740      }
741
742      @Override /* GENERATED - org.apache.juneau.Context.Builder */
743      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
744         super.cache(value);
745         return this;
746      }
747
748      @Override /* GENERATED - org.apache.juneau.Context.Builder */
749      public Builder debug() {
750         super.debug();
751         return this;
752      }
753
754      @Override /* GENERATED - org.apache.juneau.Context.Builder */
755      public Builder debug(boolean value) {
756         super.debug(value);
757         return this;
758      }
759
760      @Override /* GENERATED - org.apache.juneau.Context.Builder */
761      public Builder impl(Context value) {
762         super.impl(value);
763         return this;
764      }
765
766      @Override /* GENERATED - org.apache.juneau.Context.Builder */
767      public Builder type(Class<? extends org.apache.juneau.Context> value) {
768         super.type(value);
769         return this;
770      }
771
772      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
773      public Builder beanClassVisibility(Visibility value) {
774         super.beanClassVisibility(value);
775         return this;
776      }
777
778      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
779      public Builder beanConstructorVisibility(Visibility value) {
780         super.beanConstructorVisibility(value);
781         return this;
782      }
783
784      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
785      public Builder beanContext(BeanContext value) {
786         super.beanContext(value);
787         return this;
788      }
789
790      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
791      public Builder beanContext(BeanContext.Builder value) {
792         super.beanContext(value);
793         return this;
794      }
795
796      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
797      public Builder beanDictionary(java.lang.Class<?>...values) {
798         super.beanDictionary(values);
799         return this;
800      }
801
802      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
803      public Builder beanFieldVisibility(Visibility value) {
804         super.beanFieldVisibility(value);
805         return this;
806      }
807
808      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
809      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
810         super.beanInterceptor(on, value);
811         return this;
812      }
813
814      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
815      public Builder beanMapPutReturnsOldValue() {
816         super.beanMapPutReturnsOldValue();
817         return this;
818      }
819
820      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
821      public Builder beanMethodVisibility(Visibility value) {
822         super.beanMethodVisibility(value);
823         return this;
824      }
825
826      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
827      public Builder beanProperties(Map<String,Object> values) {
828         super.beanProperties(values);
829         return this;
830      }
831
832      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
833      public Builder beanProperties(Class<?> beanClass, String properties) {
834         super.beanProperties(beanClass, properties);
835         return this;
836      }
837
838      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
839      public Builder beanProperties(String beanClassName, String properties) {
840         super.beanProperties(beanClassName, properties);
841         return this;
842      }
843
844      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
845      public Builder beanPropertiesExcludes(Map<String,Object> values) {
846         super.beanPropertiesExcludes(values);
847         return this;
848      }
849
850      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
851      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
852         super.beanPropertiesExcludes(beanClass, properties);
853         return this;
854      }
855
856      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
857      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
858         super.beanPropertiesExcludes(beanClassName, properties);
859         return this;
860      }
861
862      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
863      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
864         super.beanPropertiesReadOnly(values);
865         return this;
866      }
867
868      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
869      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
870         super.beanPropertiesReadOnly(beanClass, properties);
871         return this;
872      }
873
874      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
875      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
876         super.beanPropertiesReadOnly(beanClassName, properties);
877         return this;
878      }
879
880      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
881      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
882         super.beanPropertiesWriteOnly(values);
883         return this;
884      }
885
886      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
887      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
888         super.beanPropertiesWriteOnly(beanClass, properties);
889         return this;
890      }
891
892      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
893      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
894         super.beanPropertiesWriteOnly(beanClassName, properties);
895         return this;
896      }
897
898      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
899      public Builder beansRequireDefaultConstructor() {
900         super.beansRequireDefaultConstructor();
901         return this;
902      }
903
904      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
905      public Builder beansRequireSerializable() {
906         super.beansRequireSerializable();
907         return this;
908      }
909
910      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
911      public Builder beansRequireSettersForGetters() {
912         super.beansRequireSettersForGetters();
913         return this;
914      }
915
916      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
917      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
918         super.dictionaryOn(on, values);
919         return this;
920      }
921
922      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
923      public Builder disableBeansRequireSomeProperties() {
924         super.disableBeansRequireSomeProperties();
925         return this;
926      }
927
928      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
929      public Builder disableIgnoreMissingSetters() {
930         super.disableIgnoreMissingSetters();
931         return this;
932      }
933
934      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
935      public Builder disableIgnoreTransientFields() {
936         super.disableIgnoreTransientFields();
937         return this;
938      }
939
940      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
941      public Builder disableIgnoreUnknownNullBeanProperties() {
942         super.disableIgnoreUnknownNullBeanProperties();
943         return this;
944      }
945
946      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
947      public Builder disableInterfaceProxies() {
948         super.disableInterfaceProxies();
949         return this;
950      }
951
952      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
953      public <T> Builder example(Class<T> pojoClass, T o) {
954         super.example(pojoClass, o);
955         return this;
956      }
957
958      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
959      public <T> Builder example(Class<T> pojoClass, String json) {
960         super.example(pojoClass, json);
961         return this;
962      }
963
964      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
965      public Builder findFluentSetters() {
966         super.findFluentSetters();
967         return this;
968      }
969
970      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
971      public Builder findFluentSetters(Class<?> on) {
972         super.findFluentSetters(on);
973         return this;
974      }
975
976      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
977      public Builder ignoreInvocationExceptionsOnGetters() {
978         super.ignoreInvocationExceptionsOnGetters();
979         return this;
980      }
981
982      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
983      public Builder ignoreInvocationExceptionsOnSetters() {
984         super.ignoreInvocationExceptionsOnSetters();
985         return this;
986      }
987
988      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
989      public Builder ignoreUnknownBeanProperties() {
990         super.ignoreUnknownBeanProperties();
991         return this;
992      }
993
994      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
995      public Builder ignoreUnknownEnumValues() {
996         super.ignoreUnknownEnumValues();
997         return this;
998      }
999
1000      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1001      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
1002         super.implClass(interfaceClass, implClass);
1003         return this;
1004      }
1005
1006      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1007      public Builder implClasses(Map<Class<?>,Class<?>> values) {
1008         super.implClasses(values);
1009         return this;
1010      }
1011
1012      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1013      public Builder interfaceClass(Class<?> on, Class<?> value) {
1014         super.interfaceClass(on, value);
1015         return this;
1016      }
1017
1018      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1019      public Builder interfaces(java.lang.Class<?>...value) {
1020         super.interfaces(value);
1021         return this;
1022      }
1023
1024      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1025      public Builder locale(Locale value) {
1026         super.locale(value);
1027         return this;
1028      }
1029
1030      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1031      public Builder mediaType(MediaType value) {
1032         super.mediaType(value);
1033         return this;
1034      }
1035
1036      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1037      public Builder notBeanClasses(java.lang.Class<?>...values) {
1038         super.notBeanClasses(values);
1039         return this;
1040      }
1041
1042      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1043      public Builder notBeanPackages(String...values) {
1044         super.notBeanPackages(values);
1045         return this;
1046      }
1047
1048      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1049      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
1050         super.propertyNamer(value);
1051         return this;
1052      }
1053
1054      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1055      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
1056         super.propertyNamer(on, value);
1057         return this;
1058      }
1059
1060      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1061      public Builder sortProperties() {
1062         super.sortProperties();
1063         return this;
1064      }
1065
1066      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1067      public Builder sortProperties(java.lang.Class<?>...on) {
1068         super.sortProperties(on);
1069         return this;
1070      }
1071
1072      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1073      public Builder stopClass(Class<?> on, Class<?> value) {
1074         super.stopClass(on, value);
1075         return this;
1076      }
1077
1078      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1079      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
1080         super.swap(normalClass, swappedClass, swapFunction);
1081         return this;
1082      }
1083
1084      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1085      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
1086         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
1087         return this;
1088      }
1089
1090      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1091      public Builder swaps(java.lang.Class<?>...values) {
1092         super.swaps(values);
1093         return this;
1094      }
1095
1096      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1097      public Builder timeZone(TimeZone value) {
1098         super.timeZone(value);
1099         return this;
1100      }
1101
1102      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1103      public Builder typeName(Class<?> on, String value) {
1104         super.typeName(on, value);
1105         return this;
1106      }
1107
1108      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1109      public Builder typePropertyName(String value) {
1110         super.typePropertyName(value);
1111         return this;
1112      }
1113
1114      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1115      public Builder typePropertyName(Class<?> on, String value) {
1116         super.typePropertyName(on, value);
1117         return this;
1118      }
1119
1120      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1121      public Builder useEnumNames() {
1122         super.useEnumNames();
1123         return this;
1124      }
1125
1126      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
1127      public Builder useJavaBeanIntrospector() {
1128         super.useJavaBeanIntrospector();
1129         return this;
1130      }
1131
1132      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
1133      public Builder detectRecursions() {
1134         super.detectRecursions();
1135         return this;
1136      }
1137
1138      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
1139      public Builder detectRecursions(boolean value) {
1140         super.detectRecursions(value);
1141         return this;
1142      }
1143
1144      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
1145      public Builder ignoreRecursions() {
1146         super.ignoreRecursions();
1147         return this;
1148      }
1149
1150      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
1151      public Builder ignoreRecursions(boolean value) {
1152         super.ignoreRecursions(value);
1153         return this;
1154      }
1155
1156      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
1157      public Builder initialDepth(int value) {
1158         super.initialDepth(value);
1159         return this;
1160      }
1161
1162      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
1163      public Builder maxDepth(int value) {
1164         super.maxDepth(value);
1165         return this;
1166      }
1167
1168      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1169      public Builder accept(String value) {
1170         super.accept(value);
1171         return this;
1172      }
1173
1174      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1175      public Builder addBeanTypes() {
1176         super.addBeanTypes();
1177         return this;
1178      }
1179
1180      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1181      public Builder addBeanTypes(boolean value) {
1182         super.addBeanTypes(value);
1183         return this;
1184      }
1185
1186      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1187      public Builder addRootType() {
1188         super.addRootType();
1189         return this;
1190      }
1191
1192      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1193      public Builder addRootType(boolean value) {
1194         super.addRootType(value);
1195         return this;
1196      }
1197
1198      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1199      public Builder keepNullProperties() {
1200         super.keepNullProperties();
1201         return this;
1202      }
1203
1204      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1205      public Builder keepNullProperties(boolean value) {
1206         super.keepNullProperties(value);
1207         return this;
1208      }
1209
1210      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1211      public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
1212         super.listener(value);
1213         return this;
1214      }
1215
1216      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1217      public Builder produces(String value) {
1218         super.produces(value);
1219         return this;
1220      }
1221
1222      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1223      public Builder sortCollections() {
1224         super.sortCollections();
1225         return this;
1226      }
1227
1228      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1229      public Builder sortCollections(boolean value) {
1230         super.sortCollections(value);
1231         return this;
1232      }
1233
1234      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1235      public Builder sortMaps() {
1236         super.sortMaps();
1237         return this;
1238      }
1239
1240      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1241      public Builder sortMaps(boolean value) {
1242         super.sortMaps(value);
1243         return this;
1244      }
1245
1246      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1247      public Builder trimEmptyCollections() {
1248         super.trimEmptyCollections();
1249         return this;
1250      }
1251
1252      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1253      public Builder trimEmptyCollections(boolean value) {
1254         super.trimEmptyCollections(value);
1255         return this;
1256      }
1257
1258      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1259      public Builder trimEmptyMaps() {
1260         super.trimEmptyMaps();
1261         return this;
1262      }
1263
1264      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1265      public Builder trimEmptyMaps(boolean value) {
1266         super.trimEmptyMaps(value);
1267         return this;
1268      }
1269
1270      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1271      public Builder trimStrings() {
1272         super.trimStrings();
1273         return this;
1274      }
1275
1276      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1277      public Builder trimStrings(boolean value) {
1278         super.trimStrings(value);
1279         return this;
1280      }
1281
1282      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1283      public Builder uriContext(UriContext value) {
1284         super.uriContext(value);
1285         return this;
1286      }
1287
1288      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1289      public Builder uriRelativity(UriRelativity value) {
1290         super.uriRelativity(value);
1291         return this;
1292      }
1293
1294      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1295      public Builder uriResolution(UriResolution value) {
1296         super.uriResolution(value);
1297         return this;
1298      }
1299
1300      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1301      public Builder fileCharset(Charset value) {
1302         super.fileCharset(value);
1303         return this;
1304      }
1305
1306      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1307      public Builder maxIndent(int value) {
1308         super.maxIndent(value);
1309         return this;
1310      }
1311
1312      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1313      public Builder quoteChar(char value) {
1314         super.quoteChar(value);
1315         return this;
1316      }
1317
1318      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1319      public Builder quoteCharOverride(char value) {
1320         super.quoteCharOverride(value);
1321         return this;
1322      }
1323
1324      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1325      public Builder sq() {
1326         super.sq();
1327         return this;
1328      }
1329
1330      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1331      public Builder streamCharset(Charset value) {
1332         super.streamCharset(value);
1333         return this;
1334      }
1335
1336      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1337      public Builder useWhitespace() {
1338         super.useWhitespace();
1339         return this;
1340      }
1341
1342      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1343      public Builder useWhitespace(boolean value) {
1344         super.useWhitespace(value);
1345         return this;
1346      }
1347
1348      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1349      public Builder ws() {
1350         super.ws();
1351         return this;
1352      }
1353
1354      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1355      public Builder addBeanTypesXml() {
1356         super.addBeanTypesXml();
1357         return this;
1358      }
1359
1360      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1361      public Builder addBeanTypesXml(boolean value) {
1362         super.addBeanTypesXml(value);
1363         return this;
1364      }
1365
1366      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1367      public Builder addNamespaceUrisToRoot() {
1368         super.addNamespaceUrisToRoot();
1369         return this;
1370      }
1371
1372      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1373      public Builder addNamespaceUrisToRoot(boolean value) {
1374         super.addNamespaceUrisToRoot(value);
1375         return this;
1376      }
1377
1378      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1379      public Builder defaultNamespace(Namespace value) {
1380         super.defaultNamespace(value);
1381         return this;
1382      }
1383
1384      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1385      public Builder disableAutoDetectNamespaces() {
1386         super.disableAutoDetectNamespaces();
1387         return this;
1388      }
1389
1390      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1391      public Builder disableAutoDetectNamespaces(boolean value) {
1392         super.disableAutoDetectNamespaces(value);
1393         return this;
1394      }
1395
1396      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1397      public Builder enableNamespaces() {
1398         super.enableNamespaces();
1399         return this;
1400      }
1401
1402      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1403      public Builder enableNamespaces(boolean value) {
1404         super.enableNamespaces(value);
1405         return this;
1406      }
1407
1408      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1409      public Builder namespaces(Namespace...values) {
1410         super.namespaces(values);
1411         return this;
1412      }
1413
1414      @Override /* GENERATED - org.apache.juneau.xml.XmlSerializer.Builder */
1415      public Builder ns() {
1416         super.ns();
1417         return this;
1418      }
1419
1420      // </FluentSetters>
1421   }
1422
1423   //-------------------------------------------------------------------------------------------------------------------
1424   // Instance
1425   //-------------------------------------------------------------------------------------------------------------------
1426
1427   final AnchorText uriAnchorText;
1428   final boolean
1429      detectLabelParameters,
1430      detectLinksInStrings,
1431      addKeyValueTableHeaders,
1432      addBeanTypesHtml;
1433   final String labelParameter;
1434
1435   private final Map<ClassMeta<?>,HtmlClassMeta> htmlClassMetas = new ConcurrentHashMap<>();
1436   private final Map<BeanPropertyMeta,HtmlBeanPropertyMeta> htmlBeanPropertyMetas = new ConcurrentHashMap<>();
1437
1438   private volatile HtmlSchemaSerializer schemaSerializer;
1439
1440   /**
1441    * Constructor.
1442    *
1443    * @param builder The builder for this object.
1444    */
1445   public HtmlSerializer(Builder builder) {
1446      super(builder);
1447      detectLabelParameters = ! builder.disableDetectLabelParameters;
1448      detectLinksInStrings = ! builder.disableDetectLinksInStrings;
1449      addKeyValueTableHeaders = builder.addKeyValueTableHeaders;
1450      labelParameter = builder.labelParameter;
1451      uriAnchorText = builder.uriAnchorText;
1452      addBeanTypesHtml = builder.addBeanTypesHtml;
1453   }
1454
1455   @Override /* Context */
1456   public Builder copy() {
1457      return new Builder(this);
1458   }
1459
1460   @Override /* Context */
1461   public HtmlSerializerSession.Builder createSession() {
1462      return HtmlSerializerSession.create(this);
1463   }
1464
1465   @Override /* Context */
1466   public HtmlSerializerSession getSession() {
1467      return createSession().build();
1468   }
1469
1470   /**
1471    * Returns the schema serializer.
1472    *
1473    * @return The schema serializer.
1474    */
1475   public HtmlSerializer getSchemaSerializer() {
1476      if (schemaSerializer == null)
1477         schemaSerializer = HtmlSchemaSerializer.create().beanContext(getBeanContext()).build();
1478      return schemaSerializer;
1479   }
1480
1481   //-----------------------------------------------------------------------------------------------------------------
1482   // Extended metadata
1483   //-----------------------------------------------------------------------------------------------------------------
1484
1485   @Override /* HtmlMetaProvider */
1486   public HtmlClassMeta getHtmlClassMeta(ClassMeta<?> cm) {
1487      HtmlClassMeta m = htmlClassMetas.get(cm);
1488      if (m == null) {
1489         m = new HtmlClassMeta(cm, this);
1490         htmlClassMetas.put(cm, m);
1491      }
1492      return m;
1493   }
1494
1495   @Override /* HtmlMetaProvider */
1496   public HtmlBeanPropertyMeta getHtmlBeanPropertyMeta(BeanPropertyMeta bpm) {
1497      if (bpm == null)
1498         return HtmlBeanPropertyMeta.DEFAULT;
1499      HtmlBeanPropertyMeta m = htmlBeanPropertyMetas.get(bpm);
1500      if (m == null) {
1501         m = new HtmlBeanPropertyMeta(bpm.getDelegateFor(), this);
1502         htmlBeanPropertyMetas.put(bpm, m);
1503      }
1504      return m;
1505   }
1506
1507   //-----------------------------------------------------------------------------------------------------------------
1508   // Properties
1509   //-----------------------------------------------------------------------------------------------------------------
1510
1511   /**
1512    * Add <js>"_type"</js> properties when needed.
1513    *
1514    * @see Builder#addBeanTypesHtml()
1515    * @return
1516    *    <jk>true</jk> if <js>"_type"</js> properties will be added to beans if their type cannot be inferred
1517    *    through reflection.
1518    */
1519   @Override
1520   protected final boolean isAddBeanTypes() {
1521      return addBeanTypesHtml || super.isAddBeanTypes();
1522   }
1523
1524   /**
1525    * Add key/value headers on bean/map tables.
1526    *
1527    * @see Builder#addKeyValueTableHeaders()
1528    * @return
1529    *    <jk>true</jk> if <bc>key</bc> and <bc>value</bc> column headers are added to tables.
1530    */
1531   protected final boolean isAddKeyValueTableHeaders() {
1532      return addKeyValueTableHeaders;
1533   }
1534
1535   /**
1536    * Look for link labels in URIs.
1537    *
1538    * @see Builder#disableDetectLabelParameters()
1539    * @return
1540    *    <jk>true</jk> if we should look for URL label parameters (e.g. <js>"?label=foobar"</js>).
1541    */
1542   protected final boolean isDetectLabelParameters() {
1543      return detectLabelParameters;
1544   }
1545
1546   /**
1547    * Look for URLs in {@link String Strings}.
1548    *
1549    * @see Builder#disableDetectLinksInStrings()
1550    * @return
1551    *    <jk>true</jk> if we should automatically convert strings to URLs if they look like a URL.
1552    */
1553   protected final boolean isDetectLinksInStrings() {
1554      return detectLinksInStrings;
1555   }
1556
1557   /**
1558    * Link label parameter name.
1559    *
1560    * @see Builder#labelParameter(String)
1561    * @return
1562    *    The parameter name to look for when resolving link labels.
1563    */
1564   protected final String getLabelParameter() {
1565      return labelParameter;
1566   }
1567
1568   /**
1569    * Anchor text source.
1570    *
1571    * @see Builder#uriAnchorText(AnchorText)
1572    * @return
1573    *    When creating anchor tags (e.g. <code><xt>&lt;a</xt> <xa>href</xa>=<xs>'...'</xs>
1574    *    <xt>&gt;</xt>text<xt>&lt;/a&gt;</xt></code>) in HTML, this setting defines what to set the inner text to.
1575    */
1576   protected final AnchorText getUriAnchorText() {
1577      return uriAnchorText;
1578   }
1579
1580   //-----------------------------------------------------------------------------------------------------------------
1581   // Other methods
1582   //-----------------------------------------------------------------------------------------------------------------
1583
1584   @Override /* Context */
1585   protected JsonMap properties() {
1586      return filteredMap()
1587         .append("uriAnchorText", uriAnchorText)
1588         .append("detectLabelParameters", detectLabelParameters)
1589         .append("detectLinksInStrings", detectLinksInStrings)
1590         .append("labelParameter", labelParameter)
1591         .append("addKeyValueTableHeaders", addKeyValueTableHeaders)
1592         .append("addBeanTypesHtml", addBeanTypesHtml);
1593   }
1594}