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.oapi;
014
015import java.util.*;
016import java.util.concurrent.*;
017
018import org.apache.juneau.*;
019import org.apache.juneau.annotation.*;
020import org.apache.juneau.collections.*;
021import org.apache.juneau.httppart.*;
022import org.apache.juneau.jsonschema.annotation.*;
023import org.apache.juneau.serializer.*;
024import org.apache.juneau.uon.*;
025
026/**
027 * Serializes POJOs to values suitable for transmission as HTTP headers, query/form-data parameters, and path variables.
028 *
029 * <ul class='seealso'>
030 *    <li class='link'>{@doc OpenApiSerializers}
031 * </ul>
032 */
033@ConfigurableContext
034public class OpenApiSerializer extends UonSerializer implements OpenApiMetaProvider, OpenApiCommon {
035
036   //-------------------------------------------------------------------------------------------------------------------
037   // Configurable properties
038   //-------------------------------------------------------------------------------------------------------------------
039
040   static final String PREFIX = "OpenApiSerializer";
041
042   //-------------------------------------------------------------------------------------------------------------------
043   // Predefined instances
044   //-------------------------------------------------------------------------------------------------------------------
045
046   /** Reusable instance of {@link OpenApiSerializer}, all default settings. */
047   public static final OpenApiSerializer DEFAULT = new OpenApiSerializer(PropertyStore.DEFAULT);
048
049
050   //-------------------------------------------------------------------------------------------------------------------
051   // Instance
052   //-------------------------------------------------------------------------------------------------------------------
053
054   private final Map<ClassMeta<?>,OpenApiClassMeta> openApiClassMetas = new ConcurrentHashMap<>();
055   private final Map<BeanPropertyMeta,OpenApiBeanPropertyMeta> openApiBeanPropertyMetas = new ConcurrentHashMap<>();
056   private final HttpPartFormat format;
057   private final HttpPartCollectionFormat collectionFormat;
058
059   /**
060    * Constructor.
061    *
062    * @param ps
063    *    The property store containing all the settings for this object.
064    * @param produces
065    *    The media type that this serializer produces.
066    * @param accept
067    *    The accept media types that the serializer can handle.
068    *    <p>
069    *    Can contain meta-characters per the <c>media-type</c> specification of {@doc ExtRFC2616.section14.1}
070    *    <p>
071    *    If empty, then assumes the only media type supported is <c>produces</c>.
072    *    <p>
073    *    For example, if this serializer produces <js>"application/json"</js> but should handle media types of
074    *    <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
075    *    <p class='bcode w800'>
076    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
077    *    </p>
078    *    <br>...or...
079    *    <p class='bcode w800'>
080    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
081    *    </p>
082    * <p>
083    * The accept value can also contain q-values.
084    */
085   public OpenApiSerializer(PropertyStore ps, String produces, String accept) {
086      super(
087         ps.builder()
088            .setDefault(UON_encoding, false)
089            .build(),
090         produces,
091         accept
092      );
093      format = getProperty(OAPI_format, HttpPartFormat.class, HttpPartFormat.NO_FORMAT);
094      collectionFormat = getProperty(OAPI_collectionFormat, HttpPartCollectionFormat.class, HttpPartCollectionFormat.NO_COLLECTION_FORMAT);
095   }
096
097   /**
098    * Constructor.
099    *
100    * @param ps
101    *    The property store containing all the settings for this object.
102    */
103   public OpenApiSerializer(PropertyStore ps) {
104      this(ps, "text/openapi", null);
105   }
106
107   @Override /* Context */
108   public OpenApiSerializerBuilder builder() {
109      return new OpenApiSerializerBuilder(getPropertyStore());
110   }
111
112   /**
113    * Instantiates a new clean-slate {@link OpenApiSerializerBuilder} object.
114    *
115    * <p>
116    * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies
117    * the settings of the object called on.
118    *
119    * @return A new {@link OpenApiSerializerBuilder} object.
120    */
121   public static OpenApiSerializerBuilder create() {
122      return new OpenApiSerializerBuilder();
123   }
124
125   //-----------------------------------------------------------------------------------------------------------------
126   // Entry point methods
127   //-----------------------------------------------------------------------------------------------------------------
128
129   @Override /* Context */
130   public OpenApiSerializerSession createSession() {
131      return createSession(createDefaultSessionArgs());
132   }
133
134   @Override /* Serializer */
135   public OpenApiSerializerSession createSession(SerializerSessionArgs args) {
136      return new OpenApiSerializerSession(this, args);
137   }
138
139   @Override /* HttpPartSerializer */
140   public OpenApiSerializerSession createPartSession(SerializerSessionArgs args) {
141      return new OpenApiSerializerSession(this, args);
142   }
143
144   //-----------------------------------------------------------------------------------------------------------------
145   // Extended metadata
146   //-----------------------------------------------------------------------------------------------------------------
147
148   @Override /* OpenApiMetaProvider */
149   public OpenApiClassMeta getOpenApiClassMeta(ClassMeta<?> cm) {
150      OpenApiClassMeta m = openApiClassMetas.get(cm);
151      if (m == null) {
152         m = new OpenApiClassMeta(cm, this);
153         openApiClassMetas.put(cm, m);
154      }
155      return m;
156   }
157
158   @Override /* OpenApiMetaProvider */
159   public OpenApiBeanPropertyMeta getOpenApiBeanPropertyMeta(BeanPropertyMeta bpm) {
160      if (bpm == null)
161         return OpenApiBeanPropertyMeta.DEFAULT;
162      OpenApiBeanPropertyMeta m = openApiBeanPropertyMetas.get(bpm);
163      if (m == null) {
164         m = new OpenApiBeanPropertyMeta(bpm.getDelegateFor(), this);
165         openApiBeanPropertyMetas.put(bpm, m);
166      }
167      return m;
168   }
169
170   //-----------------------------------------------------------------------------------------------------------------
171   // Properties
172   //-----------------------------------------------------------------------------------------------------------------
173
174   /**
175    * Returns the default format to use when not otherwise specified via {@link Schema#format()}
176    *
177    * @return The default format to use when not otherwise specified via {@link Schema#format()}
178    */
179   protected final HttpPartFormat getFormat() {
180      return format;
181   }
182
183   /**
184    * Returns the default collection format to use when not otherwise specified via {@link Schema#collectionFormat()}
185    *
186    * @return The default collection format to use when not otherwise specified via {@link Schema#collectionFormat()}
187    */
188   protected final HttpPartCollectionFormat getCollectionFormat() {
189      return collectionFormat;
190   }
191
192   //-----------------------------------------------------------------------------------------------------------------
193   // Other methods
194   //-----------------------------------------------------------------------------------------------------------------
195
196   @Override /* Context */
197   public OMap toMap() {
198      return super.toMap()
199         .a("OpenApiSerializer", new DefaultFilteringOMap()
200         );
201   }
202}