Per HHH-2412 and its design discussion I have been working on supporting JDBC4 in Hibernate. Initially I had planned on adding this in 3.6, but now leaning toward 3.5 Anyway, as outlined on the design wiki, I initially thought to add this support as separate modules. However, I quickly came to the realization that using separate modules would actually require users make an explicit choice wrt an extra
jar. Especially considering that I could make Hibernate code make this determination programatically, I really did not like that aspect to using modules here. So I started looking for alternatives.
As I normally do, I started by thinking of just the ideal outside of any build structure or tool. So to my mind the best option here seemed to include compiling JDBC4 support targeting JDK 1.6 and JDBC3 support targeting JDK 1.4 and then bundling all that code into a single jar. The code which decides which feature-set to use uses reflection anyway, so there is no issue with having both in the same jar as long as only the correct classes actually get loaded (and anything else would be a bug in this determination code).
Well unfortunately it turns out that Maven does not really support such a setup. In the common case I think you'd set up multiple source directories within that main module and run different compilation executions against them with different compiler settings (source/target). This Maven explicitly disallows (see MCOMPILER-91 and its discussion for details).
Two workable
solutions were presented to me (workable in that Maven could handle these):
- Use a single source directory, but configure 2 executions of the compiler plugin taking advantage of includes/excludes to define what to compile targeting 1.6 and 1.4. The issue here is that this is not good fit for IDEs.
- Split this into 3 modules (one each for JDB3 and JDBC4 support plus another for
commonality
to avoid circular dependencies with core). Core would then pull the compiled classes from these 3 modules into its jar. Seems overly complicated to me just to work around a self-imposed limitation of Maven. And sorry, I just don't see how this constitutes amessed up system
as indicated in that Maven discussion.
Anyway, I really hope someone has other suggestions on better ways to handle this with Maven. Anyone?
As a third option, I was thinking you could always build the patched version of the compile plugin as described on the mailing list. Build with that. Then send out a notice to everybody and tell them to use your version. Watch chaos ensue. ;-)
Maven really wants you to create lots of little bitty projects, which drives me crazy, but I suppose works out okay most of the time. So if I were you I'd go with 2.
I've used multiple source directories using the build-helper-maven-plugin. It was more or less the same than you want to do.
Another option is merging jars multiple jars into one executable jar using the maven-shade-plugin. This would enable you to develop the jdbc3 and jdbc4 as separate jars and generating a hibernate.jar which contains either of it (depending on the profile you've chosen).
I'd go this way: Build a jar containing both jdbc3 and jdbc4. At startup check which java version is running and load the appropriate jdbc classes. The core itself would only work against a common interface shared by the jdbc3 and jdbc4 classes.
Anyway, I really like to see that you ask for opinions from the community. Keep it up!
Actually it does not from what I have been told because you cannot define separate compile settings for the various added source directories.
The issue here imo is that really it is the hibernate-core jar where all this should go. But its a chicken-and-egg issue in regards to these jdbc3 and jdbc4 jars since they would depend on core, but core would need to depend on them in order to bundle their classes. This is essentially option number 2 I listed above, and as stated is way over-complicated for this situation imo.
Well this is largely what is being done (did you see the design wiki?). The problem is how to present this to the user in terms of jars they need to load into their environment.
IDEs use different terminology, but I'll use IntelliJ's as it matches pretty closely with Maven's here though the issue is the same in Eclipse as well. In IntelliJ, a project is made up of modules; it is in the modules where you define the JDK to use. Even though you can define multiple source directories within a module in IntelliJ, they all share the JDK assigned to that module.
So say you were to have JDK 1.4/1.5 (JDBC3) and JDK 1.6 (JDBC4) targetted code in the src/main/java directory. Aside from being a Maven hack, this is not the correct way to model this build. And an attempt to load that into an IDE is going to complain (if the module targets 1.4/1.5, the 1.6 targetted class will not compile, and visa versa).
So the second option sort of works using the shade plugin. You just have to be willing to accept some minor annoyances such as the fact that 3 modules (common, jdbc3 and jdbc4) are indeed needed, that these 3 modules still make there way into your local repo (and you have to explicitly configure the deplpy plugin to these modules or else they show up in the deploy repos too) and that this generally seems a bit more complex then it outght to be.
The verbiage I came to after discussing this with numerous folks is that we really have a 2-way set of dependencies here, but that the dependencies are isolated to phases. That is ideally JDBC3 and JDBC4 would have compile-time dependency on CORE, while CORE would have a package-time dependency on both JDBC3 and JDBC4 in order to package those classes into its jar. However Maven does not allow limiting dependencies to phases and even if it did it actually performs every lifecycle phase on each module before moving on to the next module.