Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cyclic gradle task dependency if build configured to include openapi specification file in the build artifact #28

Closed
tbadgu opened this issue Jul 28, 2020 · 15 comments · Fixed by #68

Comments

@tbadgu
Copy link

tbadgu commented Jul 28, 2020

Gradle build file has "$buildDir/docs" path where the spec file will be generated by the plugin configured to be included into build artifact as follows:

openApi {
	apiDocsUrl.set("http://localhost:8080/v3/api-docs")
	outputDir.set(file("$buildDir/docs"))
}

sourceSets {
	main {
		output.dir(builtBy: 'generateOpenApiDocs', '$buildDir/docs')
	}
}

But since forkedSpringBootRun task has a dependency on bootJar task there is no clean way we can incorporate the openapi specification file into the build artifact due to cyclic dependency.

Circular dependency between the following tasks:

:bootJar
+--- :classes
|    \--- :generateOpenApiDocs
|         \--- :forkedSpringBootRun
|              \--- :bootJar (*)
\--- :generateOpenApiDocs (*)

Is there any way this can be achieved?
Please let me know if anymore details are required.

@tbadgu
Copy link
Author

tbadgu commented Jul 28, 2020

@bnasslahsen @kpramesh2212 @zendern Please let me know if you were able to achieve something similar.

@zendern
Copy link
Contributor

zendern commented Jul 28, 2020

@tbadgu So just to make sure i understand you want to be able to

  1. use generateOpenApiDocs to generate and output the openapi file to $buildDir/docs
  2. include that in the final artifact spring boot jar that is produced

Out of curiosity, what is the use case for including it in the artifact directly?? You can access it via the spring boot app at /v3/api-docs (https://springdoc.org/springdoc-properties.html)

@tbadgu
Copy link
Author

tbadgu commented Jul 28, 2020

@zendern Than you for your prompt response.

Use case for the spec file to be included in the build artifact is so that i can use it with atlassian open api request validator for request/response validations based on the specs.

Gradle dependency: com.atlassian.oai:swagger-request-validator-springmvc:2.10.1

Code snippet for configuring the validator:

@Configuration
@EnableWebMvc
@Profile("!generateSpec")
public class OpenApiValidatorConfig implements WebMvcConfigurer {
    private final OpenApiValidationInterceptor validationInterceptor;

    public OpenApiValidatorConfig() throws IOException {
        final EncodedResource specResource = new EncodedResource(
                new ClassPathResource("openapi.json"),
                "UTF-8");
        this.validationInterceptor = new OpenApiValidationInterceptor(specResource);
    }

    @Bean
    public Filter validationFilter() {
        return new OpenApiValidationFilter(
                true,
                true
        );
    }

    @Override
    public void addInterceptors(final InterceptorRegistry registry) {
        registry.addInterceptor(validationInterceptor);
    }
}

@zendern
Copy link
Contributor

zendern commented Jul 29, 2020

@tbadgu Idk if i have a good answer for you. Since this plugin relies on the app being up Im not sure how to remove that dependency exactly.

But I have probably what you could at best call a hack around the problem.

  1. I tested using this demo app https://github.com/springdoc/springdoc-openapi-demos/tree/master/springdoc-openapi-spring-boot-2-webmvc
  2. And then added this to the end of the gradle file
String rebuildDir = "${project.buildDir}/rebuild"
task addOpenApiDocsToBootJar{
	doLast {
		// Unzip the bootjar for fiddling
		copy {
			from(zipTree(project.bootJar.archivePath))
			into(rebuildDir)
		}
                //Adds openapi.json at the same level as application.yml for example
		copy {
			from("${project.buildDir}/docs")
			into("${rebuildDir}/BOOT-INF/classes")
		}
	}
}
task repackageBootJar(type: Zip) {
	from rebuildDir
	//Jar inside of jars cant be compressed so remove compression
	entryCompression ZipEntryCompression.STORED
	//Use the same name and output directory as the original artifact
	archiveName project.bootJar.archiveName
	destinationDir(file("${project.buildDir}/libs"))
}

addOpenApiDocsToBootJar.finalizedBy repackageBootJar

And that allows me to run something like so
gradle clean generateOpenApiDocs addOpenApiDocsToBootJar

And what it does is it generates the normal bootJar, the normal open api does, then expands the bootJar that was created, copies over the openapi.json file to the expanded bootJar location and then repackages it all back up into a jar file that is something that can be started and run.

Not ideal but might be the best workaround option for now ¯_(ツ)_/¯


As for thoughts on the plugin maybe there is some sort of alias/copy of the original bootJar task and then we can call it openApiBootJar or something and it will not interfere with the original. I'd have to do more digging to figure that one out.

@josefhoppe
Copy link

Could you use the bootRun gradle task instead? I noticed that it doesn't depend on bootJar, so it should be fine for all use cases here. It just starts the server, I'm pretty sure it only depends on compileJava.

I am not an expert on gradle however and I wasn't able to quickly find a way to do that with gradle, so that might not be possible.

Since you asked for use cases:

I want to use the json file to generate API classes for my angular frontend (see https://www.npmjs.com/package/ng-openapi-gen if you want to know more). So this means I would like to:

  1. compile the java classes
  2. generate the openapi.json
  3. run npm run build which reads the openapi.json
  4. Package the jar file, including the compiled angular app to the static directory inside the final jar

@kpramesh2212
Copy link
Contributor

@josefhoppe

Yup I have written a proposal to use bootRun task. Hopefully we will try an release a new version once the proposal goes through.

@tngwoerleij
Copy link

Using

id 'org.springframework.boot' version '2.4.2'
id 'org.springdoc.openapi-gradle-plugin' version '1.3.0'

I could not get the suggested hack to work. This is caused by the JAR created by bootJar being an invalid ZIP file

$ unzip -t my.jar 
Archive:  my.jar 
warning [my.jar]:  9141 extra bytes at beginning or within zipfile
  (attempting to process anyway)

$ hexedit my.jar
00000000   23 21 2F 62  69 6E 2F 62  61 73 68 0A  23 0A 23 20  #!/bin/bash.#.#
00000010   20 20 20 2E  20 20 20 5F  5F 5F 5F 20  20 20 20 20     .   ____
00000020   20 20 20 20  20 5F 20 20  20 20 20 20  20 20 20 20       _
00000030   20 20 5F 5F  20 5F 20 5F  0A 23 20 20  20 2F 5C 5C    __ _ _.#   /\\
00000040   20 2F 20 5F  5F 5F 27 5F  20 5F 5F 20  5F 20 5F 28   / ___'_ __ _ _(
00000050   5F 29 5F 20  5F 5F 20 20  5F 5F 20 5F  20 5C 20 5C  _)_ __  __ _ \ \
00000060   20 5C 20 5C  0A 23 20 20  28 20 28 20  29 5C 5F 5F   \ \.#  ( ( )\__
00000070   5F 20 7C 20  27 5F 20 7C  20 27 5F 7C  20 7C 20 27  _ | '_ | '_| | '
00000080   5F 20 5C 2F  20 5F 60 20  7C 20 5C 20  5C 20 5C 20  _ \/ _` | \ \ \
00000090   5C 0A 23 20  20 20 5C 5C  2F 20 20 5F  5F 5F 29 7C  \.#   \\/  ___)|
000000A0   20 7C 5F 29  7C 20 7C 20  7C 20 7C 20  7C 20 7C 7C   |_)| | | | | ||
000000B0   20 28 5F 7C  20 7C 20 20  29 20 29 20  29 20 29 0A   (_| |  ) ) ) ).
000000C0   23 20 20 20  20 27 20 20  7C 5F 5F 5F  5F 7C 20 2E  #    '  |____| .
000000D0   5F 5F 7C 5F  7C 20 7C 5F  7C 5F 7C 20  7C 5F 5C 5F  __|_| |_|_| |_\_
000000E0   5F 2C 20 7C  20 2F 20 2F  20 2F 20 2F  0A 23 20 20  _, | / / / /.#
000000F0   20 3D 3D 3D  3D 3D 3D 3D  3D 3D 7C 5F  7C 3D 3D 3D   =========|_|===
00000100   3D 3D 3D 3D  3D 3D 3D 3D  3D 3D 3D 7C  5F 5F 5F 2F  ===========|___/
00000110   3D 2F 5F 2F  5F 2F 5F 2F  0A 23 20 20  20 3A 3A 20  =/_/_/_/.#   ::
00000120   53 70 72 69  6E 67 20 42  6F 6F 74 20  53 74 61 72  Spring Boot Star
00000130   74 75 70 20  53 63 72 69  70 74 20 3A  3A 0A 23 0A  tup Script ::.#.
00000140   0A 23 23 23  20 42 45 47  49 4E 20 49  4E 49 54 20  .### BEGIN INIT

Which causes Gradle's zipTree() (using Ant's org.apache.tools.zip.ZipFile internally) to treat the archive as empty. We have decided to move forward without automatically creating the OpenAPI specification and derived client classes during the build process for now.

@rvplauborg
Copy link

@josefhoppe

Yup I have written a proposal to use bootRun task. Hopefully we will try an release a new version once the proposal goes through.

What is the status, is there any further progress on this?

@afmjr
Copy link

afmjr commented Jan 25, 2022

Hi,

What is the status of the proposal?
Any plans to merge the PR #68?

It is a big issue for us, and I would prefer not to fork this project.

@bnasslahsen
Copy link
Contributor

@afmjr,

By the end of this week. A new release, will be planned.

@afmjr
Copy link

afmjr commented Jan 26, 2022

@afmjr,

By the end of this week. A new release, will be planned.

@bnasslahsen Thanks for the reply. Is there anywhere I can follow the planned release content?

@bnasslahsen
Copy link
Contributor

@afmjr,

You subscribe to github notifications...
When the release will be done you will recieve an email.

@afmjr
Copy link

afmjr commented Jan 30, 2022

Hi again @bnasslahsen.
Do you already know if merge of PR #68 will be included in next release?

@bnasslahsen
Copy link
Contributor

bnasslahsen commented Jan 31, 2022

@afmjr,

The resolution of this ticket is not yet complete.
The PR is only compatible Java 11.

We wait for the gradle-execfork-plugin release that fixes this bug psxpaul/gradle-execfork-plugin#40.

@bnasslahsen bnasslahsen reopened this Jan 31, 2022
@afmjr
Copy link

afmjr commented Mar 29, 2022

Hello @bnasslahsen, it's me again :-D
Seems like the gradle-execfork-plugin fix was released.
Any plans to release a new version?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants