How do you manage Hibernate's zillion JAR files - java

For my previous employer I've worked with Hibernate, and now that I'm in a small startup I would like to use it again. However, downloading both the Hibernate core and the Hibernate annotations distributions is rather painful, as it requires putting a lot of JAR files together. Because the JARs are split up into categories such as "required" and "optional" I would assume that every developer ends up with a different contents of his lib folder.
What is the common way to handle this problem? Basically I want to have a formal way to get all the JARs for Hibernate, so that (in theory) I would end up with exactly the same stuff if I would need again for another project next month.
Edit: I know roughly what Maven does, but I was wondering if there was another way to manage this sort of thing.

As Aaron has already mentioned, Maven is an option.
If you want something a bit more flexible you could use Apache Ant with Ivy.
Ivy is a dependency resolution tool which works in a similar way to Maven, you just define what libraries your project needs and it will go off and download all the dependencies for you.

Maybe this is not much of an answer, but I really don't see any problem with Hibernate dependencies. Along with hibernate3.jar, you need to have:
6 required jars, out of which commons-collections, dom4j and slf4j are more often used in other open-source projects
1 of either javassist or CGLIB jars
depending on cache and connection pooling, up to 2 jar files, which are pretty much Hibernate specific
So, at the very worst, you will have a maximum of 10 jars, Hibernate's own jar included. And out of those, only commons-collections, dom4j and slf4j will probably be used by some other library in your project. That is hardly a zillion, it can be managed easily, and surely does not warrant using an "elephant" like Maven.

I use Maven 2 and have it manage my dependencies for me.

One word of caution when considering using Maven or Ivy for managing dependencies is that the quality of the repository directly affects your build experience. If the repo is unavailable or the meta-data for the artifacts (pom.xml or ivy.xml) is incorrect you might not be able to build. Building your own local repository takes some work but is probably worth the effort. Ivy, for example, has an ANT task that will import artifacts from a Maven repository and publish them to you own Ivy repository. Once you have a local copy of the Maven repo, you can adjust the meta-data to fit what ever scheme you see fit to use. Sometimes the latest and greatest release is not in the public repository which can sometimes be an issue.

I assume you use the Hibernate APIs explicitly? Is it an option to use a standard API, let's say JPA, and let a J2EE container manage the implementation for you?
Otherwise, go with Maven or Ivy, depending on your current build system of choice.

Related

How do you resolve several-levels-indirect missing dependency hell in Maven/Gradle?

We have a project which depends on Aspose Words' com.aspose:aspose-words:16.10.0:jdk16.
The POM for aspose-words declares no dependencies, but this turns out to be a lie. It actually uses jai-core, latest version of which is at javax.media:jai-core:1.1.3.
The POM for jai-core, though, also lies - it declares no dependencies, but actually depends on jai-codec, which is at com.sun.media:jai-codec:1.1.3.
Getting these projects to fix things seems impractical. JAI is basically a dead project and Maven Central have no idea who added that POM so there is nobody responsible for fixing the metadata. Aspose refuse to fix things without a test reproducing it, even if you can show them their own code doing it wrong, and even if they fixed it, they would then add their dependency on jai-core:1.1.3, which only fixes half the problem anyway.
If I look at our entire tree of dependencies, this is only one example of the problem. Others are lurking, masked out by other dependency chains coincidentally pulling in the missing dependency. In some cases, we have even reported POM issues to projects, only for them to say that the dependency "isn't real", despite their classes clearly referring to a class in the other library.
I can think of a few equally awkward options:
Create jai-core:1.1.3.1 and aspose-words:16.10.0.1 and fix their POMs to include the missing dependencies, but whoever updates them in the future will have to do the same thing. Plus, any other library I don't know about which happens to depend on jai-core would also have to be updated.
Add a dependency from our own project, even though it really isn't one.
Edit the POM for the versions which are there now to fix the problem directly, only caveat being that people might have cached the wrong one.
So I guess I have two related questions about this:
Is there no proper way to resolve this? It seems like any non-toy project would eventually hit this problem, so there not being an obviously correct way to deal with it is worrying.
Is there a way to stop incorrect dependency metadata getting into the artifact server in the first place? It's getting kind of out of hand, because other devs on the team are adding the dependencies without checking things properly, and then I'm left to clean up their error when something breaks a year later.
Tunaki has already given many good approaches. Let me add the following:
We had to deal with a lot of legacy jars which are some old or strange versions of already existing jars on MavenCentral. We gave them a special kind of version number (like 1.2.3-companyname) and created a POM for them that fitted our purposes. This is - more or less - your first "awkward option". This is what I would go for in your case; additionally, I would define the version in the dependencyManagement, so that Maven dependency mediation will not set it to some other version.
If a new version of your jar comes around, you can check if it still has the same problems (if they did a correct Maven build, they should have all dependencies inside the POM). If so, you need to fix it again.
I wouldn't change poms for already existing versions because it confuses people and may lead to inconsistency problems because Maven will not grab the new POM if an old version is already in the local repository. Adding the dependency to your own project is an option if you have very few projects to manage so that you still see what is going on (a proper comment on the dependencies in the POM could make it clearer).
JAI is optional for Aspose.Words for Java. Aspose.Words for Java uses JAI image encoders and decoders only if they available. And it will work okay without JAI.
The codecs complement standard java ImageIO encoders/decoders. The most notable addition is support of Tiff.
JAI (Java Advanced Imaging) is not usual library. First of all - it is native library. I.e. it has separate distributives for different platforms. It has also "portable" pure-java distributive, but if you want full power of JAI - you should stick to native option.
Another thing: usually you should run installation of JAI native distributive on the host system. I.e. it installed like desktop application, not like usual java library. Again, JAI codec acts not like usual library: if it installed on system - it will plug into ImageIO, irrelevant to classpath.
So, i don't know good way to install JAI using Maven - it is like using Maven to install Skype or any other desktop application. But it is IMHO, I am not great specialist on Maven:)

Best strategy for dealing with optional dependencies

I'm currently in the process of removing the Spring dependency from Flyway. In the future though other types of dependencies might be needed to support a subset of users (such as JBoss VFS support).
Which is the best way to support optional dependencies (optional=true in Maven POM)?
Qualities of the solution would be:
Ease of use for end-users (minimum work required to use functionality if dependency is present)
Ease of use for developers (code dealing with optional dependency should be as readable and as straightforward as possible)
No unnecessary required dependencies (if some end-user don't need this functionality, no need to pull in the dependency)
I think Maven's optional dependency functionality is quite limited.
http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html
Optional dependencies will not get pulled down (as transitive dependencies) by default. However, if your users need to use these optional features the missing dependencies must be explicitly declared, in their POM.
Personally, it's not clear to me how this is helpful to users.... I suppose the optional dependencies in your POM do document which versions your code depends on. Not all users however will read the POM, all they'll see is the "NoClassDef Found" error :-(
My final observation is that this is one of those rare scenarios where a dependency manager like ivy offers more flexibility. Ivy has a concept called "configurations". Module authors can assemble different combinations of dependencies, for example "with-spring" or "without-spring".
There's a choice of:
keep the project in a single module; and use optional dependencies.
split the project into multiple modules; where each module has a (non-optional) dependency on any libraries;
I think the first makes more sense in most cases: users need to figure out their way around fewer artifacts. Typically, they'll have to add fewer new dependencies to their pom. Unless the code to support third-party projects is large, this will help improve maven download times too (fewer round-trips). With the latter approach, you can find yourself in awkward situations where the user has defined their own set of versions, but only for some of the third-party dependencies.
I prefer to see the optional dependencies in the pom (I sometimes look to see which version it's built against). It's true that some people might not look. I think copy-and-pasteable pom snippets on the website is the best solution for that. For example, if you have a page about Spring integration, you could put the relevant pom snippet on that page.
I'd suggest that non-free dependencies (or anything not easily resolvable) be kept in a separate maven module, so that contributors are always able to build the primary artifact. (I had that problem with Quartz, which IIRC has an optional dependency on an Oracle JDBC jar).
Edit: If you're worried about users seeing NoClassDefFoundErrors, it wouldn't do any harm to check that the class can be resolved before trying to use it. For example, you could can an exception, and throw a more meaningful error message pointing the user to documentation. SLF4J is a good example of this.

How to find out which dependencies need to be included?

I'm fairly new to Java/Spring and am trying to put together a simple app which will include some basic CRUD operations and I'd like to use Hibernate for data access.
I'm using Maven as my build tool. My question is: how can I find out which dependencies are required to use Hibernate? For example, I'm using Spring 3.0.6, but how would I know what version of Hibernate to use with that version of Spring? More over, if there are multiple possible Hibernate dependencies, how would I know which ones to include for the functionality I need? So far this seems to be partially reading documentation and partially trial and error.
Is there a definitive way of knowing which Maven dependencies to use with certain version of other dependencies? Any which dependencies to use for particular bits of functionality?
Thanks,
James.
I follow these steps when starting to use a new framework:
Go to framework's web site. In your case hibernate web site and try to find latest (or a specific) version. For hibernate it is 3.6.8-Final at the time of writing.
Search for a maven dependency definition on the framework web site. If you can not find any dependency definition, them simply google for "frameworkname _version_ maven dependency" and you'll most probably find necessary definition, as well as the necessary repository information. For example you can find the dependency definition for hibernate on mvnrepository.com and necessary artifact repository information on Hibernate 3.6.8 release page:
The artifacts have all been published to the JBoss Nexus repository under the org.hibernate groupId at http://repository.jboss.org/nexus/content/groups/public-jboss/
The question of which dependencies are necessary and which are optional depends entirely on the framework to be used. So for example in order to use hibernate, as stated on Hibernate Quick Start Guide:
hibernate-core: The main artifact, which contains all the Hibernate classes, in packageorg.hibernate. You need these to build applications using the native Hibernate APIs. It includes capabilities for using native Hibernate mapping in hbm.xml files, as well as annotations.
About compatibility issues (which version of hibernate is compatible with spring 3.0.6), all I can say is you have to read about integration manuals for those frameworks. Since Spring and Hibernate are two exclusively distinct frameworks, I don't think you can find a constant location to look for version compatibility matrix or something like that.
The purpose of Maven is to avoid handling dependencies by hand. Just choose which version of Hibernate to use and include it in your pom; Spring supports many different versions.
If you know what parts of Spring you want to use, just include those parts in your pom; they'll include their own requirements.
Is there a specific module and/or version combination you're having an issue with?
The only way to know for sure that you've got all dependencies is by running your app.
Maven resolves for you transitive dependencies so you can quickly detect missing ones by compiling the java code.
However, in a web app there are many dependencies that are required in runtime only, so they are not detected at compilation time.
you can find out the dependencies by running mvn dependency:tree and analyze if they are required or not by running mvn dependency:analyze.
Taking the newest ones usally works as long as they are stable.
Start with hibernate and spring core, context, tx.
After you added some could you will probably recognize that something else is missing.
Try and error doesn't sound good, but its working pretty well for spring dependencies.

When to run my own maven repository?

I'm working on a small project with one other developer. We are using libraries that are all available in public maven repositories. We have a single, multi-module maven project but build all of the modules every time in our build server and developer machines. The built artifacts are available on the build server for deployment.
Is there any reason for us to setup a maven repository manager? It would run on the build machine, which I would have to connect to via VPN and is slower than downloading from the internet directly.
The best reason to run a repo manager is to achieve reliable behavior in the face of maven's treatment of <repository> declarations.
If any dependency you reference, or plugin you use, or dependency of a plugin you use, declares any repositories, maven will start searching for everything in those repositories. And, if they are unreliable or slow, there goes your build. While current policy is to forbid repository declarations in central, there are plenty of historical poms pointing every-which way.
The only cure for this is to set up a repository manager and declare it to be a 'mirrorOf' '*' in settings.xml. Then, put the necessary rules in your repository manager to search only the places you want to search.
Of course, if there are more than one of you and you want to share snapshots or releases, you'll really want a repo manager, too. That's the obvious reason.
If I turn off my repo manager and just try to build some of my projects that have the bad luck to have plugin/dependencies with repository declarations in their poms, they fail. With the repo manager, all is well.
If you have to ask, probably not.
But it's a pretty cheap date - Nexus is pretty trivial to setup, I don't know about archiva.
Public servers tend to be unreliable.
A local mirror will be faster.
You don't want to get hung up because you cleaned your local repo and can't get something off the public one.
If and when you get into needing to work with multiple versions of your app, I'd start thinking about it harder.
In my opinion, it only becomes a good reason when the projects and the teams working on them grows more and more, specially because the 'versioning' capabilities of it.
My answer is, that you will have to create an own repository as soon as you will need a jar, which is not in the public repositories (not so hard, since for example some JDBC drivers are not hosted in public repo's for licensing issues). If you don't do so, you will loose the main advantage of Maven, that your colleagues do not have to do anything to get the proper libraries. If you introduce a new library, you do not need to say anything to the colleagues if you have company repository, but if not, you need to send the library for them and you need to tell them, how to install the library locally.

Determining what minimal jars are needed for a feature

How do you determine what jars are needed for such and such feature of a framework? For example, what jars would be needed out of all those available for Spring in order to support only dependency injection?
There are tools that create minimal JARs by figuring out which classes are actually used in an application by statically analyzing the code, then creating a new JAR containing only those classes. (I recall using Zelix Classmaster to do this, but there are many alternatives.)
The problem with using these tools for a DI framework like Spring include:
The existing only trace static dependencies. If you dynamically load classes, you have to specifically tell the analyser about each one. DI frameworks in general, and Spring in particular is replete with dynamic loading, including dynamic loading that is opaque to application code.
The existing tools work by creating a new output JAR, not by telling you which of the input JARs are not used. While repackaging the JARs is OK if you are creating a shrink-wrapped application from a closed-source codebase, it is undesirable in general, and potentially problematic with some open-source licenses. Certainly you don't want to do this with Spring.
In theory, someone could write a tool to help. In practice, the tool would need to (for example) know how to extract dynamic class dependencies from Spring configurations expressed in annotations, XML and from bean descriptors created at runtime from higher order configuration (SpringSecurity does this for example). That is a big ask. And even then you have the problem that a "small" change to the wirings made on the installation platform could fail due to a required JARs having been left out by the JAR pruning process.
In my view, the more practical alternatives are:
If you use Maven / Ivy to manage your dependencies, look at the dependency graphs, strip out dependencies that appear to be no longer needed ... and test, test, test.
Manually strip out JARs that appear to be unused ... and test, test, test.
Don't worry about it. A moderate level of unused JAR cruft might add a second or three to deployment and webapp startup times, but that generally doesn't matter. (But if it does ... see above.)
This is why some older Java projects end up having 600 Jars and a 200 MB war file, for a 10,000 line application. Kind of a pain if you don't manage it carefully...
You should really ask the framework provider or read the documentation. Statically analyzing what jars are required might not be enough in some cases(dynamic loading) and sometimes you might end up with too many jars.
I once did some ftp helper stuff to a sort of "utility" library. It depended on some apache ftp jar. If you never used the ftp features in the library you would not need the ftp jar but statical analysis of the code might say you need it. This is something you should documents.

Categories

Resources