Skip to content

Commit e4f5a0d

Browse files
author
bnasslahsen
committed
PR#355 merge
1 parent 6b03cc8 commit e4f5a0d

File tree

20 files changed

+283
-52
lines changed

20 files changed

+283
-52
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/core/AbstractResponseBuilder.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,12 @@ public abstract class AbstractResponseBuilder {
3939

4040
private final OperationBuilder operationBuilder;
4141

42-
protected AbstractResponseBuilder(OperationBuilder operationBuilder) {
42+
private final List<ReturnTypeParser> returnTypeParsers;
43+
44+
protected AbstractResponseBuilder(OperationBuilder operationBuilder, List<ReturnTypeParser> returnTypeParsers) {
4345
super();
4446
this.operationBuilder = operationBuilder;
47+
this.returnTypeParsers = returnTypeParsers;
4548
}
4649

4750
public ApiResponses build(Components components, HandlerMethod handlerMethod, Operation operation,
@@ -203,7 +206,7 @@ private Set<io.swagger.v3.oas.annotations.responses.ApiResponse> getApiResponses
203206

204207
private Content buildContent(Components components, Method method, String[] methodProduces, JsonView jsonView) {
205208
Content content = new Content();
206-
Type returnType = method.getGenericReturnType();
209+
Type returnType = getReturnType(method);
207210
if (isVoid(returnType)) {
208211
// if void, no content
209212
content = null;
@@ -219,6 +222,19 @@ private Content buildContent(Components components, Method method, String[] meth
219222
return content;
220223
}
221224

225+
private Type getReturnType(Method method) {
226+
Type returnType = Object.class;
227+
for (ReturnTypeParser returnTypeParser: returnTypeParsers) {
228+
if (returnType.getTypeName().equals(Object.class.getTypeName())) {
229+
returnType = returnTypeParser.getReturnType(method);
230+
} else {
231+
break;
232+
}
233+
}
234+
235+
return returnType;
236+
}
237+
222238
private Schema<?> calculateSchema(Components components, Type returnType, JsonView jsonView) {
223239
Schema<?> schemaN = null;
224240
if (isVoid(returnType)) {

springdoc-openapi-common/src/main/java/org/springdoc/core/OpenAPIBuilder.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,11 @@
2727
import org.springframework.web.bind.annotation.RestController;
2828
import org.springframework.web.method.HandlerMethod;
2929

30-
import java.util.ArrayList;
31-
import java.util.HashMap;
32-
import java.util.HashSet;
33-
import java.util.List;
34-
import java.util.Locale;
35-
import java.util.Map;
36-
import java.util.Optional;
37-
import java.util.Set;
30+
import java.util.*;
3831
import java.util.stream.Collectors;
3932
import java.util.stream.Stream;
4033

41-
import static org.springdoc.core.Constants.DEFAULT_SERVER_DESCRIPTION;
42-
import static org.springdoc.core.Constants.DEFAULT_TITLE;
43-
import static org.springdoc.core.Constants.DEFAULT_VERSION;
34+
import static org.springdoc.core.Constants.*;
4435

4536
public class OpenAPIBuilder {
4637

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.springdoc.core;
2+
3+
import java.lang.reflect.Method;
4+
import java.lang.reflect.Type;
5+
6+
interface ReturnTypeParser {
7+
default Type getReturnType(Method method) {
8+
return method.getGenericReturnType();
9+
}
10+
}
11+
12+
class GenericReturnTypeParser implements ReturnTypeParser{}

springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ public SecurityParser securityParser(PropertyResolverUtils propertyResolverUtils
7979
return new SecurityParser(propertyResolverUtils);
8080
}
8181

82+
@Bean
83+
public GenericReturnTypeParser genericReturnTypeParser() {
84+
return new GenericReturnTypeParser();
85+
}
86+
8287
static class ConditionOnCacheOrGroupedOpenApi extends AnyNestedCondition {
8388

8489
ConditionOnCacheOrGroupedOpenApi() {

springdoc-openapi-kotlin/pom.xml

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23
<modelVersion>4.0.0</modelVersion>
34
<artifactId>springdoc-openapi-kotlin</artifactId>
45
<name>${project.artifactId}</name>
@@ -20,11 +21,53 @@
2021
<version>${kotlin.version}</version>
2122
<scope>provided</scope>
2223
</dependency>
24+
<dependency>
25+
<groupId>org.jetbrains.kotlinx</groupId>
26+
<artifactId>kotlinx-coroutines-reactor</artifactId>
27+
<version>${kotlin-coroutines.version}</version>
28+
<scope>provided</scope>
29+
</dependency>
2330
<dependency>
2431
<groupId>org.springdoc</groupId>
2532
<artifactId>springdoc-openapi-webflux-core</artifactId>
2633
<version>${project.version}</version>
2734
<scope>test</scope>
2835
</dependency>
2936
</dependencies>
37+
38+
<build>
39+
<plugins>
40+
<plugin>
41+
<artifactId>kotlin-maven-plugin</artifactId>
42+
<groupId>org.jetbrains.kotlin</groupId>
43+
<version>${kotlin.version}</version>
44+
<executions>
45+
<execution>
46+
<id>compile</id>
47+
<goals>
48+
<goal>compile</goal>
49+
</goals>
50+
<configuration>
51+
<sourceDirs>
52+
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
53+
<sourceDir>${project.basedir}/src/main/java</sourceDir>
54+
</sourceDirs>
55+
</configuration>
56+
</execution>
57+
<execution>
58+
<id>test-compile</id>
59+
<goals>
60+
<goal>test-compile</goal>
61+
</goals>
62+
<configuration>
63+
<sourceDirs>
64+
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
65+
<sourceDir>${project.basedir}/src/test/java</sourceDir>
66+
</sourceDirs>
67+
</configuration>
68+
</execution>
69+
</executions>
70+
</plugin>
71+
</plugins>
72+
</build>
3073
</project>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.springdoc.core;
2+
3+
import kotlin.coroutines.Continuation;
4+
5+
import java.lang.reflect.*;
6+
import java.util.Arrays;
7+
import java.util.Optional;
8+
9+
public class KotlinCoroutinesReturnTypeParser implements ReturnTypeParser {
10+
11+
@Override
12+
public Type getReturnType(Method method) {
13+
Type returnType = Object.class;
14+
Optional<Parameter> continuationParameter = Arrays.stream(method.getParameters())
15+
.filter((parameter) -> parameter.getType().getCanonicalName().equals(Continuation.class.getCanonicalName()))
16+
.findFirst();
17+
if (continuationParameter.isPresent()) {
18+
Type continuationType = continuationParameter.get().getParameterizedType();
19+
if (continuationType instanceof ParameterizedType) {
20+
Type actualTypeArguments = ((ParameterizedType) continuationType).getActualTypeArguments()[0];
21+
if (actualTypeArguments instanceof WildcardType) {
22+
returnType = ((WildcardType) actualTypeArguments).getLowerBounds()[0];
23+
}
24+
}
25+
}
26+
return returnType;
27+
}
28+
}

springdoc-openapi-kotlin/src/main/java/org/springdoc/core/SpringDocKotlinConfiguration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,10 @@ KotlinCoroutinesRequestBuilder kotlinCoroutinesRequestBuilder(AbstractParameterB
2424
operationBuilder, operationCustomizers, parameterCustomizers);
2525
}
2626

27+
@Bean
28+
KotlinCoroutinesReturnTypeParser kotlinCoroutinesReturnTypeParser() {
29+
return new KotlinCoroutinesReturnTypeParser();
30+
}
31+
2732

2833
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package test.org.springdoc.api
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper
4+
import org.junit.Assert.assertEquals
5+
import org.junit.Test
6+
import org.junit.runner.RunWith
7+
import org.springdoc.core.Constants
8+
import org.springframework.beans.factory.annotation.Autowired
9+
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest
10+
import org.springframework.test.context.ActiveProfiles
11+
import org.springframework.test.context.junit4.SpringRunner
12+
import org.springframework.test.web.reactive.server.WebTestClient
13+
import java.nio.file.Files
14+
import java.nio.file.Paths
15+
16+
@RunWith(SpringRunner::class)
17+
@WebFluxTest
18+
@ActiveProfiles("test")
19+
abstract class AbstractKotlinSpringDocTest {
20+
21+
@Autowired
22+
private val webTestClient: WebTestClient? = null
23+
24+
@Autowired
25+
private val objectMapper: ObjectMapper? = null
26+
27+
@Test
28+
@Throws(Exception::class)
29+
fun testApp() {
30+
val getResult = webTestClient!!.get().uri(Constants.DEFAULT_API_DOCS_URL).exchange()
31+
.expectStatus().isOk.expectBody().returnResult()
32+
33+
val result = String(getResult.responseBody!!)
34+
val className = javaClass.simpleName
35+
val testNumber = className.replace("[^0-9]".toRegex(), "")
36+
37+
val path = Paths.get(javaClass.classLoader.getResource("results/app$testNumber.json")!!.toURI())
38+
val fileBytes = Files.readAllBytes(path)
39+
val expected = String(fileBytes)
40+
41+
assertEquals(objectMapper!!.readTree(expected), objectMapper.readTree(result))
42+
}
43+
44+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package test.org.springdoc.api.app2
2+
3+
import org.springframework.boot.autoconfigure.SpringBootApplication
4+
import org.springframework.context.annotation.ComponentScan
5+
import test.org.springdoc.api.AbstractKotlinSpringDocTest
6+
7+
@ComponentScan(basePackages = ["org.springdoc", "test.org.springdoc.api.app2"])
8+
class SpringDocApp2Test : AbstractKotlinSpringDocTest() {
9+
10+
@SpringBootApplication
11+
open class DemoApplication
12+
13+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package test.org.springdoc.api.app2
2+
3+
import kotlinx.coroutines.reactor.mono
4+
import org.springframework.web.bind.annotation.GetMapping
5+
import org.springframework.web.bind.annotation.RequestMapping
6+
import org.springframework.web.bind.annotation.RestController
7+
8+
enum class SystemStatus(val status: String) {
9+
OK("OK")
10+
}
11+
12+
data class SystemStatusResponse(
13+
val status: SystemStatus
14+
)
15+
16+
@RestController
17+
@RequestMapping("/status")
18+
class SystemStatusController {
19+
@GetMapping
20+
suspend fun index() = SystemStatusResponse(SystemStatus.OK)
21+
22+
@GetMapping("/foo")
23+
fun foo() = mono {
24+
SystemStatusResponse(SystemStatus.OK)
25+
}
26+
}

0 commit comments

Comments
 (0)