Baruch Sadogursky's complete blog can be found at: blog.sadogursky.com

Items:   6 to 10 of 14   « Previous  | Next »

Wednesday, June 22, 2011

Oh, you are using build tool with dependency management? Good! Be it Maven2/3, Gradle or Ivy, your life as devops or developer is much easier. Until you hit it. The evil transitive dependency. How can it be evil you ask? When the classes in it clash with the classes you really need.  Here’s some use-cases:

  1. Same dependency, different jar names, two examples here:
    1. The Jakarta Commons renaming effort: commons-io:commons-io:1.3.2 and org.apache.commons:common-io:1.3.2
    2. The Spring Framework artifacts naming convention alternatives: spring-beans, spring-context, etc in repo1 versus org.springframework.beans, org.springframework.context, etcin
      SpringSource EBR.
  2. Different packaging of the sample classes, many examples here:
    1. OSGi repackagings: asm:asm:3.2 and org.objectweb.asm:com.springsource.org.objectweb.asm:3.2.0
    2. Modularization of Spring 2.5.6: as single jar and as spring-whatever multiple modules
    3. Xerces and Xalan are included in JDK since 1.5. They are still present as transitive dependencies in all the tools which support JDK 1.4.
    4. Alternative packagings with and without dependencies: cglib:cglib and cglib:cglib-nodep
    5. Project merges like Google collections, which are now included in Google Guava
  3. Deliberately reimplemented interfaces, for example for bridging legacy APIs to new implementation, such as in SLF4J.
  4. Your patches for 3rd-party tools.

All those may end up with 2 or more classes with the same name in the classpath. Why it is bad? Java class identifier consists of fully-qualified class name and the classloader that loaded it, so if two classes with the same name reside in same classpath JVM considers them to be the same class, and only one of them will be loaded. Which one? The first classloader encounters. Which one will it be? You have no idea.
When the duplicated classes are exactly the same, you will never notice. But if the classes are different, you’ll start getting runtime exceptions, such as NoSuchMethodError, NoClassDefFoundError and friends. That’s because other classes expect for find one API, but encounter another one – wrong class was loaded first. Not fun.

Now, when you know how evil they are, let’s take those bastards down!

Maven 2/3

There is no simple way (Maven’s tagline) to exclude some dependency from all the scopes. I’ll show two cases – manual exclusion and working with IntelliJ IDEA:

    1. Stage 1: exclude all the banned dependencies one by one:
      1. Manually edit Maven’s poms
        1. For each evil dependency:
        2. Find which top-level dependency brings the evil transitive hitcher with it. This is done by using Maven Dependency Plugin:
          mvn dependency:tree -Dincludes=commons-logging:commons-logging
        3. You’ll get something like this:
          [INFO] com.mycompany.myproduct:rest-client:1.0
          [INFO] \- org.springframework:spring-webmvc:jar:3.0.5.RELEASE:compile
          [INFO]    \- org.springframework:spring-core:jar:3.0.5.RELEASE:compile
          [INFO]       \- commons-logging:commons-logging:jar:1.1.1:compile
        4. Go to the pom.xml with your dependency management (you use dependency management, don’t you? If you don’t, don’t tell anyone, go and start using it) find spring-webmvc dependency and add an exclusion to it:
          1     <dependency>
          2     	<groupId>org.springframework</groupId>
          3     	<artifactId>spring-webmvc</artifactId>
          4     	<version>3.0.5.RELEASE</version>
          5         <exclusions>
          6             <exclusion>
          7                 <artifactId>commons-logging</artifactId>
          8                 <groupId>commons-logging</groupId>
          9             </exclusion>
          10         </exclusions>
          11     </dependency>
      2. Working with IntelliJ IDEA:
        IntelliJ IDEA Maven Dependencies
          1. Open Maven Dependencies Graph.
          2. Filter it by the dependency you are looking for.
          3. Select it and press Shift-Delete.
    2. Good job! Your nailed them down in the current version of your build. But what happens when someone adds a new 3rd party dependency and brings some bad stuff with it as transitives? You need to protect your build from this scenario. So, stage 2: Fail the build if one of the banned dependencies ever added to the build with Maven Enforcer Plugin. Add the plugin to your root project pom:
      1 <project>
      2   <build>
      3     <plugins>
      4       <plugin>
      5         <groupId>org.apache.maven.plugins</groupId>
      6         <artifactId>maven-enforcer-plugin</artifactId>
      7         <version>1.0</version>
      8         <executions>
      9           <execution>
      10             <id>enforce-banned-dependencies</id>
      11             <goals>
      12               <goal>enforce</goal>
      13             </goals>
      14             <configuration>
      15               <rules>
      16                 <bannedDependencies>
      17                   <excludes>
      18                     <exclude>commons-logging</exclude>
      19                     <exclude>cglib:cglib</exclude>
      20                   </excludes>
      21                 </bannedDependencies>
      23               </rules>
      24               <fail>true</fail>
      25             </configuration>
      26           </execution>
      27         </executions>
      28       </plugin>
      29     </plugins>
      30 </build>
      31 </project>
    3. As I mentioned, using the Enforcer plugin won’t exclude the unwanted dependencies, it only will fail the build. Once that happened (and trust me, it will), you need to go and exclude them manually, as described in Stage 1 above.

And we are done with Maven. Not fun? Switch your build tool!

Ivy

Well, comparing to Maven it’s emabrassing how easy is to add global exclusion in Ivy. All you need to do is add exclude tag, and it will do the job for all the transitive dependencies, both in current and future use:

1 <dependencies>
2     <dependency org="org.springframework" name="spring-webmvc"
3 rev="3.0.5.RELEASE" conf="compile->default"/>
4     <exclude org="commons-logging"/>
5 </dependencies>

Done.

Gradle

Since Gradle uses Ivy under the hood, here comes the same ease, but even groovier:

1     configurations {
2         all*.exclude module: 'commons-logging'
3         all*.exclude group: 'cglib', module: 'cglib-nodep'
4     }

That’s all! Now your code is bullet-proof from classloading conflicts and you can do nasty class-replacing stuff, for logging or pleasure.


Filed under: Build Tagged: gradle, ivy, maven2, maven3

Monday, December 6, 2010

Just back from Project Automation Experience 2010.

Guess what? It was awesome!

Here’s my summary:

General:

The conference was combined with Rich Web Experience 2010, which probably, was the right thing to do for the first ever project automation seminar. It was announced 2 months ago, bringing 52 registrants (out of ~400 total for both events). Pretty impressive for such a short notice on such a narrow subject. The organization was fantastic, everything felt well-planned and well-orchestrated. It was my second NFJS conference, and like with the first one, they delivered!

Sessions:

The first speaker in the conference was the one and only Douglas Crockford in his notorious Quality talk. Top quality (pun intended) – funny, entertaining, and touching the right points. Bottom line – read The Mythical Man-Month and Literate Programming.

Yet another keynote was devoted to actually Project Automation. Hans Dockter laid down his vision on the topic, the idea being – we are entering very interesting times, better understanding of the needs combining with the right tools will enable us whole new level of project automation, way beyond what we are used to today.

Lots of fun and enriching talks, like Tim Berglund‘s Complexity Theory and Software Development or an experts panel, moderated by Ted Neward (who honestly tried to recall who I was and where did we met), and tons of useful and deep sessions and workshops, just to name a few: Fred‘s modularity and smart BRMs talks, Kohsuke’s updated Doing More with Hudson, Git, Sonar and Liquibase sessions from Matthew McCulloughOlivier Gaudin and Tim Berglund. The integration with Rich Web Experience gave the participans the opportunity to mix and match the sessions, and there was a lot of stuff to attend – HTML5, CSS3, Flash, iOS and Android development, Grails, Wicket and what’s not! 10 parallel sessions in any given time, now go choose one!

The sessions I gave:

First of all, it was my first speaking experience outside of Israel. I think I did well. At least the feedbacks say so :) The high speaker:attendee ratio produced small classes with live interaction, I loved it. As I suspected, 90 minutes are too long, looks like 60 minutes is my favorite format, but I managed to keep the audience awake :)

Here are my sessions:

By the way, Prezi rocks, as usual.

My next goal – speaking in a bigger seminar around spring 2011, probably on different topic, more relevant to my new job.

Florida:

December 1st – 30ºC, sun and ocean. That’s a typical room view. No additional comments needed, I guess.

Everglades and alligators rock too. It looks like this.


Filed under: Build, presentation Tagged: build, gradle, nfjs, pax2010, project automation experience 2010

Monday, October 11, 2010

Well, it’s time to another solution for something that I see as the biggest absent feature of Gradle - decent migration tool from Maven2. Gradle provides some cool Maven2 integration features – you can use Maven repositories, Gradle (well, Ivy inside Gradle) understand your dependencies’ poms in terms of transitive dependencies, you can even generate pom for your artifact and deploy it to Maven repo, but what about the build itself? For now it should it be trashed over and rewritten completely. That is a show-stopper for a lot of projects. They worked so hard to make their Maven work (you know what I mean… Maven == working hard), and now I have to say them to just throw it away and rewrite? No way! Some time ago I took @psynikal’s script for generating Gradle like dependencies from Maven like ones and improved it a bit to generate usable Gradle build file out of pom. The full story is here. That solution, while definitely is better than void is far from being perfect for number of reasons:

  1. It is fragile.
  2. It uses maven-help-plugin. Did I say fragile?
  3. Changes in pom.xml aren’t reflected in your build – you need to regenerate the gradle build files (writing them over, destroying all changes you made – the script isn’t perfect in that sense).
  4. Probably some annoying bugs.

Now it’s time for something more serious – the m2metadata plugin. In an essence, it takes metadata from Maven’s Project Object Model and builds Gradle project out of it.

More specifically it does the following:

  1. Ask Maven to parse poms and settings xmls as it does during regular Maven build.
  2. Set group, version and status (snapshot/release) for Gradle project.
  3. Apply Gradle plugins according to packaging (jar -> java, war -> war). Currently those two are the only supported, but more are coming.
  4. Get some metadata from well-known Maven plugins and configure Gradle plugins with it. This step currently includes setting Java compiler level and configuring sources and resources directories.
  5. Add repositories.
  6. Add dependencies (both external and inter-project).

That’s about it.

Now for the dark side. Currently, the m2metada-plugin clashes with maven-plugin (classloading issues). It can be worked around, but:

  1. Maven-plugin is bundled, so it must be explicitly removed by deleting jars from Gradle’s lib directory.
  2. The true power of m2metadata plugin is using it together with maven-plugin. M2metadata-plugin retrieves metadata part of maven build, while maven-plugin runs Maven’s runtime to execute goals like generating poms and deploying to maven repositories.

Yet another, more methodological than technical downside of m2metadata-plugin is that it preserves the usage of pom.xml. It works, so you don’t touch it, and it stays forever instead of being replaced with fully-blown build.gradle. For that concern, I see clear benefits in using the script solution, which trashes the pom.xml, leaving you with pure-gradle solution, and in conjunction with the idea-plugin gives you all you need to start going.

All in all, once the classloading issues will be sorted out, It looks to me that the mission of creating migration tool can be considered as accomplished.

You can find my work here (Usage guide in Wiki, TODOs in issues). I am going to present it (together with the script, which,as mentioned, has it own benefits) at The Project Automation Experience 2010 in the Java Build Automation Tools Jungle session. The presentation will be posted here once it will be ready.


Filed under: Build Tagged: build, gradle, maven2, project automation experience 2010

Sunday, May 30, 2010

Apparently, most of the visitors to my “Integrating MongoDB with Spring Batch” post can’t find what they look for, because they look for instructions how to integrate MongoDB with plain Spring Core.
Well, the source includes that integration, but it’s on github, and anyway that wasn’t the focus of that post.
So, here’s the integration – short, plain and simple:

  • Properties file with server and database details (resides in classpath in this example):
1    db.host=localhost
2    db.port=27017
3    app.db.name=app
  1. application-config.xml (or whatever you call it):
    1<beans xmlns="http://www.springframework.org/schema/beans"
    2       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3       xmlns:context="http://www.springframework.org/schema/context"
    4       xsi:schemaLocation="http://www.springframework.org/schema/beans
    5           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    6           http://www.springframework.org/schema/context
    7           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    8    <context:property-placeholder 
    9                location="classpath:db.properties"/>
    10    <bean id="mongo" class="com.mongodb.Mongo">
    11       <constructor-arg value="${db.host}"/>
    12       <constructor-arg value="${db.port}"/>
    13   </bean>
    14   <bean id="db" 
    15      class="com.mongodb.spring.config.DbFactoryBean">
    16       <property name="mongo" ref="mongo"/>
    17       <property name="name" value="${app.db.name}"/>
    18   </bean>
    19</beans>
  2. The com.mongodb.spring.config.DbFactoryBean class:
    1 public class DbFactoryBean implements FactoryBean<DB> {
    2    
    3        private Mongo mongo;
    4        private String name;
    5    
    6        @Override
    7        public DB getObject() throws Exception {
    8            return mongo.getDB(name);
    9        }
    10   
    11       @Override
    12       public Class<?> getObjectType() {
    13           return DB.class;
    14       }
    15   
    16       @Override
    17       public boolean isSingleton() {
    18           return true;
    19       }
    20   
    21       public void setMongo(Mongo mongo) {
    22           this.mongo = mongo;
    23       }
    24   
    25       public void setName(String name) {
    26           this.name = name;
    27       }
    28 }
    
1    @Configuration
2    public class ApplicationConfiguration {
3    
4        @Value("${app.db.name}")
5        private String appDbName;
6    
7        @Value("${db.host}")
8        private String dbHost;
9    
10       @Value("${db.port}")
11       private int dbPort;
12   
13   
14       @Bean
15       public DB db() throws UnknownHostException {
16           return mongo().getDB(appDbName);
17       }
18   
19       @Bean
20       public Mongo mongo() throws UnknownHostException {
21           return new Mongo(dbHost, dbPort);
22       }
23   }

That’s, actually, it – enjoy. If you feel some part of the puzzle is missing, please leave a comment.


Filed under: Frameworks, Friendly Java Blogs Tagged: java, mongodb, spring

Thursday, May 20, 2010

Using Maven2 to build tools was like AWT to UI frameworks: revolutionary, but not without downsides.Concepts such as standardization of project layout and centralized dependency management are preserved in almost every new and future build tool.


Filed under: Build, presentation Tagged: alphacsp, ant, build, buildr, gant, gmaven, gradle, javaedge, maven2, prezi

Items:   6 to 10 of 14   « Previous  | Next »