micronaut-maven-plugin icon indicating copy to clipboard operation
micronaut-maven-plugin copied to clipboard

POC - JAR of JARs

Open alvarosanchez opened this issue 3 years ago • 6 comments

This PR contains a POC that fixes #104:

  • Converts the project into a multi-module Maven build.
  • Provides a new io.micronaut.build:micronaut-entrypoint artifact with a single class (io.micronaut.build.entrypoint.Entrypoint) that is meant to be the Main-Class of the runnable jars.
    • The class loader used is a URLClassLoader that loads dependencies (included in the JAR's libs/ folder) by copying them to the local file system first, since nested JAR URLs aren't supported by URLClassLoader. Ideally, this should be replaced by a custom class loader that is able to read nested JAR URLs.
  • Includes a micronaut-entrypoint-test test application, coming from a vanilla mn create-cli-app, with the following changes to its POM:
    • Copies dependencies to classes/libs so that they end up being inside the JAR.
    • Unpacks micronaut-entrypoint in the classes directory, since it needs to be exploded to be the JAR's main class.
    • Configure the generated JAR's manifest:
      • Class-Path entry contains all the dependencies in the format libs/foo-1.2.3.jar.
      • Main-Class is fixed to io.micronaut.build.entrypoint.Entrypoint.
      • Micronaut-Entrypoint points to the actual main class (io.micronaut.build.entrypoint.test.MainCommand in this case).
    • Ideally, a MOJO should be provided to perform these tasks, so that the user POMs are cleaner.

The generated JAR looks like:

.
├── META-INF
│   ├── MANIFEST.MF
│   ├── maven
│   │   └── ...
│   └── native-image
│       └── ...
├── application.yml
├── io
│   └── micronaut
│       └── build
│           └── entrypoint
│               ├── Entrypoint.class        // Unpacked
│               └── test
│                   └── MainCommand.class.  // The actual main class
├── libs
│   ├── apiguardian-api-1.1.0.jar
│   ├── jackson-annotations-2.11.2.jar
│   ├── jackson-core-2.11.2.jar
│   ├── jackson-databind-2.11.2.jar
│   ├── jackson-datatype-jdk8-2.11.2.jar
│   ├── jackson-datatype-jsr310-2.11.2.jar
│   ├── javax.annotation-api-1.3.2.jar
│   ├── javax.inject-1.jar
│   ├── jsr305-3.0.2.jar
│   ├── junit-jupiter-api-5.7.0.jar
│   ├── junit-jupiter-engine-5.7.0.jar
│   ├── junit-platform-commons-1.7.0.jar
│   ├── junit-platform-engine-1.7.0.jar
│   ├── logback-classic-1.2.3.jar
│   ├── logback-core-1.2.3.jar
│   ├── micronaut-aop-2.3.3.jar
│   ├── micronaut-buffer-netty-2.3.3.jar
│   ├── micronaut-core-2.3.3.jar
│   ├── micronaut-http-2.3.3.jar
│   ├── micronaut-http-client-2.3.3.jar
│   ├── micronaut-http-client-core-2.3.3.jar
│   ├── micronaut-http-netty-2.3.3.jar
│   ├── micronaut-inject-2.3.3.jar
│   ├── micronaut-picocli-3.2.0.jar
│   ├── micronaut-runtime-2.3.3.jar
│   ├── micronaut-test-core-2.3.2.jar
│   ├── micronaut-test-junit5-2.3.2.jar
│   ├── micronaut-validation-2.3.3.jar
│   ├── micronaut-websocket-2.3.3.jar
│   ├── netty-buffer-4.1.59.Final.jar
│   ├── netty-codec-4.1.59.Final.jar
│   ├── netty-codec-http-4.1.59.Final.jar
│   ├── netty-codec-http2-4.1.59.Final.jar
│   ├── netty-codec-socks-4.1.59.Final.jar
│   ├── netty-common-4.1.59.Final.jar
│   ├── netty-handler-4.1.59.Final.jar
│   ├── netty-handler-proxy-4.1.59.Final.jar
│   ├── netty-resolver-4.1.59.Final.jar
│   ├── netty-transport-4.1.59.Final.jar
│   ├── opentest4j-1.2.0.jar
│   ├── picocli-4.6.1.jar
│   ├── reactive-streams-1.0.3.jar
│   ├── rxjava-2.2.10.jar
│   ├── slf4j-api-1.7.26.jar
│   ├── snakeyaml-1.26.jar
│   ├── spotbugs-annotations-4.0.3.jar
│   └── validation-api-2.0.1.Final.jar
└── logback.xml

alvarosanchez avatar Mar 01 '21 12:03 alvarosanchez

Spring's "repackage" goal (in the Spring Boot Maven Plugin), does something similar to this, but as you mentioned above, removes the need for unpack the jar first. https://github.com/spring-projects/spring-boot/tree/v2.5.2/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader

The actual "spring" dependencies on that project are minimal (if any at all, the last I looked)

The resulting package ends up looking like this:

.
├── META-INF
│   ├── MANIFEST.MF
│   ├── ...
│ 
├── BOOT-INF
│   ├── classes
│   │   ├── META-INF
│   │   │   └── rest-dice-parser.kotlin_module
│   │   ├── application.properties
│   │   └── com
│   │       └── example
│   │           └── app
│   │               ├── MyCode.class
│   │               ├── ...
│   └── lib
│       ├── my-deps-1.2.3.jar
│       ├── ...
|
└── org
    └── springframework
        └── boot
            └── loader
                ├── ClassloaderRelatedBits.class
                ├── ...

I've been using this even on non-Spring projects just to avoid using the Shade plugin.

bdemers avatar Jun 28 '21 22:06 bdemers

@bdemers thanks, this was just a POC I did right before leaving the Micronaut team.

Going forward, @melix and @graemerocher should be able to decide in which direction they want to move.

alvarosanchez avatar Jun 30 '21 15:06 alvarosanchez

Can we take inspiration or borrow something from One Jar? The project seems to be dead but works in general. Will be very useful in this case.

shirishpandharikar avatar Feb 07 '22 19:02 shirishpandharikar

FYI, we don't have plans to spend time on this in the short term, the interest by the community seems low.

alvarosanchez avatar Feb 08 '22 08:02 alvarosanchez

SonarCloud Quality Gate failed.    Quality Gate failed

Bug C 3 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot E 2 Security Hotspots
Code Smell A 86 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

sonarqubecloud[bot] avatar Apr 26 '22 10:04 sonarqubecloud[bot]

CLA assistant check
All committers have signed the CLA.

CLAassistant avatar Feb 07 '24 21:02 CLAassistant