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

Build executable fat jar #69

Closed
wants to merge 1 commit into from

Conversation

ttddyy
Copy link
Contributor

@ttddyy ttddyy commented Oct 21, 2022

Background

When docs-gen is used by the exec-maven-plugin's exec:java goal, there is a problem for System.exit calls.
The exec:java goal execute the docs-gen in the same maven VM. When docs-gen calls System.exit, it halts the maven itself immediately without any maven post processing(showing maven outputs in console).
This is a limitation of exec:java goal because it runs the program on the same maven process.

This is problematic to the docs-gen for error handlings. When docs-gen encounters an error, it should fail the maven process in appropriate way.
If System.exit is not used, even the docs-gen failed in middle, the maven execution continues to the next step rather than stop with failure.

To use System.exit in docs-gen for proper error handlings, we cannot use exec:java goal.

Approach

One approach to solve this problem is to use exec:exec goal. This goal runs the docs-gen in a separate process. Hence, the System.exit does not stop the maven process. However, this approach requires a new set of challenges such as managing the dependent libraries and resolving the location of the executable.

To use exec:exec goal, this PR makes docs-gen artifact a self contained executable jar(fat jar).
Using executable fat jar has several advantages. First, to run the jar, it does not need to solve dependent library files. Another benefit is that the fat jar itself is distributed as a maven dependency, so it could be referenced by a known location(local maven repo).
One disadvantage I can think of is that the jar file is not suitable to be used as a library. Since it shades the all required library, there will be conflicts with application libraries.(Can be avoided by relocating the dependent library packages while shading.) However, the docs-gen is more of an independent jar file, so it should not be used as a library.

Run the fat jar in maven:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <executions>
    <execution>
      <id>generate-observability-docs</id>
      <phase>prepare-package</phase>
      <goals>
        <goal>exec</goal>
      </goals>
      <configuration>
        <executable>java</executable>
        <arguments>
          <argument>-jar</argument>
          <argument>${settings.localRepository}/io/micrometer/micrometer-docs-generator/${micrometer-docs-generator.version}/micrometer-docs-generator-${micrometer-docs-generator.version}.jar</argument>
          <argument>${micrometer-docs-generator.inputPath}</argument>
          <argument>${micrometer-docs-generator.inclusionPattern}</argument>
          <argument>${micrometer-docs-generator.outputPath}</argument>
        </arguments>
      </configuration>
    </execution>
  </executions>
  <dependencies>
    <dependency>
      <groupId>io.micrometer</groupId>
      <artifactId>micrometer-docs-generator</artifactId>
      <version>${micrometer-docs-generator.version}</version>
      <type>jar</type>
      </dependency>
  </dependencies>
</plugin>

Run the fat jar in gradle:

configurations {
  docgen
}

dependencies {
  docgen "io.micrometer:micrometer-docs-generator:$micrometerDocsVersion"
}

task generateObservabilityDocs(type: JavaExec) {
  classpath files(configurations.docgen)
  main 'io.micrometer.docs.DocsGeneratorCommand'
  args inputDir, '.*', outputDir
}

ttddyy added a commit that referenced this pull request Oct 21, 2022
@ttddyy
Copy link
Contributor Author

ttddyy commented Oct 21, 2022

After some experiments, I took a simpler solution - throwing an exception AFTER DocsGeneratorCommand execution by checking the returned code.
Any exceptions thrown In the DocsGeneratorCommand was captured by picocli infrastructure and converted to an exit code.
Exceptions thrown outside of DocsGeneratorCommand will be propagated to the exec:java run and maven could appropriately handle it.

For example, an exception thrown in a logic shows its stacktrace and continues to display the maven error messages as below:

java.lang.IllegalArgumentException: manual exception
	at io.micrometer.docs.spans.SpansDocGenerator.generate(SpansDocGenerator.java:70)
	at io.micrometer.docs.DocsGeneratorCommand.generateSpansDoc(DocsGeneratorCommand.java:123)
	at io.micrometer.docs.DocsGeneratorCommand.run(DocsGeneratorCommand.java:109)
	at picocli.CommandLine.executeUserObject(CommandLine.java:1939)
	at picocli.CommandLine.access$1300(CommandLine.java:145)
	at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2358)
	at picocli.CommandLine$RunLast.handle(CommandLine.java:2352)
	at picocli.CommandLine$RunLast.handle(CommandLine.java:2314)
	at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
	at picocli.CommandLine$RunLast.execute(CommandLine.java:2316)
	at picocli.CommandLine.execute(CommandLine.java:2078)
	at io.micrometer.docs.DocsGeneratorCommand.main(DocsGeneratorCommand.java:83)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:254)
	at java.base/java.lang.Thread.run(Thread.java:833)
[WARNING]
java.lang.RuntimeException: DocsGeneratorCommand failed.
    at io.micrometer.docs.DocsGeneratorCommand.main (DocsGeneratorCommand.java:88)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:254)
    at java.lang.Thread.run (Thread.java:833)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  14.917 s
[INFO] Finished at: 2022-10-21T11:45:31-07:00
[INFO] ------------------------------------------------------------------------

This way, since it doesn't use System.exit, no need to convert to an executable fat jar.

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 this pull request may close these issues.

None yet

1 participant