Skip to content

Commit

Permalink
Fixed a bug that javadoc of record class parameters was not recognized.
Browse files Browse the repository at this point in the history
  • Loading branch information
uc4w6c committed Mar 14, 2023
1 parent 809063d commit d25f9dd
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* *
* * *
* * * *
* * * * * Copyright 2019-2022 the original author or authors.
* * * * * Copyright 2019-2023 the original author or authors.
* * * * *
* * * * * Licensed under the Apache License, Version 2.0 (the "License");
* * * * * you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -105,7 +105,16 @@ private void setJavadocDescription(Class<?> cls, List<Field> fields, Schema exis
existingSchema.setDescription(javadocProvider.getClassJavadoc(cls));
}
Map<String, Schema> properties = existingSchema.getProperties();
if (!CollectionUtils.isEmpty(properties))
if (!CollectionUtils.isEmpty(properties)) {
if (cls.getSuperclass() != null && cls.isRecord()) {
Map<String, String> recordParamMap = javadocProvider.getRecordClassParamJavadoc(cls);
properties.entrySet().stream()
.filter(stringSchemaEntry -> StringUtils.isBlank(stringSchemaEntry.getValue().getDescription()))
.forEach(stringSchemaEntry -> {
if (recordParamMap.containsKey(stringSchemaEntry.getKey()))
stringSchemaEntry.getValue().setDescription(recordParamMap.get(stringSchemaEntry.getKey()));
});
}
properties.entrySet().stream()
.filter(stringSchemaEntry -> StringUtils.isBlank(stringSchemaEntry.getValue().getDescription()))
.forEach(stringSchemaEntry -> {
Expand All @@ -116,7 +125,7 @@ private void setJavadocDescription(Class<?> cls, List<Field> fields, Schema exis
stringSchemaEntry.getValue().setDescription(fieldJavadoc);
});
});

}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* *
* * *
* * * *
* * * * * Copyright 2019-2022 the original author or authors.
* * * * * Copyright 2019-2023 the original author or authors.
* * * * *
* * * * * Licensed under the Apache License, Version 2.0 (the "License");
* * * * * you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -42,6 +42,14 @@ public interface JavadocProvider {
*/
String getClassJavadoc(Class<?> cl);

/**
* Gets param descripton of record class.
*
* @param cl the class
* @return map of field and param descriptions
*/
Map<String, String> getRecordClassParamJavadoc(Class<?> cl);

/**
* Gets method description.
*
Expand Down Expand Up @@ -91,4 +99,3 @@ public interface JavadocProvider {
*/
String getFirstSentence(String text);
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* *
* * *
* * * *
* * * * * Copyright 2019-2022 the original author or authors.
* * * * * Copyright 2019-2023 the original author or authors.
* * * * *
* * * * * Licensed under the Apache License, Version 2.0 (the "License");
* * * * * you may not use this file except in compliance with the License.
Expand All @@ -28,6 +28,7 @@
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.github.therapi.runtimejavadoc.ClassJavadoc;
import com.github.therapi.runtimejavadoc.CommentFormatter;
Expand Down Expand Up @@ -65,6 +66,19 @@ public String getClassJavadoc(Class<?> cl) {
return formatter.format(classJavadoc.getComment());
}

/**
* Gets param descripton of record class.
*
* @param cl the class
* @return map of field and param descriptions
*/
@Override
public Map<String, String> getRecordClassParamJavadoc(Class<?> cl) {
ClassJavadoc classJavadoc = RuntimeJavadoc.getJavadoc(cl);
return classJavadoc.getRecordComponents().stream()
.collect(Collectors.toMap(ParamJavadoc::getName, record -> formatter.format(record.getComment())));
}

/**
* Gets method javadoc description.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ Schema calculateSchema(Components components, ParameterInfo parameterInfo, Reque
Type type = ReturnTypeParser.getType(methodParameter);
if (type instanceof Class && !((Class<?>) type).isEnum() && optionalWebConversionServiceProvider.isPresent()) {
WebConversionServiceProvider webConversionServiceProvider = optionalWebConversionServiceProvider.get();
if (!MethodParameterPojoExtractor.isSwaggerPrimitiveType((Class) type) && methodParameter.getParameterType().getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class) == null){
if (!MethodParameterPojoExtractor.isSwaggerPrimitiveType((Class) type) && methodParameter.getParameterType().getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class) == null) {
Class<?> springConvertedType = webConversionServiceProvider.getSpringConvertedType(methodParameter.getParameterType());
if (!(String.class.equals(springConvertedType) && ((Class<?>) type).isEnum()))
type = springConvertedType;
Expand Down Expand Up @@ -727,17 +727,28 @@ public boolean isRequestBodyPresent(ParameterInfo parameterInfo) {
String getParamJavadoc(JavadocProvider javadocProvider, MethodParameter methodParameter) {
String pName = methodParameter.getParameterName();
DelegatingMethodParameter delegatingMethodParameter = (DelegatingMethodParameter) methodParameter;
final String paramJavadocDescription;
if (delegatingMethodParameter.isParameterObject()) {
String fieldName;
if (StringUtils.isNotEmpty(pName) && pName.contains(DOT))
fieldName = StringUtils.substringAfterLast(pName, DOT);
else fieldName = pName;
Field field = FieldUtils.getDeclaredField(((DelegatingMethodParameter) methodParameter).getExecutable().getDeclaringClass(), fieldName, true);
paramJavadocDescription = javadocProvider.getFieldJavadoc(field);
if (!delegatingMethodParameter.isParameterObject()) {
return javadocProvider.getParamJavadoc(methodParameter.getMethod(), pName);
}
String fieldName;
if (StringUtils.isNotEmpty(pName) && pName.contains(DOT))
fieldName = StringUtils.substringAfterLast(pName, DOT);
else fieldName = pName;

String paramJavadocDescription = null;
Class cls = ((DelegatingMethodParameter) methodParameter).getExecutable().getDeclaringClass();
if (cls.getSuperclass() != null && cls.isRecord()) {
Map<String, String> recordParamMap = javadocProvider.getRecordClassParamJavadoc(cls);
if (recordParamMap.containsKey(fieldName)) {
paramJavadocDescription = recordParamMap.get(fieldName);
}
}

Field field = FieldUtils.getDeclaredField(cls, fieldName, true);
String fieldJavadoc = javadocProvider.getFieldJavadoc(field);
if (StringUtils.isNotBlank(fieldJavadoc)) {
paramJavadocDescription = fieldJavadoc;
}
else
paramJavadocDescription = javadocProvider.getParamJavadoc(methodParameter.getMethod(), pName);
return paramJavadocDescription;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package test.org.springdoc.api.app169;

import org.springdoc.core.annotations.ParameterObject;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("record")
public class RecordController {
@GetMapping
public SimpleOuterClass index(@ParameterObject SimpleOuterClass filter) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package test.org.springdoc.api.app169;

/**
* simple inner class
*
* @param name the boolean name
* @param maxNumber the max number
*/
public record SimpleInnerClass(Boolean name, Integer maxNumber) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package test.org.springdoc.api.app169;

/**
* simple outer class
*
* @param name the name of the outer class
* @param simpleInnerClass the inner class
*/
public record SimpleOuterClass(String name, SimpleInnerClass simpleInnerClass) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
*
* * Copyright 2019-2023 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * https://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/

package test.org.springdoc.api.app169;

import test.org.springdoc.api.AbstractSpringDocTest;

import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* The type Spring doc app 169 test.
*/
public class SpringDocApp169Test extends AbstractSpringDocTest {

/**
* The type Spring doc test app.
*/
@SpringBootApplication
static class SpringDocTestApp {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"openapi": "3.0.1",
"info": {
"title": "OpenAPI definition",
"version": "v0"
},
"servers": [
{
"url": "http://localhost",
"description": "Generated server url"
}
],
"paths": {
"/record": {
"get": {
"tags": [
"record-controller"
],
"operationId": "index",
"parameters": [
{
"name": "name",
"in": "query",
"description": "the name of the outer class",
"required": false,
"schema": {
"type": "string"
}
},
{
"name": "simpleInnerClass.name",
"in": "query",
"description": "the boolean name",
"required": false,
"schema": {
"type": "boolean"
}
},
{
"name": "simpleInnerClass.maxNumber",
"in": "query",
"description": "the max number",
"required": false,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/SimpleOuterClass"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"SimpleInnerClass": {
"type": "object",
"properties": {
"name": {
"type": "boolean",
"description": "the boolean name"
},
"maxNumber": {
"type": "integer",
"description": "the max number",
"format": "int32"
}
},
"description": "simple inner class"
},
"SimpleOuterClass": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the name of the outer class"
},
"simpleInnerClass": {
"$ref": "#/components/schemas/SimpleInnerClass"
}
},
"description": "simple outer class"
}
}
}
}

0 comments on commit d25f9dd

Please sign in to comment.