{"id":21457781,"url":"https://github.com/remal-gradle-plugins/classes-relocation","last_synced_at":"2025-10-29T21:36:10.239Z","repository":{"id":262892307,"uuid":"888693061","full_name":"remal-gradle-plugins/classes-relocation","owner":"remal-gradle-plugins","description":"This Gradle plugin creates a fat JAR for your Java application by bundling and relocating specified dependencies. It helps to prevent dependency conflicts and ensures consistent application behavior by isolating these dependencies from downstream projects.","archived":false,"fork":false,"pushed_at":"2025-03-15T05:49:59.000Z","size":642,"stargazers_count":0,"open_issues_count":6,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-03-15T06:29:09.773Z","etag":null,"topics":["fat-jar","fatjar","gradle","gradle-plugin","plugin","relocation","shadow","uber-jar"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/remal-gradle-plugins.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-14T20:54:07.000Z","updated_at":"2025-03-15T05:50:01.000Z","dependencies_parsed_at":"2024-11-14T21:35:02.079Z","dependency_job_id":"8c64a6cc-6eb6-4659-b1c6-f7071c708117","html_url":"https://github.com/remal-gradle-plugins/classes-relocation","commit_stats":null,"previous_names":["remal-gradle-plugins/classes-relocation"],"tags_count":6,"template":false,"template_full_name":"remal-gradle-plugins/template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remal-gradle-plugins%2Fclasses-relocation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remal-gradle-plugins%2Fclasses-relocation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remal-gradle-plugins%2Fclasses-relocation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remal-gradle-plugins%2Fclasses-relocation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/remal-gradle-plugins","download_url":"https://codeload.github.com/remal-gradle-plugins/classes-relocation/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243971193,"owners_count":20376784,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fat-jar","fatjar","gradle","gradle-plugin","plugin","relocation","shadow","uber-jar"],"created_at":"2024-11-23T06:07:00.312Z","updated_at":"2025-10-29T21:36:10.230Z","avatar_url":"https://github.com/remal-gradle-plugins.png","language":"Java","readme":"**Tested on Java LTS versions from \u003c!--property:java-runtime.min-version--\u003e11\u003c!--/property--\u003e to \u003c!--property:java-runtime.max-version--\u003e25\u003c!--/property--\u003e.**\n\n**Tested on Gradle versions from \u003c!--property:gradle-api.min-version--\u003e7.5\u003c!--/property--\u003e to \u003c!--property:gradle-api.max-version--\u003e9.2.0\u003c!--/property--\u003e.**\n\n# `name.remal.classes-relocation` plugin\n\n[![configuration cache: supported from v2.1](https://img.shields.io/static/v1?label=configuration%20cache\u0026message=supported%20from%20v2.1\u0026color=success)](https://docs.gradle.org/current/userguide/configuration_cache.html)\n\nUsage:\n\n\u003c!--plugin-usage:name.remal.classes-relocation--\u003e\n```groovy\nplugins {\n    id 'name.remal.classes-relocation' version '2.1.5'\n}\n```\n\u003c!--/plugin-usage--\u003e\n\n\u0026nbsp;\n\nThis Gradle plugin facilitates the creation of a fat JAR by bundling your Java application with specific dependencies.\nIt relocates these dependencies to a new namespace within the JAR to prevent exposure to and conflicts with downstream projects.\n\nThis plugin is ideal for scenarios where your code relies on specific dependencies,\nbut you need to ensure that these dependencies do not interfere with those in projects that consume your JAR.\n\nBy using this plugin, you can better manage dependency versions,\nleading to more reliable and predictable behavior of your Java applications across different environments.\n\n## Base configuration\n\n```groovy\nclassesRelocation {\n  basePackageForRelocatedClasses = 'your.project.relocated' // specify the base package for relocated dependencies\n}\n\ndependencies {\n  classesRelocation('com.google.guava:guava:XX.X.X-jre') { // relocate Guava with transitive dependencies\n    exclude group: 'com.google.errorprone', module: 'error_prone_annotations' // but do NOT relocate Error Prone annotations\n  }\n}\n```\n\n## Minimization\n\nThis plugin can automatically remove all classes of relocated dependencies that are not used by the project,\nminimizing the result JAR file.\nThe minimization is implemented via extensive bytecode analysis.\n\nThese class members are **always** relocated:\n\n* Static initializer\n  * It means that all initialized static fields will always be kept\n  * See issue [#37](https://github.com/remal-gradle-plugins/classes-relocation/issues/37)\n\nSerialization-related members are relocated if any instance member is relocated:\n\n* `serialVersionUID` static field\n* `writeObject(ObjectOutputStream)` method\n* `readObject(ObjectInputStream)` method\n* `readObjectNoData()` method\n* `writeReplace()` method\n* `readResolve()` method\n\nIf you relocate a dependency that doesn't use reflection (`Class.getMethod()`, `Class.getField()`, etc),\nyou likely don't need to configure minimization.\n\n### Keep class members annotated with configured annotations\n\nAll class members annotated by these annotations will be kept:\n\n\u003c!--iterable-code-property:keepAnnotationInclusionsDefault--\u003e\n* `jakarta.inject.**`\n* `javax.inject.**`\n* `com.fasterxml.jackson.**`\n* `com.google.gson.**`\n* `jakarta.validation.**`\n* `javax.validation.**`\n* `org.hibernate.validator.**`\n\u003c!--/iterable-code-property--\u003e\n\nYou can configure other annotation type patterns:\n\n```groovy\nclassesRelocation {\n  minimize {\n    keepMembersAnnotatedWith('jakarta.inject.**') // all class members annotated with annotations matched to the provided patterns will be kept\n  }\n}\n```\n\n### GraalVM's Reachability Metadata\n\nTo avoid the removal of necessary code, the plugin uses [GraalVM's Reachability Metadata](https://www.graalvm.org/latest/reference-manual/native-image/metadata/):\n\n* `META-INF/native-image/\u003cgroupId\u003e/\u003cartifactId\u003e/reachability-metadata.json` files in the relocated dependencies are processed\n  * only `$.reflection` field is supported\n  * `$.resources` and `$.bundles` fields are NOT supported, so resource relocation can be broken is some cases\n* `reflect-config.json` files from [oracle/graalvm-reachability-metadata](https://github.com/oracle/graalvm-reachability-metadata) are processed\n\n### Full minimization configuration\n\n```groovy\nclassesRelocation {\n  minimize {\n    keepClasses('com.google.common.*') // all classes in the `com.google.common` package will be fully relocated; subpackages (like `com.google.common.base`) will NOT be minimized\n    keepClasses('com.google.common.**') // all classes in the `com.google.common` package in its subpackages (like `com.google.common.base`) will be fully relocated\n\n    keepMembersAnnotatedWith('jakarta.inject.**') // all class members annotated with annotations matched to the provided patterns will be kept\n\n    graalvmReachabilityMetadataVersion = 'x.x.x' // set release of https://github.com/oracle/graalvm-reachability-metadata\n\n    addClassReachabilityConfig { // add GraalVM's Reachability Metadata programmatically\n      className('package.Class') // for `$.reflection[*].type`\n      onReachedClass('other.package.reached.Class') // for `$.reflection[*].condition.typeReached`\n      onReached() // equals to `onReachedClass()` with the same class name as `className()`\n      field('fieldName') // for `$.reflection[*].fields[*].name`\n      fields(['fieldName1', 'fieldName2']) // for `$.reflection[*].fields[*].name`\n      method('methodName', '(Ljava/lang/String)') // for `$.reflection[*].methods[*].name` and `$.reflection[*].methods[*].parameterTypes`; `(Ljava/lang/String)` is a method descriptor (see https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3), return type is OPTIONAL\n      allDeclaredConstructors(true) // for `$.reflection[*].allDeclaredConstructors`\n      allPublicConstructors(true) // for `$.reflection[*].allPublicConstructors`\n      allDeclaredMethods(true) // for `$.reflection[*].allDeclaredMethods`\n      allPublicMethods(true) // for `$.reflection[*].allPublicMethods`\n      allDeclaredFields(true) // for `$.reflection[*].allDeclaredFields`\n      allPublicFields(true) // for `$.reflection[*].allPublicFields`\n      allPermittedSubclasses(true) // for `$.reflection[*].allPermittedSubclasses`\n    }\n\n    addClassReachabilityConfig { /* ... */ } // add more GraalVM's Reachability Metadata\n  }\n}\n```\n\nUsed minimization configuration is stored in the result JAR file.\nSo, if the result JAR file is used as a relocated dependency in another project,\nall kept classes/members will be relocated.\n\n## How the plugin works\n\nThis plugin adds a new action to the [`jar`](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html) task.\nThis action recreates the JAR file relocating dependencies from the `classesRelocation` configuration.\n\nOnly directly used classes will be relocated.\n\nThe result JAR file will be used by\n[`Test`](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/Test.html),\n[`PluginUnderTestMetadata`](https://docs.gradle.org/current/javadoc/org/gradle/plugin/devel/tasks/PluginUnderTestMetadata.html),\n[`ValidatePlugins`](https://docs.gradle.org/current/javadoc/org/gradle/plugin/devel/tasks/ValidatePlugins.html),\n[`JacocoReportBase`](https://docs.gradle.org/current/javadoc/org/gradle/testing/jacoco/tasks/JacocoReportBase.html) tasks (instead of `build/classes/main/*` directories).\n\nOther projects in Multi-Project builds will consume the result JAR file\nif the current project is declared as a dependency (the same way it happens by default).\n\nThe result JAR file will be published to Maven repositories (the same way it happens by default).\n\nBy default, the [`jar`](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html) task is not cacheable.\nThis plugin makes this task cacheable.\n\n# Alternatives\n\n## [`com.gradleup.shadow`](https://plugins.gradle.org/plugin/com.gradleup.shadow)\n\nThe classic Gradle plugin for fat-JAR creation.\n\n**Benefits of `name.remal.classes-relocation`**\n\n* Simpler configuration.\n* Other projects in Multi-Project builds will consume the relocated JAR file automatically.\n* Publication of the relocated JAR is configured automatically.\n* Minimization is relatively simple and enabled by default\n\n**Benefits of `com.gradleup.shadow`**\n\n* Used in many projects, so it can be considered more stable and reliable.\n* Can be used not only for classes relocation but for creating fat-JARs.\n* Extendable (be implementing `com.github.jengelman.gradle.plugins.shadow.transformers.Transformer`)\n* More configuration options. For example, a capability of excluding specific files and packages from relocation.\n* Minimization requires tests to be written (by default, classes not used in **test** will be removed)\n  * Code coverage should be very high to work properly\n  * Build will fail if there is a dependency like this: `:prod - main source set` (with relocation) \u003e `:test-utils - main source set` (depends on `:prod`) \u003e `:prod \u003e test source set` (prod's tests depend on `:test-utils`)\n\n# Migration guide\n\n## Version 1.* to 2.*\n\nThe minimum Java version is 11.\n\nThe `name.remal.gradle_plugins.classes_relocation.ClassesRelocationExtension` project extension should be used\ninstead of `name.remal.gradle_plugins.plugins.classes_relocation.ClassesRelocationExtension`.\n\nThe `relocateClasses` configuration is still supported but was deprecated. Use `classesRelocation` instead.\n\nThe `@name.remal.gradle_plugins.api.RelocateClasses` and `@name.remal.gradle_plugins.api.RelocatePackages` annotations are no longer supported.\nIf you need to relocate a dependency of a specific class only (but not of other classes), create a separate module and include it in your build.\n\nThe `excludeFromClassesRelocation` and `excludeFromForcedClassesRelocation` configurations are no longer supported.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremal-gradle-plugins%2Fclasses-relocation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremal-gradle-plugins%2Fclasses-relocation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremal-gradle-plugins%2Fclasses-relocation/lists"}