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.commons.collections.*; 020import org.apache.juneau.marshall.*; 021import org.apache.juneau.marshall.json.*; 022import org.apache.juneau.marshall.jsonschema.*; 023 024/** 025 * Serializes POJO metamodels to HTML. 026 * 027 * <h5 class='topic'>Media types</h5> 028 * 029 * Handles <c>Accept</c> types: <bc>text/html+schema</bc> 030 * <p> 031 * Produces <c>Content-Type</c> types: <bc>text/html</bc> 032 * 033 * <h5 class='topic'>Description</h5> 034 * 035 * Essentially the same as {@link HtmlSerializer}, except serializes the POJO metamodel instead of the model itself. 036 * 037 * <p> 038 * Produces output that describes the POJO metamodel similar to an XML schema document. 039 * 040 * <p> 041 * The easiest way to create instances of this class is through the {@link HtmlSerializer#getSchemaSerializer()}, 042 * which will create a schema serializer with the same settings as the originating serializer. 043 * 044 * <h5 class='section'>Notes:</h5><ul> 045 * <li class='note'>This class is thread safe and reusable. 046 * </ul> 047 * 048 * <h5 class='section'>See Also:</h5><ul> 049 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HtmlSupport">HTML</a> 050 051 * </ul> 052 */ 053@SuppressWarnings({ 054 "java:S110", // Inheritance depth acceptable for HtmlSchemaSerializer hierarchy 055 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 056 "java:S9149" // Per-format static factories intentionally shadow the parent's. 057}) 058public class HtmlSchemaSerializer extends HtmlSerializer { 059 060 /** 061 * Builder class. 062 */ 063 public static class Builder extends HtmlSerializer.Builder<Builder> { 064 065 private static final Cache<HashKey,HtmlSchemaSerializer> CACHE = Cache.of(HashKey.class, HtmlSchemaSerializer.class).build(); 066 067 JsonSchemaGenerator.Builder generatorBuilder; 068 069 /** 070 * Constructor, default settings. 071 */ 072 protected Builder() { 073 produces("text/html"); 074 accept("text/html+schema"); 075 generatorBuilder = JsonSchemaGenerator.create().marshallingContext(marshallingContext()); 076 } 077 078 /** 079 * Copy constructor. 080 * 081 * @param copyFrom The builder to copy from. 082 */ 083 protected Builder(Builder copyFrom) { 084 super(copyFrom); 085 generatorBuilder = copyFrom.generatorBuilder.copy().marshallingContext(marshallingContext()); 086 } 087 088 /** 089 * Copy constructor. 090 * 091 * @param copyFrom The bean to copy from. 092 */ 093 protected Builder(HtmlSchemaSerializer copyFrom) { 094 super(copyFrom); 095 generatorBuilder = copyFrom.generator.copy().marshallingContext(marshallingContext()); 096 } 097 098 /** 099 * <i><l>HtmlSchemaSerializer</l> configuration property: </i> Add descriptions. 100 * 101 * <p> 102 * Identifies which categories of types that descriptions should be automatically added to generated schemas. 103 * <p> 104 * The description is the result of calling {@link ClassMeta#getName()}. 105 * 106 * <h5 class='section'>See Also:</h5><ul> 107 * <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#addDescriptionsTo(TypeCategory...) JsonSchemaGenerator.Builder#addDescriptionsTo(TypeCategory...)} 108 * </ul> 109 * 110 * @param values 111 * The values to add to this setting. 112 * <br>The default is an empty string. 113 * @return This object. 114 */ 115 public Builder addDescriptionsTo(TypeCategory...values) { 116 generatorBuilder.addDescriptionsTo(values); 117 return this; 118 } 119 120 /** 121 * <i><l>HtmlSchemaSerializer</l> configuration property: </i> Add examples. 122 * 123 * <p> 124 * Identifies which categories of types that examples should be automatically added to generated schemas. 125 * <p> 126 * The examples come from calling {@link ClassMeta#getExample(MarshallingSession,JsonParserSession)} which in turn gets examples 127 * from the following: 128 * <ul class='javatree'> 129 * <li class='ja'>{@link Example} 130 * <li class='ja'>{@link Marshalled#example() Marshalled(example)} 131 * </ul> 132 * 133 * <h5 class='section'>See Also:</h5><ul> 134 * <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#addExamplesTo(TypeCategory...) JsonSchemaGenerator.Builder#addExamplesTo(TypeCategory...)} 135 * </ul> 136 * 137 * @param values 138 * The values to add to this setting. 139 * <br>The default is an empty string. 140 * @return This object. 141 */ 142 public Builder addExamplesTo(TypeCategory...values) { 143 generatorBuilder.addExamplesTo(values); 144 return this; 145 } 146 147 /** 148 * <i><l>HtmlSchemaSerializer</l> configuration property: </i> Allow nested descriptions. 149 * 150 * <p> 151 * Identifies whether nested descriptions are allowed in schema definitions. 152 * 153 * <h5 class='section'>See Also:</h5><ul> 154 * <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#allowNestedDescriptions() JsonSchemaGenerator.Builder#allowNestedDescriptions()} 155 * </ul> 156 * 157 * @return This object. 158 */ 159 public Builder allowNestedDescriptions() { 160 generatorBuilder.allowNestedDescriptions(); 161 return this; 162 } 163 164 /** 165 * <i><l>HtmlSchemaSerializer</l> configuration property: </i> Allow nested examples. 166 * 167 * <p> 168 * Identifies whether nested examples are allowed in schema definitions. 169 * 170 * <h5 class='section'>See Also:</h5><ul> 171 * <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#allowNestedExamples() JsonSchemaGenerator.Builder#allowNestedExamples()} 172 * </ul> 173 * 174 * @return This object. 175 */ 176 public Builder allowNestedExamples() { 177 generatorBuilder.allowNestedExamples(); 178 return this; 179 } 180 181 /** 182 * <i><l>HtmlSchemaSerializer</l> configuration property: </i> Schema definition mapper. 183 * 184 * <p> 185 * Interface to use for converting Bean classes to definition IDs and URIs. 186 * <p> 187 * Used primarily for defining common definition sections for beans in Swagger JSON. 188 * <p> 189 * This setting is ignored if {@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#useBeanDefs() JsonSchemaGenerator.Builder#useBeanDefs()} is not enabled. 190 * 191 * <h5 class='section'>See Also:</h5><ul> 192 * <li class='jm'>{@link org.apache.juneau.marshall.jsonschema.JsonSchemaGenerator.Builder#beanDefMapper(Class) JsonSchemaGenerator.Builder#beanDefMapper(Class)} 193 * </ul> 194 * 195 * @param value 196 * The new value for this property. 197 * <br>The default is {@link BasicBeanDefMapper}. 198 * @return This object. 199 */ 200 public Builder beanDefMapper(Class<? extends MarshallingDefMapper> value) { 201 generatorBuilder.beanDefMapper(value); 202 return this; 203 } 204 205 @Override /* Overridden from Context.Builder<?> */ 206 public HtmlSchemaSerializer build() { 207 return cache(CACHE).build(HtmlSchemaSerializer.class); 208 } 209 210 @Override /* Overridden from Context.Builder<?> */ 211 public Builder copy() { 212 return new Builder(this); 213 } 214 215 @Override /* Overridden from Context.Builder<?> */ 216 public HashKey hashKey() { 217 // @formatter:off 218 return HashKey.of( 219 super.hashKey(), 220 generatorBuilder.hashKey() 221 ); 222 // @formatter:on 223 } 224 225 /** 226 * <i><l>HtmlSchemaSerializer</l> configuration property: </i> Use bean definitions. 227 * 228 * <p> 229 * When enabled, schemas on beans will be serialized as the following: 230 * <p class='bjson'> 231 * { 232 * type: <js>'object'</js>, 233 * <js>'$ref'</js>: <js>'#/definitions/TypeId'</js> 234 * } 235 * </p> 236 * 237 * @return This object. 238 */ 239 public Builder useBeanDefs() { 240 generatorBuilder.useBeanDefs(); 241 return this; 242 } 243 244 245 } 246 247 /** Default serializer, with whitespace. */ 248 public static class Readable extends HtmlSchemaSerializer { 249 250 /** 251 * Constructor. 252 * 253 * @param builder The builder for this object. 254 */ 255 public Readable(Builder builder) { 256 super(builder.useWhitespace()); 257 } 258 } 259 260 /** Default serializer, single quotes, simple mode. */ 261 public static class Simple extends HtmlSchemaSerializer { 262 263 /** 264 * Constructor. 265 * 266 * @param builder The builder for this object. 267 */ 268 public Simple(Builder builder) { 269 super(builder.quoteChar('\'')); 270 } 271 } 272 273 /** Default serializer, single quotes, simple mode, with whitespace. */ 274 public static class SimpleReadable extends HtmlSchemaSerializer { 275 276 /** 277 * Constructor. 278 * 279 * @param builder The builder for this object. 280 */ 281 public SimpleReadable(Builder builder) { 282 super(builder.quoteChar('\'').useWhitespace()); 283 } 284 } 285 286 /** Default serializer, all default settings.*/ 287 public static final HtmlSchemaSerializer DEFAULT = new HtmlSchemaSerializer(create()); 288 /** Default serializer, all default settings.*/ 289 public static final HtmlSchemaSerializer DEFAULT_READABLE = new Readable(create()); 290 291 /** Default serializer, single quotes, simple mode. */ 292 public static final HtmlSchemaSerializer DEFAULT_SIMPLE = new Simple(create()); 293 294 /** Default serializer, single quotes, simple mode, with whitespace. */ 295 public static final HtmlSchemaSerializer DEFAULT_SIMPLE_READABLE = new SimpleReadable(create()); 296 297 /** 298 * Creates a new builder for this object. 299 * 300 * @return A new builder. 301 */ 302 public static Builder create() { 303 return new Builder(); 304 } 305 306 final JsonSchemaGenerator generator; 307 308 /** 309 * Constructor. 310 * 311 * @param builder The builder for this serializer. 312 */ 313 public HtmlSchemaSerializer(Builder builder) { 314 super(builder.detectRecursions().ignoreRecursions()); 315 316 generator = builder.generatorBuilder.build(); 317 } 318 319 @Override /* Overridden from Context */ 320 public Builder copy() { 321 return new Builder(this); 322 } 323 324 @Override /* Overridden from Context */ 325 public HtmlSchemaSerializerSession.Builder createSession() { 326 return HtmlSchemaSerializerSession.create(this); 327 } 328 329 @Override /* Overridden from Context */ 330 public HtmlSchemaSerializerSession getSession() { return createSession().build(); } 331 332 @Override /* Overridden from HtmlSerializer */ 333 protected FluentMap<String,Object> properties() { 334 return super.properties() 335 .a("generator", generator); 336 } 337 338 JsonSchemaGenerator getGenerator() { return generator; } 339}