Managing common dependencies across plugins - java

I have implemented a springboot application that can be extended by loading plugins into it. The plugins are created by extending from a common interface specified in my library (LibA) and loaded into the springboot application using Java SPI. Because of this, LibA is a dependency to the springboot application.
There are some common libraries (LibB, LibC) that are used by the plugins which are not part of the springboot application.
The current implementation requires each plugin to be a fat jar containing LibA, LibB, LibC and because of this the versions of the libs need to be the same otherwise there will be issues (such as method not found) while loading these plugins.
I would like to have these common libraries as part of the springboot application and have the plugins refer to the versions in the application. Doing this could result in smaller jars and also ensure the consistency of the version of the libraries used by the plugins.
I could specify LibA, LibB and LibC as dependencies of the springboot application and have the plugins remove them from it's jar and things might work but this would still require the versions to be specified in the plugin's build.gradle.
What I want to know is how to have something similar to the way springboot specifies and provides it's dependencies. Other ways to manage this is also appreciated. I'm using gradle as the build tool.
Current
App (LibA), plugins (LibA, LibB, LibC)
What i need
App (LibA, LibB, LibC), plugins (just refer to the versions in app)
I'm unsure if this is the correct channel to post this question, let me know if it's not suitable.

Related

Spring boot: Will a library get dependency from the parent app/service

I am using spring-retry in my spring-boot service, as well as spring-boot library.
I Noticed this scenario to work:
Use spring retry logic in the library, but the spring retry jars are not imported in the library
Use the library in the parent service as a maven dependency.
The parent service imports spring-retry maven jars.
Is is normal for the library code to use the maven jars from the parent app ? and not need to import the jars itself ? My common intuition says it should, as the resulting compilation unit will have the dependencies injected.. but not sure.
Sorry if this is a super naive question, but my searches did not give a good answer (maybe want using the right keywords)
I'm not sure I've got you right, probably this question should be rephrased.
So you say, that there is a "spring-boot library" that uses spring retry logic.
If so, this library has a maven module and it gets compiled into a regular jar, right?
But if so, if it uses classes/interfaces/annotations from spring retry library and doesn't have it on the compile class path how it gets compiled? I believe you do have this spring retry library in the dependencies but just don't notice (try mvn dependency:tree in the spring boot library module to see the dependencies)
Other than that - usually when you develop a library its intended to be reused by different applications, and if it has dependencies on its own, usually it should list them in the project's library pom. Also usually people who develop the library try to minimize the dependencies list of the library itself.
So if pom.xml of the library doesn't list the required dependencies it won't even compile.
Now in runtime, all the dependencies (including transitive of course) should be available to the spring boot application, otherwise the class that uses these dependencies might not load. But other than that, spring, being a runtime framework, doesn't really care how did the dependency find its way into BOOT-INF/lib folder - its expected to work as long as the dependency is there.

Best practice project layout with multiple libraries in Android Studio

I have several projects which share some locally developed libraries; these libraries vary from being fairly static to being flexibly updated as the applications that use them grow.
For debugging/update purposes it is useful to have them as part of my project (when a new library version is released I can test/update the library as necessary if bugs are uncovered while running the main application projects).
For building purposes it's a pain that when rebuilding a project it also rebuilds the (sometimes large) libraries.
From my perspective, it would be ideal if some of the libraries could be set to not rebuild or clean unless it is explicitly done. Or if I could switch them between being JAR/AAR libraries vs. full modules.
At this point I wonder if there is a better way.
So, if you want to include a library (for edit/update purposes) in a project but do not want it rebuilding all the time, is there a way and what is the best practice?
FWIW, the basic structure I currently have is:
MainApp
platform specific code
Library for app (usually the platform independant code specific to the app)
Local Utils lib (can be fairly dynamic, but often goes for days/weeks without changes)
Other Local Utils (fairly static, occasionally updated)
You can make the library as a separate project then install it as a local artifact using maven plugin in the library. Read more at Deploying an Artifact to the Local Cache in Gradle
In your project, you need to add mavenLocal() to the repositories in your root build.gradle:
repositories {
mavenCentral()
mavenLocal()
}
And add the dependencies to your project build.gradle:
dependencies {
...
compile 'com.your.library:x.y.z'
...
}
But if your project is shared in your local network, you need to use Repository management like Artifactory by JFrog or Nexus Repository Manager by Sonatype.

How can I generate multiple OSGi bundles from a single Maven project?

The basic problem is as such: I've got a project that already uses multiple Maven modules for various sub-projects. However, one of the modules (the core module) could itself be split into multiple OSGi bundles when created. This is due to the core module containing several optional dependencies, each of which have isolated Java packages where they're required. For instance, support for JSON input files are optional as they require the optional dependencies from Jackson. The classes that rely on the Jackson dependencies are all isolated to certain json packages within the module. Thus, in theory, I could create a minimal bundle from core that doesn't include the packages that rely on optional dependencies.
Normally, I'd simply split up this module into more Maven modules to make life easier for creating bundles via Felix's maven-bundle-plugin. The problem here is that I still want to create a core JAR for non-OSGi users who don't want to have to include several extra JARs just to use optional functionality (which requires they provide the optional dependencies on the class path as it is). Not only that, but I don't wish to have to split up this module into more modules as it makes development on the project more tedious for the developers as well, especially when we're already splitting up code into proper package-based modules as it is.
The way we were trying to use OSGi already was to make the API module a fragment host (in order to allow it to load a provider bundle without requiring OSGi support), then make the other bundles use said fragment host. This seemed to work well for the smaller modules outside of core, but for core, we wanted to be able to provide multiple bundles from a single module so that optional dependencies wouldn't be required in the bundle itself. As it stands, for plugins, we already have a mechanism for scanning them and ignoring plugins that don't have all the required classes to load them (e.g., if a plugin requires a JPA provider but the JPA API is not available, that plugin isn't loaded). Once we can successfully split up the core module into multiple bundles, I can use declarative services as the plugin method in an OSGi environment (instead of the default class path JAR scanning mechanism in place for normal Java environments), so that isn't an issue.
Is there any way to do all this using Felix's maven-bundle-plugin? Or will I have to use the assembly plugin to copy subsets of the module where bundles can be generated from? Or will I have to resort to writing an Ant script (or Maven plugin) to do this? We've tried using separate Maven modules that simply import the core module as a dependency and generating a bundle from there, but the resultant bundle is always empty regardless of import/export package settings and embed dependencies.
Or, is there a better way to do this? We already use the <optional>true</optional> configuration for the optional dependencies, yet the Felix plugin doesn't seem to care about that and imports all of those dependencies anyways without using the optional attribute.
Well, this is what I'm ending up doing to accomplish this. I'm using the maven-assembly-plugin to copy the binaries I need and filtering out the classes I don't want to include using the <fileSets/> element similar to the <fileset/> element in Ant.
Using the generated directories for each assembly, I'm using the maven-bundle-plugin along with the <buildDirectory/> configuration option to specify where the bundle's class files are located.
It's not ideal, but it's better than writing an Ant script for a Maven project!

Best practices for a "multi plugins" Java web application - Managing common libraries and conflictual versions

I'm new on a web project where we have to develop plugins (called "extensions" in that specific project). The main application runs in a modified Tomcat web server and we have to add our plugins' .jars in a common lib folder. I'm still not very used to the application and how it works, but I'm pretty sure there is a common classloader for the application and all its plugins. All libraries in that lib folder are shared.
My question is how to deal with the plugins' dependencies and potentially conflictual versions, in that environment.
Should we have shared libraries for example some-common-lib-1.3.4 as jars in the lib folder and plugins have to use those versions when they need to use a library?
Or should a plugin contain its own dependencies (using Maven Shade Plugin for example) so different versions of a same dependency are not an issue?
The problem I see with having shared libraries with a specific version to use for all plugins, is about transitive dependencies. If a common library has a dependency to some-transitive-dependency-1.0.0 and we have a specific plugin which requires a new library which itself have a transitive dependency on some-transitive-dependency-2.0.0 then we're screwed... We would then need both some-transitive-dependency-1.0.0 and some-transitive-dependency-2.0.0 in the lib folder and who knows what will happen.
Also, if for one specific plugin we need to update a dependency to a new major version, we may have to update all plugins since that library is shared by all.
Any real world experience with such situation? Any tips?
Since OSGI is not an option, and potentially everyone could create new plugins, the only feasible way to separate them is, as you already suggested, using the shade plugin or some similar technique.
Since you cannot separate classloaders and recompiling all plugins (for which you might not even have the source code) is really not an option and sometimes you might even have non-resolvable conflicts (asm 1.x and 2.x are totally incompatible), you have to use your own "poor-man's OSGI" and use shade.
Note, however, that this does reduce the option of plugins working together or sharing common data not defined in the main application.

Java Dependency Management For Large Projects

I hope I can keep this question specific enough, my team at work is currently debating the best way to manage our dependencies for a huge project (150+ dependencies ~300mb).
We have two main problems
Keeping all the developers dependencies the same so we are compiling against the same files
Ensure the project (once compiled) is comliped against the same dependencies
The two ideas that have been suggested are using a BirJar (all dependencies in one file) and just adding a version number to it and using a shared folder and pointing everyone's machines at the same place.
Or making including all the dependencies in the jar when we compile it (a jar, of jars, of jars) and just have a project that "has no dependencies"
Someone also mentioned setting up an internal version of Ivy and pointing all the code to pull dependencies from there.
What are the best practices regarding massive dependency management?
Why don't you use Maven and its dependency management ?
You can specify each dependency, its particular version and its scope (compile-time, for testing, for deployment etc.). You can provide a master pom.xml (the config file) that specifies these, and developers can override if they need (say, to evaluate new versions).
e.g. I specify a pom.xml that details the particular jars I require and their versions (or range). Dependent jars are determined/downloaded automatically. I can nominate which of these jars are used for compilation vs. deployment etc. If I use a centralised repository such as Nexus I can then build my artefact (e.g. a library) and deploy that into Nexus, and it'll become available for other developers to download in exactly the same manner as 3rd party libs etc.
Incase you dont like/want to follow the Maven project structure...
If you already use Ant, then your best bet is to use Ivy for dependency management.
http://ant.apache.org/ivy/
It provides a rich set of ant tasks for dependency manipulation.
from : Ant dependency management

Categories

Resources