springdoc / springdoc-openapi-gradle-plugin

Library for OpenAPI 3 with spring-boot
https://springdoc.org
Apache License 2.0
145 stars 46 forks source link

generateOpenApiDocs fails with Webflux application #10

Closed ghost closed 4 years ago

ghost commented 4 years ago

I am trying to get the springdoc-openapi-gradle-plugin working with the same Webflux application that is used in the Maven-based springdoc-openapi-demos project.

I run the Spring Boot application successfully, but nothing appears at http://localhost:8080/v3/api-docs.

Similarly, when I run the generateOpenApiDocs Gradle task, I get this:

Timeout occurred while trying to connect to http://localhost:8080/v3/api-docs

My project is available here:

https://github.com/dcp65/springdoc-openapi-gradle-demo

Any idea what I'm doing wrong?

RobNE commented 4 years ago

I had similar issues and fixed them by adding the following dependency: implementation("org.springdoc:springdoc-openapi-ui:1.2.33")

kpramesh2212 commented 4 years ago

@dcp65

I am unable to run your application. It seems to throw some exceptions.

But I have attached my sample project here. If you wanted to take a look at how it works.

openapi-demo.zip

ghost commented 4 years ago

Thanks @RobNE. I tried springdoc-openapi-webflux-ui, since I am using Webflux. That didn't work either.

ghost commented 4 years ago

Thanks @kpramesh2212. Your demo worked for me, but it isn't using Webflux, which is what I am trying to do.

ghost commented 4 years ago

Can anyone confirm whether the springdoc-openapi-gradle-plugin supports Webflux?

Here is my build.gradle:

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.2.5.RELEASE'
    id 'com.github.johnrengelman.processes' version '0.5.0'
    id 'org.springdoc.openapi-gradle-plugin' version '1.0.0'
}

group 'org.example'
version '1.0.0'

sourceCompatibility = 11

repositories {  
    mavenCentral()
}

springBoot {
    mainClassName = 'org.springdoc.demo.app3.WebfluxDemoApplication'
}

dependencies {
    implementation "io.swagger.core.v3:swagger-annotations:$swaggerVersion"
    implementation "io.swagger.core.v3:swagger-models:$swaggerVersion"
    implementation 'javax.validation:validation-api:2.0.1.Final'
    implementation 'org.springdoc:springdoc-openapi-core:1.1.49'
    implementation 'org.springdoc:springdoc-openapi-webflux-core:1.2.33'
    implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.2.3'
    implementation "org.springframework.boot:spring-boot-starter-data-mongodb-reactive:$springBootVersion"
    implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
    implementation "org.springframework.data:spring-data-commons:$springBootVersion"
    implementation "org.springframework.data:spring-data-mongodb:$springBootVersion"
    testImplementation 'junit:junit:4.12'
}
kpramesh2212 commented 4 years ago

@dcp65

Could you please do the following

  1. Run gradle clean build

  2. Start your spring boot application manually either via command line or via IDE or use gradle bootRun

  3. Do not run the gradle clean generateOpenApiDocs task

  4. Access your application via http://localhost:8080/v3/api-docs

Could you please paste the output here?

ghost commented 4 years ago

With the builld.gradle configuration above I get the following stack trace:

java.lang.NullPointerException: null
    at org.webjars.WebJarAssetLocator.getFullPathExact(WebJarAssetLocator.java:254)
    at org.springframework.web.servlet.resource.WebJarsResourceResolver.findWebJarResourcePath(WebJarsResourceResolver.java:109)
    at org.springframework.web.servlet.resource.WebJarsResourceResolver.resolveResourceInternal(WebJarsResourceResolver.java:80)
    at org.springframework.web.servlet.resource.AbstractResourceResolver.resolveResource(AbstractResourceResolver.java:46)
    at org.springframework.web.servlet.resource.DefaultResourceResolverChain.resolveResource(DefaultResourceResolverChain.java:75)
    at org.springframework.web.servlet.resource.VersionResourceResolver.resolveResourceInternal(VersionResourceResolver.java:161)
    at org.springframework.web.servlet.resource.AbstractResourceResolver.resolveResource(AbstractResourceResolver.java:46)
    at org.springframework.web.servlet.resource.DefaultResourceResolverChain.resolveResource(DefaultResourceResolverChain.java:75)
    at org.springframework.web.servlet.resource.CachingResourceResolver.resolveResourceInternal(CachingResourceResolver.java:122)
    at org.springframework.web.servlet.resource.AbstractResourceResolver.resolveResource(AbstractResourceResolver.java:46)
    at org.springframework.web.servlet.resource.DefaultResourceResolverChain.resolveResource(DefaultResourceResolverChain.java:75)
    at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.getResource(ResourceHttpRequestHandler.java:560)
    at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:485)
    at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:53)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1639)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:834)
kpramesh2212 commented 4 years ago

@dcp65

I think there is a problem with the spring boot application.

If the server is unable to startup then this gradle plugin wont be able to download the openapi json data.

In order for this plugin to work properly

  1. Your spring boot application should startup successfully

  2. Your spring boot application should expose the open api specification in json format via the url http://localhost:8080/v3/api-doc

ghost commented 4 years ago

@kpramesh2212 The Spring boot application does start up successfully and I am able to make API calls against it.

The stack trace above occurs when I try to hit the http://localhost:8080/v3/api-doc URL.

kpramesh2212 commented 4 years ago

@dcp65

What I ment was the http://localhost:8080/v3/api-doc is not working.

So the plugin basically does the following

  1. It starts up your spring boot application

  2. It then access that url http://localhost:8080/v3/api-doc

  3. Downloads the response (Which basically is the openapi docs)

  4. Writes it to a file openapi.json in your build directory

So the problem with spring webflux application is that it is not exposing anything on url http://localhost:8080/v3/api-doc

ghost commented 4 years ago

I know it's not working. That's why I've logged a bug about it and that's what I said in my initial comment:

I run the Spring Boot application successfully, but nothing appears at http://localhost:8080/v3/api-docs.

kpramesh2212 commented 4 years ago

@dcp65

Its something to do with the springdoc webflux api

Can you please check with the core spring doc team they might be able to help you

Meanwhile I try to write a simple spring webflux application to see whats the story.

ghost commented 4 years ago

@kpramesh2212 OK. Thanks.

The only thing is, my application is lifted from the springdoc-openapi-demos, where the OpenAPI endpoint works perfectly with Webflux.

That demo uses Maven; I just wanted to get it working with Gradle. I can't help feeling this has something to do with my Gradle configuration.

kpramesh2212 commented 4 years ago

@dcp65

Ahhhh I am really sorry I didnt really know you cloned springdoc example and you where trying to gradalize it

Anyways your last message helped

Its your gradle file. Please use the below gradle file

Name the file as build.gradle.kts

plugins {
    `java`
    id("org.springframework.boot") version "2.2.5.RELEASE"
    id("io.spring.dependency-management") version "1.0.9.RELEASE"
    id("com.github.johnrengelman.processes") version "0.5.0"
    id("org.springdoc.openapi-gradle-plugin") version "1.0.0"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
    implementation(group = "org.springdoc", name = "springdoc-openapi-webflux-ui", version = "1.2.33")
    compileOnly("org.projectlombok:lombok")
    annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
    annotationProcessor("org.projectlombok:lombok")
    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
    }
    testImplementation("io.projectreactor:reactor-test")
}

tasks.withType<Test> {
    useJUnitPlatform()
}

Let me know how you get on.

ghost commented 4 years ago

Got it! Just couple of tweaks to the build.gradle.

Working version available here:

https://github.com/dcp65/springdoc-openapi-gradle-demo

Thanks @kpramesh2212