001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.marshall.html;
018
019import org.apache.juneau.marshall.*;
020import org.apache.juneau.marshall.json.*;
021import org.apache.juneau.marshall.jsonschema.*;
022
023/**
024 * Serializes POJO metamodels to HTML.
025 *
026 * <h5 class='topic'>Media types</h5>
027 *
028 * Handles <c>Accept</c> types:  <bc>text/html+schema</bc>
029 * <p>
030 * Produces <c>Content-Type</c> types:  <bc>text/html</bc>
031 *
032 * <h5 class='topic'>Description</h5>
033 *
034 * Essentially the same as {@link HtmlDocSerializer}, except serializes the POJO metamodel instead of the model itself.
035 *
036 * <p>
037 * Produces output that describes the POJO metamodel similar to an XML schema document.
038 *
039 * <p>
040 * The easiest way to create instances of this class is through the {@link HtmlSerializer#getSchemaSerializer()},
041 * which will create a schema serializer with the same settings as the originating serializer.
042 *
043 * <h5 class='section'>Notes:</h5><ul>
044 *    <li class='note'>This class is thread safe and reusable.
045 * </ul>
046 *
047 * <h5 class='section'>See Also:</h5><ul>
048 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HtmlSupport">HTML</a>
049
050 * </ul>
051 */
052@SuppressWarnings({
053   "java:S110", // Inheritance depth acceptable for HtmlSchemaDocSerializer hierarchy
054   "java:S9149" // Per-format static factories intentionally shadow the parent's.
055})
056public class HtmlSchemaDocSerializer extends HtmlDocSerializer {
057
058   /**
059    * Builder class.
060    */
061   public static class Builder extends HtmlDocSerializer.Builder<Builder> {
062
063      JsonSchemaGenerator.Builder generatorBuilder;
064
065      /**
066       * Constructor, default settings.
067       */
068      protected Builder() {
069         produces("text/html");
070         accept("text/html+schema");
071         generatorBuilder = JsonSchemaGenerator.create().marshallingContext(marshallingContext());
072      }
073
074      /**
075       * Copy constructor.
076       *
077       * @param copyFrom The builder to copy from.
078       */
079      protected Builder(Builder copyFrom) {
080         super(copyFrom);
081         generatorBuilder = copyFrom.generatorBuilder.copy().marshallingContext(marshallingContext());
082      }
083
084      /**
085       * Copy constructor.
086       *
087       * @param copyFrom The bean to copy from.
088       */
089      protected Builder(HtmlSchemaDocSerializer copyFrom) {
090         super(copyFrom);
091         generatorBuilder = copyFrom.generator.copy().marshallingContext(marshallingContext());
092      }
093
094      /**
095       * <i><l>HtmlSchemaSerializer</l> configuration property:&emsp;</i>  Add descriptions.
096       *
097       * <p>
098       * Identifies which categories of types that descriptions should be automatically added to generated schemas.
099       * <p>
100       * The description is the result of calling {@link ClassMeta#getName()}.
101       *
102       * <h5 class='section'>See Also:</h5><ul>
103       *    <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#addDescriptionsTo(TypeCategory...) JsonSchemaGenerator.Builder#addDescriptionsTo(TypeCategory...)}
104       * </ul>
105       *
106       * @param values
107       *    The values to add to this setting.
108       *    <br>The default is an empty string.
109       * @return This object.
110       */
111      public Builder addDescriptionsTo(TypeCategory...values) {
112         generatorBuilder.addDescriptionsTo(values);
113         return this;
114      }
115
116      /**
117       * <i><l>HtmlSchemaSerializer</l> configuration property:&emsp;</i>  Add examples.
118       *
119       * <p>
120       * Identifies which categories of types that examples should be automatically added to generated schemas.
121       * <p>
122       * The examples come from calling {@link ClassMeta#getExample(MarshallingSession,JsonParserSession)} which in turn gets examples
123       * from the following:
124       * <ul class='javatree'>
125       *    <li class='ja'>{@link Example}
126       *    <li class='ja'>{@link Marshalled#example() Marshalled(example)}
127       * </ul>
128       *
129       * <h5 class='section'>See Also:</h5><ul>
130       *    <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#addExamplesTo(TypeCategory...) JsonSchemaGenerator.Builder#addExamplesTo(TypeCategory...)}
131       * </ul>
132       *
133       * @param values
134       *    The values to add to this setting.
135       *    <br>The default is an empty string.
136       * @return This object.
137       */
138      public Builder addExamplesTo(TypeCategory...values) {
139         generatorBuilder.addExamplesTo(values);
140         return this;
141      }
142
143      /**
144       * <i><l>HtmlSchemaSerializer</l> configuration property:&emsp;</i>  Allow nested descriptions.
145       *
146       * <p>
147       * Identifies whether nested descriptions are allowed in schema definitions.
148       *
149       * <h5 class='section'>See Also:</h5><ul>
150       *    <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#allowNestedDescriptions() JsonSchemaGenerator.Builder#allowNestedDescriptions()}
151       * </ul>
152       *
153       * @return This object.
154       */
155      public Builder allowNestedDescriptions() {
156         generatorBuilder.allowNestedDescriptions();
157         return this;
158      }
159
160      /**
161       * <i><l>HtmlSchemaSerializer</l> configuration property:&emsp;</i>  Allow nested examples.
162       *
163       * <p>
164       * Identifies whether nested examples are allowed in schema definitions.
165       *
166       * <h5 class='section'>See Also:</h5><ul>
167       *    <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#allowNestedExamples() JsonSchemaGenerator.Builder#allowNestedExamples()}
168       * </ul>
169       *
170       * @return This object.
171       */
172      public Builder allowNestedExamples() {
173         generatorBuilder.allowNestedExamples();
174         return this;
175      }
176
177      /**
178       * <i><l>HtmlSchemaSerializer</l> configuration property:&emsp;</i>  Schema definition mapper.
179       *
180       * <p>
181       * Interface to use for converting Bean classes to definition IDs and URIs.
182       * <p>
183       * Used primarily for defining common definition sections for beans in Swagger JSON.
184       * <p>
185       * This setting is ignored if {@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#useBeanDefs() JsonSchemaGenerator.Builder#useBeanDefs()} is not enabled.
186       *
187       * <h5 class='section'>See Also:</h5><ul>
188       *    <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#beanDefMapper(Class) JsonSchemaGenerator.Builder#beanDefMapper(Class)}
189       * </ul>
190       *
191       * @param value
192       *    The new value for this property.
193       *    <br>The default is {@link BasicBeanDefMapper}.
194       * @return This object.
195       */
196      public Builder beanDefMapper(Class<? extends MarshallingDefMapper> value) {
197         generatorBuilder.beanDefMapper(value);
198         return this;
199      }
200
201      @Override /* Overridden from Context.Builder<?> */
202      public HtmlSchemaDocSerializer build() {
203         return build(HtmlSchemaDocSerializer.class);
204      }
205
206      @Override /* Overridden from Context.Builder<?> */
207      public Builder copy() {
208         return new Builder(this);
209      }
210
211      /**
212       * <i><l>HtmlSchemaSerializer</l> configuration property:&emsp;</i>  Use bean definitions.
213       *
214       * <p>
215       * When enabled, schemas on beans will be serialized as the following:
216       * <p class='bjson'>
217       *    {
218       *       type: <js>'object'</js>,
219       *       <js>'$ref'</js>: <js>'#/definitions/TypeId'</js>
220       *    }
221       * </p>
222       *
223       * @return This object.
224       */
225      public Builder useBeanDefs() {
226         generatorBuilder.useBeanDefs();
227         return this;
228      }
229
230
231      @Override /* Overridden from Builder */
232      @SuppressWarnings({
233         "unchecked" // Varargs method requires unchecked cast
234      })
235      public Builder widgets(Class<? extends HtmlWidget>...values) {
236         super.widgets(values);
237         return this;
238      }
239
240   }
241
242   /**
243    * Creates a new builder for this object.
244    *
245    * @return A new builder.
246    */
247   public static Builder create() {
248      return new Builder();
249   }
250
251   final JsonSchemaGenerator generator;
252
253   /**
254    * Constructor.
255    *
256    * @param builder
257    *    The builder for this object.
258    */
259   public HtmlSchemaDocSerializer(HtmlDocSerializer.Builder<?> builder) {
260      super(builder.detectRecursions().ignoreRecursions());
261
262      generator = JsonSchemaGenerator.create().marshallingContext(getMarshallingContext()).build();
263   }
264
265   @Override /* Overridden from Context */
266   public Builder copy() {
267      return new Builder(this);
268   }
269
270   @Override /* Overridden from Context */
271   public HtmlSchemaDocSerializerSession.Builder createSession() {
272      return HtmlSchemaDocSerializerSession.create(this);
273   }
274
275   @Override /* Overridden from Context */
276   public HtmlSchemaDocSerializerSession getSession() { return createSession().build(); }
277
278   JsonSchemaGenerator getGenerator() { return generator; }
279}