diff --git a/MAVEN_BEST_PRACTICES.md b/MAVEN_BEST_PRACTICES.md new file mode 100644 index 0000000..40c9ee1 --- /dev/null +++ b/MAVEN_BEST_PRACTICES.md @@ -0,0 +1,482 @@ +# Maven Dependency Management Best Practices + +This guide helps Maven users resolve dependency convergence issues when using authzed-java alongside other libraries, particularly gRPC. + +## Table of Contents +- [Understanding Dependency Convergence](#understanding-dependency-convergence) +- [Recommended Solution: Use dependencyManagement](#recommended-solution-use-dependencymanagement) +- [Option 1: Use gRPC BOM (Recommended)](#option-1-use-grpc-bom-recommended) +- [Option 2: Explicit Version Pinning](#option-2-explicit-version-pinning) +- [Option 3: Exclusions (Last Resort)](#option-3-exclusions-last-resort) +- [Complete Example](#complete-example) +- [References](#references) + +--- + +## Understanding Dependency Convergence + +The Maven Enforcer Plugin's `dependencyConvergence` rule ensures that "dependency versions are the same everywhere in the tree" ([Maven Enforcer Documentation](https://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html)). This prevents runtime classpath conflicts. + +### Common Convergence Errors with authzed-java + +When using authzed-java with other gRPC-based libraries, you may encounter version conflicts for: +- `io.grpc:grpc-api` +- `com.google.protobuf:protobuf-java` +- `com.google.j2objc:j2objc-annotations` +- `com.google.api.grpc:proto-google-common-protos` +- `com.google.code.gson:gson` + +### Why This Happens + +**Gradle vs Maven**: authzed-java is built with Gradle, which automatically resolves conflicts by choosing the newest version. Maven, with the enforcer plugin enabled, requires explicit version alignment. + +--- + +## Recommended Solution: Use dependencyManagement + +Maven's `` section "allows project authors to directly specify the versions of artifacts to be used when they are encountered in transitive dependencies" ([Maven Dependency Mechanism Guide](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)). + +### Benefits +- ✅ Centralizes version control +- ✅ Prevents version conflicts across your entire dependency tree +- ✅ Works for both compile and runtime scopes +- ✅ No need for exclusions scattered throughout your POM +- ✅ Future-proof as dependencies evolve + +--- + +## Option 1: Use gRPC BOM (Recommended) + +The **Bill of Materials (BOM)** pattern provides centralized version management for groups of related dependencies. + +### What is the gRPC BOM? + +The gRPC project provides `io.grpc:grpc-bom` which manages versions for all gRPC modules (`io.grpc:*` artifacts like grpc-api, grpc-protobuf, grpc-stub, etc.). + +**Important**: The gRPC BOM does **not** manage dependencies outside the `io.grpc` group, including: +- `com.google.api.grpc:proto-google-common-protos` +- `com.google.j2objc:j2objc-annotations` +- `com.google.protobuf:protobuf-java` + +For more details, see the [gRPC BOM on Maven Central](https://central.sonatype.com/artifact/io.grpc/grpc-bom). + +### Implementation + +```xml + + + + + + io.grpc + grpc-bom + 1.76.0 + pom + import + + + + + + + + io.grpc + grpc-api + + + + + com.authzed.api + authzed + 1.5.4 + + + +``` + +### How It Works + +1. The `import` directive imports the gRPC BOM's dependency management +2. The BOM defines versions for all gRPC modules (grpc-api, grpc-protobuf, etc.) +3. Your gRPC dependencies don't need explicit versions +4. authzed-java's transitive gRPC dependencies align with the BOM's versions + +### Version Selection and Trade-offs + +**Which gRPC version should you use?** + +- authzed-java 1.5.4 uses gRPC **1.75.0** +- You can import the gRPC BOM at 1.75.0 to match authzed's version +- gRPC minor releases are generally source compatible, but always check the [gRPC Release Notes](https://github.com/grpc/grpc-java/releases) before upgrading to 1.76.0+ + +**Important: What the gRPC BOM Actually Manages**: + +The gRPC BOM **only manages `io.grpc:*` artifacts** (grpc-api, grpc-protobuf, grpc-stub, etc.). It does **not** manage: +- `com.google.api.grpc:proto-google-common-protos` +- `com.google.j2objc:j2objc-annotations` +- `com.google.protobuf:protobuf-java` + +**Version Sources in Your Build**: +``` +Your project +├─ gRPC BOM 1.75.0 (in dependencyManagement) +│ └─ manages io.grpc:* artifacts at 1.75.0 +├─ authzed-java 1.5.4 +│ ├─ uses gRPC 1.75.0 (aligned with BOM) +│ ├─ explicitly declares proto-google-common-protos 2.61.3 (authzed's choice) +│ └─ explicitly declares protobuf-java 4.32.1 +└─ protobuf-java-util 4.32.1 (transitive) + └─ brings j2objc-annotations 2.8 +``` + +**When using the BOM**: The BOM manages gRPC module versions (1.75.0) only. Other dependencies like proto-google-common-protos:2.61.3 come from authzed-java's own POM, not the BOM. + +--- + +## Option 2: Explicit Version Pinning + +If you're not using the gRPC BOM, you can explicitly pin versions in ``. However, **we strongly recommend using the gRPC BOM instead** to ensure compatibility. + +**⚠️ Important**: Only pin the versions of direct dependencies or those causing actual conflicts. Let Maven resolve transitive dependencies when possible to avoid forcing incompatible versions. + +```xml + + + + + io.grpc + grpc-api + 1.75.0 + + + io.grpc + grpc-protobuf + 1.75.0 + + + io.grpc + grpc-stub + 1.75.0 + + + + + com.google.protobuf + protobuf-java + 4.32.1 + + + + + + + + + + com.authzed.api + authzed + 1.5.4 + + + +``` + +### Version Compatibility Notes + +- **authzed-java 1.5.4** explicitly declares: + - gRPC modules at **1.75.0** + - protobuf-java **4.32.1** + - proto-google-common-protos **2.61.3** + +- **gRPC 1.75.0/1.76.0 BOM** manages: + - Only `io.grpc:*` artifacts (grpc-api, grpc-protobuf, grpc-stub, etc.) + - Does **not** manage proto-google-common-protos or j2objc-annotations + +- **Common dependency versions** in your build: + - proto-google-common-protos **2.61.3** (from authzed-java) + - j2objc-annotations **2.8** (from protobuf-java-util:4.32.1) + - Note: guava brings j2objc-annotations:3.0.0, creating a 2.8 vs 3.0.0 conflict + +**When pinning proto-google-common-protos**: +- Pin to **2.61.3** to match authzed's version (recommended) +- This is authzed's tested version and includes the protos needed by the SDK + +**For j2objc-annotations**: Pin to **2.8** (from protobuf-java-util) to resolve the 2.8 vs 3.0.0 conflict + +--- + +## Option 3: Exclusions (Last Resort) + +If you cannot use `dependencyManagement`, use exclusions. **This approach is NOT recommended** as it requires manual maintenance and doesn't scale well. + +```xml + + com.authzed.api + authzed + 1.5.4 + + + + com.google.j2objc + j2objc-annotations + + + + com.google.api.grpc + proto-google-common-protos + + + + + + + + com.google.j2objc + j2objc-annotations + 2.8 + + + + com.google.api.grpc + proto-google-common-protos + 2.61.3 + +``` + +### Why Exclusions Are Problematic +- ❌ Requires you to know all transitive dependencies +- ❌ Breaks when authzed-java updates its dependencies +- ❌ Doesn't prevent other conflicts in your dependency tree +- ❌ Manual maintenance burden + +--- + +## Complete Example + +Here's a complete POM demonstrating best practices: + +```xml + + + 4.0.0 + + com.example + my-authzed-app + 1.0.0 + + + 11 + 11 + + 1.75.0 + + + + + + + io.grpc + grpc-bom + ${grpc.version} + pom + import + + + + + com.google.j2objc + j2objc-annotations + 2.8 + + + + + + + + com.authzed.api + authzed + 1.5.4 + + + + + io.grpc + grpc-netty-shaded + + + io.grpc + grpc-services + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.6.2 + + + enforce-dependency-convergence + + enforce + + + + + + + + + + + + +``` + +--- + +## Troubleshooting + +### Viewing Your Dependency Tree + +```bash +mvn dependency:tree +``` + +### Finding Convergence Issues + +```bash +mvn enforcer:enforce +``` + +### Testing Locally + +After changes, verify convergence: + +```bash +mvn clean verify +``` + +### Common Issues + +#### Issue: "Dependency convergence error for io.grpc:grpc-api" +**Solution**: Use the gRPC BOM or pin the version in `` + +#### Issue: "Dependency convergence error for com.google.api.grpc:proto-google-common-protos" +**Cause**: Multiple transitive dependencies may bring different versions; authzed-java declares 2.61.3 +**Solution**: Pin to authzed's tested version in ``: +```xml + + + + com.google.api.grpc + proto-google-common-protos + 2.61.3 + + + +``` +Note: The gRPC BOM does not manage this artifact; use authzed's version for best compatibility. + +#### Issue: "Dependency convergence error for com.google.j2objc:j2objc-annotations" +**Cause**: guava brings 3.0.0, protobuf-java-util brings 2.8 +**Solution**: Add version pinning in ``: +```xml + + com.google.j2objc + j2objc-annotations + 2.8 + +``` +Note: Using 3.0.0 (guava's version) also works but may cause convergence warnings. + +#### Issue: Compilation errors after adding exclusions +**Cause**: You excluded a required dependency +**Solution**: Re-add the excluded artifact as an explicit dependency with the correct version + +--- + +## References + +### Official Documentation + +1. **Maven Dependency Mechanism** + https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html + Official Apache Maven guide on dependency management, transitive dependencies, and the `` section. + +2. **Maven Enforcer Plugin - Dependency Convergence Rule** + https://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html + Official documentation for the dependency convergence rule, including configuration options and resolution strategies. + +3. **gRPC BOM (Bill of Materials)** + https://central.sonatype.com/artifact/io.grpc/grpc-bom + Maven Central repository page for the gRPC BOM artifact with version history and usage examples. + +4. **gRPC Java Examples** + https://github.com/grpc/grpc-java/blob/master/examples/pom.xml + Official gRPC Java examples demonstrating BOM usage in Maven projects. + +### Additional Resources + +5. **Maven BOM Pattern** + https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#bill-of-materials-bom-poms + Explanation of the Bill of Materials pattern and the `import` scope. + +6. **Dependency Convergence Best Practices** + https://rieckpil.de/avoid-runtime-errors-with-maven-dependency-convergence/ + Community guide on avoiding runtime errors through proper dependency convergence. + +7. **Stack Overflow: Solving Maven Dependency Convergence Issues** + https://stackoverflow.com/questions/16100315/solving-maven-dependency-convergence-issues + Community-contributed strategies for resolving convergence problems. + +--- + +## Support + +If you encounter dependency convergence issues not covered by this guide: + +1. Check your dependency tree: `mvn dependency:tree` +2. Review the [authzed-java releases](https://github.com/authzed/authzed-java/releases) for version compatibility notes +3. Open an issue at https://github.com/authzed/authzed-java/issues with: + - Your Maven version + - The complete convergence error output + - Your `pom.xml` dependencies section + - Output of `mvn dependency:tree` + +--- + +## Summary + +**Best Practice Hierarchy:** + +1. ✅ **Use gRPC BOM** - Most reliable, future-proof +2. ✅ **Explicit version pinning in dependencyManagement** - Good for fine-grained control +3. ⚠️ **Exclusions** - Only as a last resort, high maintenance + +**Key Takeaways:** + +- Maven's `` is the recommended solution for version conflicts +- The gRPC BOM simplifies dependency management significantly **for `io.grpc:*` artifacts only** +- The gRPC BOM does **not** manage proto-google-common-protos, j2objc-annotations, or protobuf-java +- authzed-java declares proto-google-common-protos:2.61.3 - use this tested version +- For j2objc-annotations conflicts, pin to 2.8 (from protobuf-java-util) +- Exclusions should be avoided when possible - use version pinning instead +- Test with `mvn enforcer:enforce` after making changes +- Document your version choices for future maintainers + +**What Actually Happens When You Use the gRPC BOM + authzed-java:** + +The BOM manages `io.grpc:*` versions only. Other dependencies come from authzed-java's POM and its transitive dependencies: +- ✅ gRPC modules: Controlled by BOM (1.75.0 or your chosen version) +- ✅ proto-google-common-protos: authzed's 2.61.3 (from authzed-java's POM) +- ⚠️ j2objc-annotations: May need manual pinning to resolve 2.8 (protobuf-java-util) vs 3.0.0 (guava) conflict +- ✅ protobuf-java: authzed's 4.32.1 (from authzed-java's POM) + +This combination is tested and works correctly. diff --git a/README.md b/README.md index 996045b..a101de4 100644 --- a/README.md +++ b/README.md @@ -41,17 +41,17 @@ Most commonly, if you are using [Maven] you can add the following to your pom.xm com.authzed.api authzed - 1.5.0 + 1.5.4 io.grpc grpc-api - 1.72.0 + 1.75.0 io.grpc grpc-stub - 1.72.0 + 1.75.0 ``` @@ -60,9 +60,9 @@ If you are using [Gradle] then add the following to your `build.gradle` file: ```groovy dependencies { - implementation "com.authzed.api:authzed:1.4.1" - implementation 'io.grpc:grpc-api:1.72.0' - implementation 'io.grpc:grpc-stub:1.72.0' + implementation "com.authzed.api:authzed:1.5.4" + implementation 'io.grpc:grpc-api:1.75.0' + implementation 'io.grpc:grpc-stub:1.75.0' } ``` @@ -71,6 +71,66 @@ dependencies { [Maven]: https://maven.apache.org [Gradle]: https://gradle.org/ +#### Maven Dependency Convergence + +If you use Maven's [`maven-enforcer-plugin`](https://maven.apache.org/enforcer/maven-plugin/) with the `dependencyConvergence` rule, you should use Maven's `` section to centralize version control and avoid conflicts. + +**Recommended approach** - Use the [gRPC BOM](https://central.sonatype.com/artifact/io.grpc/grpc-bom): + +```xml + + + + + + io.grpc + grpc-bom + 1.75.0 + pom + import + + + + + com.google.j2objc + j2objc-annotations + 2.8 + + + + + + + com.authzed.api + authzed + 1.5.4 + + + + io.grpc + grpc-api + + + io.grpc + grpc-stub + + +``` + +This approach ensures all gRPC modules use consistent versions across your project. + +**Important notes**: +- The gRPC BOM only manages `io.grpc:*` artifacts; it does not manage `proto-google-common-protos` or `j2objc-annotations` +- authzed-java 1.5.4 uses gRPC 1.75.0 and explicitly declares proto-google-common-protos 2.61.3 +- You may need to pin j2objc-annotations:2.8 if you encounter convergence warnings (this version comes from protobuf-java-util, not the gRPC BOM) +- gRPC minor releases are generally source compatible, but check the [gRPC release notes](https://github.com/grpc/grpc-java/releases) before upgrading + +**For detailed guidance**, including troubleshooting and alternative approaches, see [MAVEN_BEST_PRACTICES.md](MAVEN_BEST_PRACTICES.md). + +**References:** +- [Maven Dependency Management Guide](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html) +- [Maven Enforcer Plugin - Dependency Convergence](https://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html) + ### Initializing a client