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