1818
1919import static com .google .common .base .MoreObjects .firstNonNull ;
2020import static com .google .common .collect .ImmutableList .toImmutableList ;
21- import static com .linecorp .armeria .internal .server .annotation .AnnotatedDocServicePlugin .toTypeSignature ;
2221import static com .linecorp .armeria .internal .server .annotation .AnnotatedValueResolver .isAnnotatedNullable ;
22+ import static com .linecorp .armeria .server .docs .DocServiceTypeUtil .toTypeSignature ;
2323import static java .util .Objects .requireNonNull ;
2424
2525import java .lang .reflect .AnnotatedElement ;
@@ -74,29 +74,6 @@ public final class DefaultDescriptiveTypeInfoProvider implements DescriptiveType
7474 this .request = request ;
7575 }
7676
77- @ Nullable
78- @ Override
79- public DescriptiveTypeInfo newDescriptiveTypeInfo (Object typeDescriptor ) {
80- requireNonNull (typeDescriptor , "typeDescriptor" );
81- if (!(typeDescriptor instanceof Class )) {
82- return null ;
83- }
84- final Class <?> clazz = (Class <?>) typeDescriptor ;
85- if (clazz .isEnum ()) {
86- return newEnumInfo (clazz );
87- }
88-
89- if (HttpResponse .class .isAssignableFrom (clazz )) {
90- return HTTP_RESPONSE_INFO ;
91- }
92-
93- if (request ) {
94- return requestStructInfo (clazz );
95- } else {
96- return responseStructInfo (clazz );
97- }
98- }
99-
10077 private static EnumInfo newEnumInfo (Class <?> enumClass ) {
10178 final String name = enumClass .getName ();
10279
@@ -118,123 +95,6 @@ private static EnumInfo newEnumInfo(Class<?> enumClass) {
11895 return new EnumInfo (name , values , classDescriptionInfo (enumClass ));
11996 }
12097
121- private StructInfo requestStructInfo (Class <?> type ) {
122- final JavaType javaType = mapper .constructType (type );
123- if (!mapper .canDeserialize (javaType )) {
124- return newReflectiveStructInfo (type );
125- }
126- return new StructInfo (type .getName (), requestFieldInfos (javaType ),
127- classDescriptionInfo (javaType .getRawClass ()));
128- }
129-
130- private List <FieldInfo > requestFieldInfos (JavaType javaType ) {
131- if (!mapper .canDeserialize (javaType )) {
132- return ImmutableList .of ();
133- }
134-
135- final BeanDescription description = mapper .getDeserializationConfig ().introspect (javaType );
136- final List <BeanPropertyDefinition > properties = description .findProperties ();
137- if (properties .isEmpty ()) {
138- return newReflectiveStructInfo (javaType .getRawClass ()).fields ();
139- }
140-
141- return properties .stream ()
142- .map (property -> fieldInfos (javaType ,
143- property .getName (),
144- property .getInternalName (),
145- property .getPrimaryType ()))
146- .collect (toImmutableList ());
147- }
148-
149- private StructInfo responseStructInfo (Class <?> type ) {
150- if (!mapper .canSerialize (type )) {
151- return newReflectiveStructInfo (type );
152- }
153- final JavaType javaType = mapper .constructType (type );
154- return new StructInfo (type .getName (), responseFieldInfos (javaType ), classDescriptionInfo (type ));
155- }
156-
157- private List <FieldInfo > responseFieldInfos (JavaType javaType ) {
158- if (!mapper .canSerialize (javaType .getRawClass ())) {
159- return ImmutableList .of ();
160- }
161-
162- final BeanDescription description = mapper .getSerializationConfig ().introspect (javaType );
163- final List <BeanPropertyDefinition > properties = description .findProperties ();
164- if (properties .isEmpty ()) {
165- return newReflectiveStructInfo (javaType .getRawClass ()).fields ();
166- }
167-
168- return properties .stream ()
169- .map (property -> fieldInfos (javaType ,
170- property .getName (),
171- property .getInternalName (),
172- property .getPrimaryType ()))
173- .collect (toImmutableList ());
174- }
175-
176- private FieldInfo fieldInfos (JavaType javaType , String name , String internalName , JavaType fieldType ) {
177- TypeSignature typeSignature = toTypeSignature (fieldType );
178- final FieldRequirement fieldRequirement ;
179- if (typeSignature .type () == TypeSignatureType .OPTIONAL ) {
180- typeSignature = ((ContainerTypeSignature ) typeSignature ).typeParameters ().get (0 );
181- if (typeSignature .type ().hasTypeDescriptor ()) {
182- final Object descriptor =
183- ((DescriptiveTypeSignature ) typeSignature ).descriptor ();
184- if (descriptor instanceof Class ) {
185- fieldType = mapper .constructType ((Class <?>) descriptor );
186- }
187- }
188- fieldRequirement = FieldRequirement .OPTIONAL ;
189- } else {
190- fieldRequirement = fieldRequirement (javaType , fieldType , internalName );
191- }
192-
193- final DescriptionInfo descriptionInfo = fieldDescriptionInfo (javaType , fieldType , internalName );
194- return FieldInfo .builder (name , typeSignature )
195- .requirement (fieldRequirement )
196- .descriptionInfo (descriptionInfo )
197- .build ();
198- }
199-
200- private FieldRequirement fieldRequirement (JavaType classType , JavaType fieldType , String fieldName ) {
201- if (fieldType .isPrimitive ()) {
202- return FieldRequirement .REQUIRED ;
203- }
204-
205- if (KotlinUtil .isData (classType .getRawClass ())) {
206- // Only the parameters in the constructor of data classes correctly provide
207- // `isMarkedNullable` information.
208- final FieldRequirement requirement =
209- extractFromConstructor (classType , fieldType , fieldName , parameter -> {
210- if (isNullable (parameter )) {
211- return FieldRequirement .OPTIONAL ;
212- } else {
213- return FieldRequirement .REQUIRED ;
214- }
215- });
216- if (requirement != null ) {
217- return requirement ;
218- }
219- }
220-
221- final FieldRequirement requirement =
222- extractFieldMeta (classType , fieldType , fieldName , element -> {
223- if (request ) {
224- if (element instanceof Method ) {
225- // Use the first parameter information for the setter method
226- element = ((Method ) element ).getParameters ()[0 ];
227- }
228- }
229- if (isNullable (element )) {
230- return FieldRequirement .OPTIONAL ;
231- }
232- return FieldRequirement .REQUIRED ;
233- });
234-
235- return firstNonNull (requirement , FieldRequirement .UNSPECIFIED );
236- }
237-
23898 static boolean isNullable (AnnotatedElement element ) {
23999 return isAnnotatedNullable (element ) || KotlinUtil .isMarkedNullable (element );
240100 }
@@ -248,28 +108,6 @@ private static DescriptionInfo classDescriptionInfo(Class<?> clazz) {
248108 }
249109 }
250110
251- private DescriptionInfo fieldDescriptionInfo (JavaType classType , JavaType fieldType , String fieldName ) {
252- final Description description = extractFieldMeta (classType , fieldType , fieldName , element -> {
253- return AnnotationUtil .findFirst (element , Description .class );
254- });
255-
256- if (description != null ) {
257- return DescriptionInfo .from (description );
258- } else {
259- return DescriptionInfo .empty ();
260- }
261- }
262-
263- @ Nullable
264- private <T > T extractFieldMeta (JavaType classType , JavaType fieldType , String fieldName ,
265- Function <AnnotatedElement , @ Nullable T > extractor ) {
266- if (request ) {
267- return extractRequestFieldMeta (classType , fieldType , fieldName , extractor );
268- } else {
269- return extractResponseFieldMeta (classType , fieldType , fieldName , extractor );
270- }
271- }
272-
273111 @ Nullable
274112 private static <T > T extractRequestFieldMeta (JavaType classType , JavaType fieldType , String fieldName ,
275113 Function <AnnotatedElement , @ Nullable T > extractor ) {
@@ -430,4 +268,166 @@ private static <T> T extractFromGetter(JavaType classType, JavaType fieldType, S
430268 private static StructInfo newReflectiveStructInfo (Class <?> clazz ) {
431269 return (StructInfo ) ReflectiveDescriptiveTypeInfoProvider .INSTANCE .newDescriptiveTypeInfo (clazz );
432270 }
271+
272+ @ Nullable
273+ @ Override
274+ public DescriptiveTypeInfo newDescriptiveTypeInfo (Object typeDescriptor ) {
275+ requireNonNull (typeDescriptor , "typeDescriptor" );
276+ if (!(typeDescriptor instanceof Class )) {
277+ return null ;
278+ }
279+ final Class <?> clazz = (Class <?>) typeDescriptor ;
280+ if (clazz .isEnum ()) {
281+ return newEnumInfo (clazz );
282+ }
283+
284+ if (HttpResponse .class .isAssignableFrom (clazz )) {
285+ return HTTP_RESPONSE_INFO ;
286+ }
287+
288+ if (request ) {
289+ return requestStructInfo (clazz );
290+ } else {
291+ return responseStructInfo (clazz );
292+ }
293+ }
294+
295+ private StructInfo requestStructInfo (Class <?> type ) {
296+ final JavaType javaType = mapper .constructType (type );
297+ if (!mapper .canDeserialize (javaType )) {
298+ return newReflectiveStructInfo (type );
299+ }
300+ return new StructInfo (type .getName (), requestFieldInfos (javaType ),
301+ classDescriptionInfo (javaType .getRawClass ()));
302+ }
303+
304+ private List <FieldInfo > requestFieldInfos (JavaType javaType ) {
305+ if (!mapper .canDeserialize (javaType )) {
306+ return ImmutableList .of ();
307+ }
308+
309+ final BeanDescription description = mapper .getDeserializationConfig ().introspect (javaType );
310+ final List <BeanPropertyDefinition > properties = description .findProperties ();
311+ if (properties .isEmpty ()) {
312+ return newReflectiveStructInfo (javaType .getRawClass ()).fields ();
313+ }
314+
315+ return properties .stream ()
316+ .map (property -> fieldInfos (javaType ,
317+ property .getName (),
318+ property .getInternalName (),
319+ property .getPrimaryType ()))
320+ .collect (toImmutableList ());
321+ }
322+
323+ private StructInfo responseStructInfo (Class <?> type ) {
324+ if (!mapper .canSerialize (type )) {
325+ return newReflectiveStructInfo (type );
326+ }
327+ final JavaType javaType = mapper .constructType (type );
328+ return new StructInfo (type .getName (), responseFieldInfos (javaType ), classDescriptionInfo (type ));
329+ }
330+
331+ private List <FieldInfo > responseFieldInfos (JavaType javaType ) {
332+ if (!mapper .canSerialize (javaType .getRawClass ())) {
333+ return ImmutableList .of ();
334+ }
335+
336+ final BeanDescription description = mapper .getSerializationConfig ().introspect (javaType );
337+ final List <BeanPropertyDefinition > properties = description .findProperties ();
338+ if (properties .isEmpty ()) {
339+ return newReflectiveStructInfo (javaType .getRawClass ()).fields ();
340+ }
341+
342+ return properties .stream ()
343+ .map (property -> fieldInfos (javaType ,
344+ property .getName (),
345+ property .getInternalName (),
346+ property .getPrimaryType ()))
347+ .collect (toImmutableList ());
348+ }
349+
350+ private FieldInfo fieldInfos (JavaType javaType , String name , String internalName , JavaType fieldType ) {
351+ TypeSignature typeSignature = toTypeSignature (fieldType );
352+ final FieldRequirement fieldRequirement ;
353+ if (typeSignature .type () == TypeSignatureType .OPTIONAL ) {
354+ typeSignature = ((ContainerTypeSignature ) typeSignature ).typeParameters ().get (0 );
355+ if (typeSignature .type ().hasTypeDescriptor ()) {
356+ final Object descriptor =
357+ ((DescriptiveTypeSignature ) typeSignature ).descriptor ();
358+ if (descriptor instanceof Class ) {
359+ fieldType = mapper .constructType ((Class <?>) descriptor );
360+ }
361+ }
362+ fieldRequirement = FieldRequirement .OPTIONAL ;
363+ } else {
364+ fieldRequirement = fieldRequirement (javaType , fieldType , internalName );
365+ }
366+
367+ final DescriptionInfo descriptionInfo = fieldDescriptionInfo (javaType , fieldType , internalName );
368+ return FieldInfo .builder (name , typeSignature )
369+ .requirement (fieldRequirement )
370+ .descriptionInfo (descriptionInfo )
371+ .build ();
372+ }
373+
374+ private FieldRequirement fieldRequirement (JavaType classType , JavaType fieldType , String fieldName ) {
375+ if (fieldType .isPrimitive ()) {
376+ return FieldRequirement .REQUIRED ;
377+ }
378+
379+ if (KotlinUtil .isData (classType .getRawClass ())) {
380+ // Only the parameters in the constructor of data classes correctly provide
381+ // `isMarkedNullable` information.
382+ final FieldRequirement requirement =
383+ extractFromConstructor (classType , fieldType , fieldName , parameter -> {
384+ if (isNullable (parameter )) {
385+ return FieldRequirement .OPTIONAL ;
386+ } else {
387+ return FieldRequirement .REQUIRED ;
388+ }
389+ });
390+ if (requirement != null ) {
391+ return requirement ;
392+ }
393+ }
394+
395+ final FieldRequirement requirement =
396+ extractFieldMeta (classType , fieldType , fieldName , element -> {
397+ if (request ) {
398+ if (element instanceof Method ) {
399+ // Use the first parameter information for the setter method
400+ element = ((Method ) element ).getParameters ()[0 ];
401+ }
402+ }
403+ if (isNullable (element )) {
404+ return FieldRequirement .OPTIONAL ;
405+ }
406+ return FieldRequirement .REQUIRED ;
407+ });
408+
409+ return firstNonNull (requirement , FieldRequirement .UNSPECIFIED );
410+ }
411+
412+ private DescriptionInfo fieldDescriptionInfo (JavaType classType , JavaType fieldType , String fieldName ) {
413+ final Description description = extractFieldMeta (classType , fieldType , fieldName , element -> {
414+ return AnnotationUtil .findFirst (element , Description .class );
415+ });
416+
417+ if (description != null ) {
418+ return DescriptionInfo .from (description );
419+ } else {
420+ return DescriptionInfo .empty ();
421+ }
422+ }
423+
424+ @ Nullable
425+ private <T > T extractFieldMeta (JavaType classType , JavaType fieldType , String fieldName ,
426+ Function <AnnotatedElement , @ Nullable T > extractor ) {
427+ if (request ) {
428+ return extractRequestFieldMeta (classType , fieldType , fieldName , extractor );
429+ } else {
430+ return extractResponseFieldMeta (classType , fieldType , fieldName , extractor );
431+ }
432+ }
433433}
0 commit comments