22
33import com .google .api .client .util .Maps ;
44import com .google .api .server .spi .TypeLoader ;
5+ import com .google .api .server .spi .config .Description ;
56import com .google .api .server .spi .config .ResourcePropertySchema ;
67import com .google .api .server .spi .config .ResourceSchema ;
78import com .google .api .server .spi .config .annotationreader .ApiAnnotationIntrospector ;
89import com .google .api .server .spi .config .jsonwriter .JacksonResourceSchemaProvider ;
910import com .google .api .server .spi .config .jsonwriter .ResourceSchemaProvider ;
11+ import com .google .api .server .spi .config .model .Schema .Builder ;
1012import com .google .api .server .spi .config .model .Schema .Field ;
1113import com .google .api .server .spi .config .model .Schema .SchemaReference ;
1214import com .google .common .annotations .VisibleForTesting ;
1315import com .google .common .base .Optional ;
16+ import com .google .common .base .Strings ;
1417import com .google .common .collect .ImmutableList ;
1518import com .google .common .collect .LinkedHashMultimap ;
1619import com .google .common .collect .Multimap ;
@@ -121,7 +124,7 @@ private Map<TypeToken<?>, Schema> getAllTypesForConfig(ApiConfig config) {
121124 }
122125
123126 private Schema getOrCreateTypeForConfig (
124- TypeToken type , Map <TypeToken <?>, Schema > typesForConfig , ApiConfig config ) {
127+ TypeToken <?> type , Map <TypeToken <?>, Schema > typesForConfig , ApiConfig config ) {
125128 type = ApiAnnotationIntrospector .getSchemaType (type , config );
126129 Schema schema = typesForConfig .get (type );
127130 ApiKey key = config .getApiKey ().withoutRoot ();
@@ -139,54 +142,64 @@ private Schema getOrCreateTypeForConfig(
139142 TypeToken <?> arrayItemType = Types .getArrayItemType (type );
140143 if (typeLoader .isSchemaType (type )) {
141144 throw new IllegalArgumentException ("Can't add a primitive type as a resource" );
142- } else if (arrayItemType != null ) {
143- Field .Builder arrayItemSchema = Field .builder ().setName (ARRAY_UNUSED_MSG );
144- fillInFieldInformation (arrayItemSchema , arrayItemType , null , typesForConfig , config );
145- schema = Schema .builder ()
146- .setName (Types .getSimpleName (type , config .getSerializationConfig ()))
147- .setType ("object" )
148- .addField ("items" , Field .builder ()
149- .setName ("items" )
150- .setType (FieldType .ARRAY )
151- .setArrayItemSchema (arrayItemSchema .build ())
152- .build ())
153- .build ();
154- typesForConfig .put (type , schema );
155- schemaByApiKeys .put (key , schema );
156- return schema ;
157- } else if (Types .isObject (type )) {
158- typesForConfig .put (type , ANY_SCHEMA );
159- schemaByApiKeys .put (key , ANY_SCHEMA );
160- return ANY_SCHEMA ;
161- } else if (Types .isMapType (type )) {
162- schema = MAP_SCHEMA ;
163- final TypeToken <Map <?, ?>> mapSupertype = type .getSupertype (Map .class );
164- final boolean hasConcreteKeyValue = Types .isConcreteType (mapSupertype .getType ());
165- boolean forceJsonMapSchema = EndpointsFlag .MAP_SCHEMA_FORCE_JSON_MAP_SCHEMA .isEnabled ();
166- if (hasConcreteKeyValue && !forceJsonMapSchema ) {
167- schema = createMapSchema (mapSupertype , typesForConfig , config ).or (schema );
168- }
169- typesForConfig .put (type , schema );
170- schemaByApiKeys .put (key , schema );
171- return schema ;
172- } else if (Types .isEnumType (type )) {
173- Map <String , String > valuesAndDescriptions = Types .getEnumValuesAndDescriptions (type );
174- Schema .Builder builder = Schema .builder ()
175- .setName (Types .getSimpleName (type , config .getSerializationConfig ()))
176- .setType ("string" );
177- for (Entry <String , String > entry : valuesAndDescriptions .entrySet ()) {
178- builder .addEnumValue (entry .getKey ());
179- builder .addEnumDescription (entry .getValue ());
180- }
181- schema = builder .build ();
182- typesForConfig .put (type , schema );
183- schemaByApiKeys .put (key , schema );
184- return schema ;
185145 } else {
186- schema = createBeanSchema (type , typesForConfig , config );
187- typesForConfig .put (type , schema );
188- schemaByApiKeys .put (key , schema );
189- return schema ;
146+ String simpleName = Types .getSimpleName (type , config .getSerializationConfig ());
147+ if (arrayItemType != null ) {
148+ Field .Builder arrayItemSchema = Field .builder ().setName (ARRAY_UNUSED_MSG );
149+ fillInFieldInformation (arrayItemSchema , arrayItemType , typesForConfig , config );
150+ Field arrayField = arrayItemSchema .build ();
151+ Builder builder = Schema .builder ()
152+ .setName (simpleName )
153+ .setType ("object" )
154+ .addField ("items" , Field .builder ()
155+ .setName ("items" )
156+ .setType (FieldType .ARRAY )
157+ .setArrayItemSchema (arrayField )
158+ .build ());
159+ SchemaReference itemSchema = arrayField .schemaReference ();
160+ if (itemSchema != null ) {
161+ builder .setDescription ("An ordered list of " + itemSchema .get ().name ());
162+ }
163+ schema = builder .build ();
164+ typesForConfig .put (type , schema );
165+ schemaByApiKeys .put (key , schema );
166+ return schema ;
167+ } else if (Types .isObject (type )) {
168+ typesForConfig .put (type , ANY_SCHEMA );
169+ schemaByApiKeys .put (key , ANY_SCHEMA );
170+ return ANY_SCHEMA ;
171+ } else if (Types .isMapType (type )) {
172+ schema = MAP_SCHEMA ;
173+ final TypeToken <Map <?, ?>> mapSupertype = ((TypeToken ) type ).getSupertype (Map .class );
174+ final boolean hasConcreteKeyValue = Types .isConcreteType (mapSupertype .getType ());
175+ boolean forceJsonMapSchema = EndpointsFlag .MAP_SCHEMA_FORCE_JSON_MAP_SCHEMA .isEnabled ();
176+ if (hasConcreteKeyValue && !forceJsonMapSchema ) {
177+ schema = createMapSchema (mapSupertype , typesForConfig , config ).or (schema );
178+ }
179+ typesForConfig .put (type , schema );
180+ schemaByApiKeys .put (key , schema );
181+ return schema ;
182+ } else if (Types .isEnumType (type )) {
183+ Map <String , String > valuesAndDescriptions
184+ = Types .getEnumValuesAndDescriptions ((TypeToken <Enum <?>>) type );
185+ Schema .Builder builder = Schema .builder ()
186+ .setName (simpleName )
187+ .setType ("string" );
188+ setSchemaDescription (type , builder );
189+ for (Entry <String , String > entry : valuesAndDescriptions .entrySet ()) {
190+ builder .addEnumValue (entry .getKey ());
191+ builder .addEnumDescription (entry .getValue ());
192+ }
193+ schema = builder .build ();
194+ typesForConfig .put (type , schema );
195+ schemaByApiKeys .put (key , schema );
196+ return schema ;
197+ } else {
198+ schema = createBeanSchema (type , typesForConfig , config );
199+ typesForConfig .put (type , schema );
200+ schemaByApiKeys .put (key , schema );
201+ return schema ;
202+ }
190203 }
191204 }
192205
@@ -237,35 +250,42 @@ private Optional<Schema> createMapSchema(
237250 .setName (Types .getSimpleName (mapType , config .getSerializationConfig ()))
238251 .setType ("object" );
239252 Field .Builder fieldBuilder = Field .builder ().setName (MAP_UNUSED_MSG );
240- fillInFieldInformation (fieldBuilder , valueSchemaType , null , typesForConfig , config );
241- return Optional .of (builder .setMapValueSchema (fieldBuilder .build ()).build ());
253+ fillInFieldInformation (fieldBuilder , valueSchemaType , typesForConfig , config );
254+ Field mapValueField = fieldBuilder .build ();
255+ SchemaReference valueSchema = mapValueField .schemaReference ();
256+ if (valueSchema != null ) {
257+ builder .setDescription (
258+ String .format ("A collection of name / %s pairs" , valueSchema .get ().name ()));
259+ }
260+ return Optional .of (builder .setMapValueSchema (mapValueField ).build ());
242261 }
243262
244263 private Schema createBeanSchema (
245264 TypeToken <?> type , Map <TypeToken <?>, Schema > typesForConfig , ApiConfig config ) {
246265 Schema .Builder builder = Schema .builder ()
247266 .setName (Types .getSimpleName (type , config .getSerializationConfig ()))
248267 .setType ("object" );
268+ setSchemaDescription (type , builder );
249269 ResourceSchema schema = resourceSchemaProvider .getResourceSchema (type , config );
250270 for (Entry <String , ResourcePropertySchema > entry : schema .getProperties ().entrySet ()) {
251271 String propertyName = entry .getKey ();
252272 ResourcePropertySchema propertySchema = entry .getValue ();
253273 TypeToken <?> propertyType = propertySchema .getType ();
254274 if (propertyType != null ) {
255- Field .Builder fieldBuilder = Field .builder ().setName (propertyName );
256- fillInFieldInformation (fieldBuilder , propertyType , propertySchema .getDescription (),
257- typesForConfig , config );
275+ Field .Builder fieldBuilder = Field .builder ()
276+ .setName (propertyName )
277+ .setDescription (propertySchema .getDescription ());
278+ fillInFieldInformation (fieldBuilder , propertyType , typesForConfig , config );
258279 builder .addField (propertyName , fieldBuilder .build ());
259280 }
260281 }
261282 return builder .build ();
262283 }
263284
264285 private void fillInFieldInformation (Field .Builder builder , TypeToken <?> fieldType ,
265- String description , Map <TypeToken <?>, Schema > typesForConfig , ApiConfig config ) {
286+ Map <TypeToken <?>, Schema > typesForConfig , ApiConfig config ) {
266287 FieldType ft = FieldType .fromType (fieldType );
267288 builder .setType (ft );
268- builder .setDescription (description );
269289 if (ft == FieldType .OBJECT || ft == FieldType .ENUM ) {
270290 getOrCreateTypeForConfig (fieldType , typesForConfig , config );
271291 builder .setSchemaReference (SchemaReference .create (this , config , fieldType ));
@@ -274,12 +294,18 @@ private void fillInFieldInformation(Field.Builder builder, TypeToken<?> fieldTyp
274294 fillInFieldInformation (
275295 arrayItemBuilder ,
276296 ApiAnnotationIntrospector .getSchemaType (Types .getArrayItemType (fieldType ), config ),
277- null ,
278297 typesForConfig ,
279298 config );
280299 builder .setArrayItemSchema (arrayItemBuilder .build ());
281300 }
282301 }
302+
303+ private void setSchemaDescription (TypeToken <?> type , Builder builder ) {
304+ Description description = type .getRawType ().getAnnotation (Description .class );
305+ if (description != null && !Strings .isNullOrEmpty (description .value ())) {
306+ builder .setDescription (description .value ());
307+ }
308+ }
283309
284310 public static boolean isJsonMapSchema (Schema schema ) {
285311 return schema == MAP_SCHEMA ;
0 commit comments