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>"*​/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}