Posts Tagged Maven
Scenario: To make use of a new feature in a certain dependency or to get a bugfix that’s causing your project pain, you bump the version of a dependency in your pom file — maybe the parent pom version. Then you type
…put your hands over your eyes, and gingerly press Enter.
You may see something like this:
[WARNING] Rule 0: org.apache.maven.plugins.enforcer.RequireUpperBoundDeps failed with message: Failed while enforcing RequireUpperBoundDeps. The error(s) are [ Require upper bound dependencies error for org.slf4j:slf4j-api:1.7.11 paths to dependency are: +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-org.slf4j:slf4j-api:1.7.11 and +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-com.netflix.hystrix:hystrix-core:1.5.4 +-org.slf4j:slf4j-api:1.7.11 (managed) < -- org.slf4j:slf4j-api:1.7.10 and +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-com.example.framework:example-core:0.5.9-SNAPSHOT +-org.slf4j:slf4j-api:1.7.11 (managed) < -- org.slf4j:slf4j-api:1.7.7 and +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-com.example.framework:example-core-data:0.5.9-SNAPSHOT +-org.slf4j:slf4j-api:1.7.11 (managed) < -- org.slf4j:slf4j-api:1.7.5 ...
…only it goes on for screens and screens. What happened? Read the rest of this entry »
In a prior post about when to use which scope for a Maven artifact, I left out the provided scope, because, as I said at the time, “I don’t get as confused about that one so I left it out.” I spoke too soon. : )
When I said that, I was only thinking of which classpath(s) the artifact would available to in its immediate project. But there are two additional concerns besides the classpath availability: whether the artifact will be built into the resulting (.war) target, and whether artifacts depending on this one will inherit the dependency. The latter issue is also affected by the <optional> tag.
The following table reflects my current understanding of how the scope and optionalness of a dependency affect:
- The classpath(s) in which the artifact is available;
- Whether the artifact is included in the war; and
- When artifact A declares a dependency on artifact D: whether artifacts declaring a dependency on artifact A will also transitively get a dependency on artifact D.
|Scope||Optional?||Classpaths in which artifact is available||Artifact included in war**||Dependency propagates transitively|
|(main) compile||(main) runtime||test*|
*Note that the “test” classpath is used both at test compile time and test runtime; it doesn’t seem to be possible to specify that an artifact should be available at test runtime but not test compile time.
**I don’t think it has to necessarily be packaged as war… trying to make a concrete example.
The “deployment fails the second time” issue has been resolved, and the CI servers are back in business.
For those who may be interested, the problem turned out to be a Maven config issue in [the functional test project]’s pom file.
(Note: you may need your techno-gibberish decoder goggles for the next details: )
In making ojdbc available to Liquibase for when we deliver schema changes, the ojdbc jar file got included in the war file. The config has been this way for several weeks, but we didn’t notice it until we just in the last few days got to the point of contributing Hibernate mappings, which starts the Persistence service, which needs ojdbc to actually work. At that time, the ojdbc jar in the war file fought with the ojdbc jar in JBoss’s server/default/lib directory, and just like when you were fighting with your sister over that cookie, nobody won and we got the NoClassDefFoundError.
(Or something vaguely similar to that.)
Thanks to [those who helped] for their help with this!
Now back to our regular programming…
I keep getting confused about which artifact scope to use: compile, test, or runtime? So here’s a little algorithm to help me (it’s a conservative algorithm, trying to depend on libraries only to the extent necessary):
- If the artifact is not not needed by the production code but only by tests, use test scope.
- Otherwise, if production code needs the artifact at runtime but does not need to code against its classes and interfaces (for instance, if all references to the artifact in production code are in Spring bean files), use runtime scope.
- Otherwise, if the production code needs to code against the artifact’s classes and interfaces, use compile scope.
So in my algorithm you consider test scope first, and open it up to runtime or compile scope only if necessary.
I use Eclipse’s External Tools feature to run a lot of Maven goals: clean install, eclipse:clean eclipse:eclipse, etc. I have an external tool configuration set up for each of these common commands.
Sometimes, though, I want to try out a goal I don’t as often use. Maven dependency:tree and dependency:list I use almost enough to have a special external tool configuration for each… but from time to time I find out about other Maven plugins that I want to try out but would rather not have to clutter up the external tools list with special entries for each one.
As an alternative, sometimes I try out these goals from the Windows command prompt, but it’s a pain to navigate to my project’s working directory each time before executing the command. I probably experiment less with such commands than I would otherwise because of the effort to prepare to run them — I just get by without their output, without really thinking about it.
Yesterday, though, Keith was helping me get set up to do JBoss remote debugging in Eclipse (a whole ‘nother topic), and in the process of setting it up, one of us wondered if you could set up an external tool that just dropped you to a Windows command prompt so you could type whatever command you want.
You can! Here’s my configuration, which I call Ultimate Power:
When I run this, it puts a Windows command prompt sitting in my project directory in a Console window, and now I can type my command:
I’m experiencing an issue where if I have my producer send 100 JMS messages to my ActiveMQ queue while a consumer is listening, the listener will pick up maybe 90 of them and then no more. This is not good! I need to find out why this is.
I’m running ActiveMQ 5.1.0 at the moment, but one of the suggestions I found was to upgrade to the 5.2.0 Release Candidate. I updated my pom to depend on that version, but since this artifact is not in the main Maven repository yet, Maven Eclipse couldn’t find it and I couldn’t build my project.
I had run into this type of thing before when I was trying out a Bitronix Transaction Manager 1.3 release candidate. What I needed was to add this to my pom:
<repositories> <repository> <id>activemq-5.2.0-release-candidates</id> <url>http://people.apache.org/~gtully/staging-repos/activemq-5.2.0</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
- I got the URL from Gary Tully’s RC3 announcement post
- I made up the id – I don’t think it’s necessary in this case
That worked — after running what we call “Maven Eclipse” (
mvn eclipse:clean eclipse:eclipse), now activemq-core-5.2.0.jar shows up in my Referenced Libraries!
First, some background:
Keith just recently changed our can’t-mock-dis Startup service from a plain ol’ Singleton (in the Gang-of-Four sense, not in the Spring sense) to an Abstract Factory so that — woohoo! — we can now mock out the Startup service and its application-context-creatin’ slowness when we want to.
This gives us such great flexibility in the testing department, and the cost is a slightly wordier syntax when you’re getting an instance of the real StartupSvc. This syntax changed from:
StartupSvc startupSvc = StartupSvc.getStartupSvc();
StartupSvc startupSvc = new StartupSvcFactoryImpl().getStartupSvc();
But these calls aren’t littered throughout the application code — it’s kicked off by ServletContextListeners and such — so there are really only a few places that even have to change. It’s great!
A Happy Move
So anyway, earlier this week when Keith committed his changes, I had eventually Maven Eclipsed a couple of prototype .war projects I was working on and noticed that I needed to update to the new syntax for getting an instance of the StartupSvc. I was glad to see that the abstract factory stuff had been committed.
But then today, I Maven Eclipsed again, and now Eclipse was saying it didn’t know what a StartupSvcFactoryImpl was and trying to get me to return to the old syntax.
It appeared that Keith had reverted his changes and removed the abstract factory. Had he encountered a nasty problem and reverted it until we could figure out a solution? I didn’t want to go back to the old way! Why didn’t he tell me?! (This last one was a bit hypocritical on my part, since I’m not very good yet myself at noticing when my changes are breaking changes that will affect others on the project and notifying them accordingly.)
Then I realized that, oops, hadn’t I just Maven Install’d the Startup module (with a minor change I needed to test with on my other project) to my local Maven repository from my local working copy? And how long had it been since I had updated the source code of that project?
Oopsy oops, I had just made the StartupSvc revert, by installing an older version. I just updated the Startup project from Subversion, then Maven Installed it again, then Maven Eclipsed my .war prototype… and the abstract factory is back.
Silly me! :)