odpi / egeria

Egeria core
https://egeria-project.org
Apache License 2.0
806 stars 260 forks source link

[Investigate] Difference in dependencies between maven and gradle #6854

Closed mandy-chessell closed 1 year ago

mandy-chessell commented 2 years ago

Is there an existing issue for this?

Current Behavior

Gradle seems to need more dependencies listed in each module than Maven. Most importantly, it needs some of the interface definitions used to build a dependency. Maven just needs the single dependency.

On discussion with @planetf1 we are not sure if this is ok or needs further investigation. This issue is just to record an example.

Expected Behavior

Need to understand if this an inherent difference in the gradle build mechanism or something we can influence.

Steps To Reproduce

Compare the dependencies in the pom.xml and build.gradle files in the governance-program-client module.

Environment

- Egeria:
- OS:
- Java:
- Browser (for UI issues):
- Additional connectors and integration:

Any Further Information?

No response

planetf1 commented 2 years ago

thanks - will add to the list and take a look!

planetf1 commented 2 years ago

Taking the example given, these are the gradle dependenceis (commented out) that don't feature in the maven pom:

    implementation project(':open-metadata-implementation:common-services:ffdc-services')
//    implementation project(':open-metadata-implementation:common-services:gaf-metadata-management:gaf-metadata-api')
    implementation project(':open-metadata-implementation:common-services:gaf-metadata-management:gaf-metadata-client')
//    implementation project(':open-metadata-implementation:common-services:ocf-metadata-management:ocf-metadata-api')
    implementation project(':open-metadata-implementation:common-services:ocf-metadata-management:ocf-metadata-client')
    implementation project(':open-metadata-implementation:frameworks:audit-log-framework')
    implementation project(':open-metadata-implementation:frameworks:open-connector-framework')
    implementation project(':open-metadata-implementation:access-services:governance-program:governance-program-api')
//    implementation 'org.springframework:spring-web'
//    compileOnly 'com.fasterxml.jackson.core:jackson-annotations'

With these removals, the first observed failure is:

  class file for org.springframework.core.ParameterizedTypeReference not found

In maven the transitive chain that needs this dependency seems to be:

[INFO] org.odpi.egeria:governance-program-client:jar:3.12-SNAPSHOT
[INFO] +- org.odpi.egeria:ffdc-services:jar:3.12-SNAPSHOT:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.13.3:compile
[INFO] |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.13.3:compile
[INFO] |  +- org.odpi.egeria:spring-rest-client-connector:jar:3.12-SNAPSHOT:compile
[INFO] |  |  +- org.springframework:spring-web:jar:5.3.22:compile

Some useful articles: https://stackoverflow.com/questions/55389699/gradle-multi-project-transitive-dependency https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation https://discuss.gradle.org/t/transitive-project-dependencies-available-at-compile-to-the-depending-project/23981

It seems the issue here is gradle's attempts to stop transitive dependencies leaking into a consumer's classpath -- intentionally, in order to preserve the API that module offers

With maven this leakage occurs, so a consumer isn't aware of those other implementation dependencies.

planetf1 commented 2 years ago

Requires further analysis - looking at classpath & exploring the 'api' dependency, as well as why spring implementation is exposed, and whether it should be

Similarly for other dependencies in that list

planetf1 commented 1 year ago

To clarify, when using dependencies, those such as 'api' will pull in the specific dependency listed AND make all of it's dependencies available, whilst 'implementation' will pull in the specific dependency ONLY (maven allows more leakage, which is why we need extra dependencies for gradle)

api could make sense to use when a dependency uses types from another dependency for example, but mostly I think implementation is much more explicit

there are compile only/test only variations of these also

I therefore don't think we need any explicit action on this issue - closing.

planetf1 commented 1 year ago

I think we may need to revisit this....

Our current gradle build mostly uses 'implementation' for regular build+runtime dependencies (there are of course many other variations for restricting scope to runtime only, test compile etc)

When we build a module in this way, only the classes in the module itself are exposed to it's consumers ie NOT those of it's dependencies. In many cases this makes sense as it avoids leaking implementation detail to consumers

However in some cases dependencies are/need to be exposed publicly & form part of the interface. We see this when we try and consume a module, and HAVE to add another dependency just to get it to work. That tells us that this other module is needed by all consumers, ie it's implementation forms part of the interface (be it at build or runtime)

We have several choices at this point a) We should question why the other module is needed. What knowledge is needed of that dependency by consumers? Is it reasonable to continue requiring consumers to explicitly depend on that module? If so we can leave as is. To some extent being explicit at least makes others aware of the dependency so they can better manage it. b) After analysis we realise we are accidentally requiring this additional dependency & should do some refactoring c) We WANT to expose this additional dependency to all consumers. We therefore change the scope in our module (the one providing the capability) to 'api' (or a related variant). This can make it easier for consumers to use our libraries.

Within egeria main project itself it probably doesn't matter too much, but for those building connectors, third parties consuming our modules, it may be more relevant in terms of docs/usability

planetf1 commented 1 year ago

I don't think there's any particular action here. Anything to note before we close?

planetf1 commented 1 year ago

will close