Отмечено: java Показать/спрятать ветки комментариев | Горячие клавиши

  • manandbytes 12:00 on April 27, 2011 Постоянная ссылка |
    Метки: java,   

    Why -source and -target are not a convention 

    Convention over configuration is a simple concept. Maven incorporates this concept by providing sensible default behavior for projects. The Compiler Plugin is used to compile the sources of your project and provides some defaults for source/target levels for Java source code.

    You may think that source/target levels is a part of this ‘convention over configuration’ concept. But actually they are not, so keep reading to learn why.

    What problems to expect when building something that small as Kewin Sawicki‘s TimeAgo library with Maven? No, I’m not kidding since I’ve expected no problems at all but… Unfortunately, build of the current master branch fails:

    [INFO] ------------------------------------------------------------------------
    [INFO] Compilation failure
    /org.github.timeago/src/main/java/org/github/timeago/TimeAgo.java:[129,23] cannot find symbol
    symbol  : method format(java.lang.String,long)
    location: class java.text.MessageFormat
    [INFO] ------------------------------------------------------------------------

    There are 5 such problems related to java.text.MessageFormat‘s method format(String pattern, Object... arguments). This method uses the varargs feature introduced in Java5, as well as the method itself, so the problem is obvious: Maven tries to compile TimeAgo with pre-Java5 JDK.

    How is it posible?! It was taken for granted that Maven allows to avoid such problems but, for some reason, I can’t build it as is.

    Here we have a problem, that Martin Fawler explained some time ago:

    One of the prevailing assumptions that fans of Continuous Integration have is that builds should be reproducible. By this we mean that at any point you should be able to take some older version of the system that you are working on and build it from source in exactly the same way as you did then.

    Let’s digg into some details and try to find out why it’s unreproducible and how easy it will be to find a configuration that ‘just works’.

    Problem: unreproducible build

    So, right now I have 3 different JDK installed:

    • usr/lib/jvm/java-6-openjdk
    • usr/lib/jvm/java-1.5.0-sun-
    • usr/lib/jvm/java-6-sun-

    Lets add 4 versions of Maven2 to the mix:

    • Apache Maven 2.1.0 (r755702; 2009-03-18 21:10:27+0200)
    • Apache Maven 2.2.1 (rdebian-4)
    • Apache Maven 3.0.2 (r1056850; 2011-01-09 02:58:10+0200)
    • Apache Maven 3.0.4-SNAPSHOT (rNON-CANONICAL_2011-04-06_23-20_mn; 2011-04-06 23:20:51+0300)

    and try to build TimeAgo with mvn clean compile using bash-matrix-project 😉 approach described earlier:

    Apache Maven 2.1.0 (r755702; 2009-03-18 21:10:27+0200) FAIL
    Apache Maven 2.2.1 (rdebian-4) FAIL
    Apache Maven 3.0.2 (r1056850; 2011-01-09 02:58:10+0200) SUCCESSFUL
    Apache Maven 3.0.4-SNAPSHOT (rNON-CANONICAL_2011-04-06_23-20_mn; 2011-04-06 23:20:51+0300) SUCCESSFUL

    As build fails for Maven 2.x but succeeds for Maven 3.x, regardless of JDK been used, definetely, it’s not reproducible. Let’s try to find the reason for such strange behavior.


    Fire build again but this time we’ll set source/target levels explicitly, via command-line options -Dmaven.compiler.source=1.5 and -Dmaven.compiler.target=1.5 and it succeeds for all environments.

    #1: missing source/target levels in POM

    Looking at the project’s POM, we see nothing related to compiler plugin’s settings. This way build depends on default values for source and target levels implemented in currently effective version of the compiler plugin. I strongly disagree with comments like

    Maven has a strong preference for «convention over configuration» which means that requiring the source and target entries in the pom is not really reasonable IMO. Instead, the defaults should be documented better, and perhaps the error message could be adjusted to point to a FAQ entry that explains things for new users.

    on MCOMPILER-57. Comments on MCOMPILER-80 like

    Using default source/target levels in a build tool is not a good idea since it makes both the success of the build and its artifacts dependent on the environment in which it was run, contrary to the goals of a reproducible build. A given module or tree of modules will have a certain source level it requires in order to compile, so increments to this in the POM should be coversioned with source code changes to use new language features. Target level (usually but not necessarily the same as source level) is even more important to specify explicitly, because it is not obvious when you get it wrong — until your bytecode fails to load on an older customer JVM which you had intended to still support.

    or this one

    Just that, the source/target levels should be decided by its owners/developers, NOT BY Maven. It’s the project owner/developer’s responsibility to decided the expected source/target levels and set the values in the project POM. Thus to have reproducible builds across computers/jdks.

    reflect a reality much better.

    Maven2 help plug-in is not that helpful

    I tryed to inspect the project’s effective POM with maven-help-plugin, as you may find answers like this. For Maven 2.x it’s quite small, due to some bug in Maven2 and not in plugin:

    [preserved_text e28c4bc0cef72ff1780a91c079421884 /]

    After this change, your build will fail if some plugins are missing valid versions, with a clear reason:

    [INFO] ------------------------------------------------------------------------
    [INFO] Building Time Ago
    [INFO]    task-segment: [test-compile]
    [INFO] ------------------------------------------------------------------------
    [INFO] [enforcer:enforce {execution: enforce-plugin-versions}]
    [WARNING] Rule 0: org.apache.maven.plugins.enforcer.RequirePluginVersions failed with message:
    Some plugins are missing valid versions:(LATEST RELEASE SNAPSHOT are not allowed )
    org.apache.maven.plugins:maven-clean-plugin.    The version currently in use is 2.3
    org.apache.maven.plugins:maven-resources-plugin.        The version currently in use is 2.3
    org.apache.maven.plugins:maven-deploy-plugin.   The version currently in use is 2.5
    org.apache.maven.plugins:maven-compiler-plugin.         The version currently in use is 2.0.2
    org.apache.maven.plugins:maven-install-plugin.  The version currently in use is 2.3.1
    org.apache.maven.plugins:maven-surefire-plugin.         The version currently in use is 2.7.2
    org.apache.maven.plugins:maven-site-plugin.     The version currently in use is 2.0
    org.apache.maven.plugins:maven-jar-plugin.      The version currently in use is 2.2
    [INFO] ------------------------------------------------------------------------
    [INFO] ------------------------------------------------------------------------
    [INFO] Some Enforcer rules have failed. Look above for specific messages explaining why the rule failed.

    However, you still have to be careful when choosing versions. Using wrong version, you may, by accident, narrow down a range of the tools available to your consumers.

    For instance, one of the real projects I know about, is a Flex application that requires some specific version of a plugin to be used and that very version works with an exact version of Maven 2. So using any plugins that require anything higher than Maven 2.0.8, IIRC, is a ‘no-no’ for this project.

    Recent changes in Jenkins is another example. It started using com.cloudbees.maven-license-plugin to check license headers in source files. Initially this plugin required Maven 3.x and introducing this dependency to Jenkins made it impossible to build Jenkins with Maven 2.x for no apparent reason. Fixing this problem, in this particular case, was easy for two reasons:

    But this not true for most projects. I would rather be more consvervative in such situations and not use the latest (but not always greatest) versions without clear benefits.


    One apple a day… When it refers to the Maven compiler plugin, you:

    • must explicitly define source and target levels
    • should specify version of plugin (but please, be sane)

    These small changes will make your builds much more stable and resistant to changes in environments while obeying its contracts like ‘I’m Java5-compatible’.

  • manandbytes 20:05 on April 17, 2011 Постоянная ссылка |
    Метки: debian, , harmony, java   

    Installing Apache Harmony on Debian 

    What’s Apache Harmony? It’s an open source Java SE implementation with an unclear future. But, please, don’t ask me ‘Why installing it?’ Because developers are curious creatures 😉

    I don’t like to install a software distributed as a tar.gz archives. If it is possible, I’ll use my distribution’s native packages. It turned out that Apache Harmony project provides prebuilt packages for Debian/Ubuntu. So you have to download packages one by one and just install with dpkg --install harmony-5.0-jre_0.0r991518-1_i386.deb.

    There is nothing wrong if you’re interested in a one-time installation but there are manual actions required when (and if) Harmony project provides updates:

    • you have to be notified somehow about the fact that a new version is available;
    • you have to download a number of packages one by one;
    • you may have to (semi)manually resolve missing dependencies.

    As my motto says,

    less work for humans, more work for machines. just as it should be

    so let my machines do some more work 😉

    Make packages’ location known to APT

    Add these two lines to /etc/apt/sources.list:

    deb http://mirrors.ibiblio.org/pub/mirrors/apache/harmony/milestones/6.0/debian/i386/ ./
    deb http://mirrors.ibiblio.org/pub/mirrors/apache/harmony/milestones/5.0/debian/i386/ ./

    and update the list of available packages with aptitude update.

    For most Apache projects, all links on the download page point to the best mirror site based on your location, and Harmony’s Project Downloads page is no different. It suggested http://apache.vc.ukrtel.net/ as the best mirror site for my current location and, unfortunately, files mirrored to /harmony/milestones/6.0/M3/debian/i386. Chances are that the next milestone builds will be stored in other directory like /harmony/milestones/6.0/M4/debian/i386 and I have to touch sources.list. I think that layout provided by mirrors.ibiblio.org doesn’t have these drawbacks but only time will tell.

    Install them

    Installation is as simple as running aptitude install harmony-5.0-hdk harmony-6.0-hdk.

    Check what’s installed

    Let’s check what we have for main two executables, update-alternatives --display java:

    java - manual mode
      link currently points to /usr/lib/jvm/java-6-sun/jre/bin/java
    /usr/bin/gij-4.4 - priority 1044
    /usr/bin/gij-4.5 - priority 1045
    /usr/bin/java-harmony - priority 30
      slave java.1.gz: /usr/share/man/man1/java-harmony.1.gz
    /usr/bin/java-harmony-6.0 - priority 30
      slave java.1.gz: /usr/share/man/man1/java-harmony-6.0.1.gz
    /usr/lib/jvm/java-1.5.0-sun/jre/bin/java - priority 53
      slave java.1.gz: /usr/lib/jvm/java-1.5.0-sun/jre/man/man1/java.1.gz
    /usr/lib/jvm/java-6-openjdk/jre/bin/java - priority 1061
      slave java.1.gz: /usr/lib/jvm/java-6-openjdk/jre/man/man1/java.1.gz
    /usr/lib/jvm/java-6-sun/jre/bin/java - priority 63
      slave java.1.gz: /usr/lib/jvm/java-6-sun/jre/man/man1/java.1.gz
    Current 'best' version is '/usr/lib/jvm/java-6-openjdk/jre/bin/java'.

    and update-alternatives --display javac:

    javac - manual mode
      link currently points to /usr/lib/jvm/java-6-openjdk/bin/javac
    /usr/bin/ecj - priority 143
      slave javac.1.gz: /usr/share/man/man1/ecj.1.gz
    /usr/bin/gcj-wrapper-4.5 - priority 1045
    /usr/bin/javac-harmony - priority 30
      slave javac.1.gz: /usr/share/man/man1/javac-harmony.1.gz
    /usr/bin/javac-harmony-6.0 - priority 30
      slave javac.1.gz: /usr/share/man/man1/javac-harmony-6.0.1.gz
    /usr/lib/jvm/java-1.5.0-sun/bin/javac - priority 53
      slave javac.1.gz: /usr/lib/jvm/java-1.5.0-sun/man/man1/javac.1.gz
    /usr/lib/jvm/java-6-openjdk/bin/javac - priority 1061
      slave javac.1.gz: /usr/lib/jvm/java-6-openjdk/man/man1/javac.1.gz
    /usr/lib/jvm/java-6-sun/bin/javac - priority 63
      slave javac.1.gz: /usr/lib/jvm/java-6-sun/man/man1/javac.1.gz
    Current 'best' version is '/usr/lib/jvm/java-6-openjdk/bin/javac'.

    What about more deatiled verson information? /usr/bin/java-harmony -version reports:

    Apache Harmony Launcher : (c) Copyright 1991, 2010 The Apache Software Foundation or its licensors, as applicable.
    java version "1.5.0"
    Apache Harmony (1.5.0)
    DRLVM (1.5.0-r991518)
    pre-alpha : not complete or compatible
    svn = r991518, (Sep  7 2010), Linux/ia32/gcc 4.3.2, release build

    and /usr/bin/java-harmony-6.0 -version:

    Apache Harmony Launcher : (c) Copyright 1991, 2010 The Apache Software Foundation or its licensors, as applicable.
    java version "1.6.0"
    Apache Harmony (1.6.0)
    DRLVM (1.6.0-r991881)
    pre-alpha : not complete or compatible
    svn = r991881, (Sep  8 2010), Linux/ia32/gcc 4.3.2, release build


    • No alternatives for java-harmony nor javac-harmony
      What is the Debian alternatives system:

      The Debian alternatives system creates a way for several programs that fullfill the same or similar functions to be listed as alternative implementations that are installed simultaneously but with one particular implementation designated as the default.

      It’s a minor issue, though.

    • Both Harmony 5 and 6 use the same Java compiler
      /usr/bin/javac-harmony -version and /usr/bin/javac-harmony-6.0 -version report exactly the same version of the compiler:

      Eclipse Java Compiler 0.972_R35x, 3.5.1 release, Copyright IBM Corp 2000, 2009. All rights reserved.

      It seems to me as a quite serious issue, but what roadblocks to expect when cross-compiling and using different versions of compilers is a topic for another post.


    I don’t have enough time to play with, so there are not so much to say, except: Apache Harmony installs, works in some cases, and may be uninstalled with ease.

  • manandbytes 10:03 on April 7, 2011 Постоянная ссылка |
    Метки: java, , , shell   

    How to emulate Jenkin’s ‘matrix build’ in command line ad-hoc 


    Jenkins presents a concept of the multi-configuration project (AKA matrix project). This feature is useful when you would like to test your application in several environments (with different versions of JDK) or package it for different platforms.

    But what if you can’t use Jenkins for some reason? Scriptable shell comes to the rescue and here is a real-life example: I have to investigate an issue building a project in different environments (actually, for a combination of several versions of Maven2 and a number of different JDKs).


    So, I need two «axes» for my task:

    • version of Maven2. There are only 4 versions to run my tests against and I just enumerate all installations;
    • version of JDK. Thanks to a great package management system available in Debian, I still have Sun’s Java5 JDK installed. Not as a default one, however 😉 And Sun’s JDK 6 alongside OpenJDK 6… And some other are installed and removed occasionally. So I will just use find utility instead of enumerating all my JDK installations.


    for m in \
        ~/bin/apache-maven-2.1.0/bin/ /usr/share/maven2/bin/ ~/bin/apache-maven-3.0.2/bin/ ~/bin/apache-maven-3.0-SNAPSHOT/bin/ ; do \
        for j in `find /usr/lib/jvm/ -maxdepth 2 -type d -name bin` ; do \
            echo "-----" ; \
            export JAVA_HOME=$j/../ ; \
            $m/mvn -version ; \
            $m/mvn clean compile --quiet ; \
        done \

    Once executed, this runs given project using a) every version of Maven2 and b) for every Maven2 version using every JDK available. Output looks like:

    Apache Maven 2.1.0 (r755702; 2009-03-18 21:10:27+0200)
    Java version: 1.6.0_22
    Java home: /usr/lib/jvm/java-6-openjdk/jre
    Default locale: uk_UA, platform encoding: UTF-8
    OS name: "linux" version: "2.6.38-2-686-bigmem" arch: "i386" Family: "unix"
    Apache Maven 2.1.0 (r755702; 2009-03-18 21:10:27+0200)
    Java version: 1.5.0_22
    Java home: /usr/lib/jvm/java-1.5.0-sun-
    Default locale: uk_UA, platform encoding: UTF-8
    OS name: "linux" version: "2.6.38-2-686-bigmem" arch: "i386" Family: "unix"
    Apache Maven 2.1.0 (r755702; 2009-03-18 21:10:27+0200)
    Java version: 1.6.0_24
    Java home: /usr/lib/jvm/java-6-sun-
    Default locale: uk_UA, platform encoding: UTF-8
    OS name: "linux" version: "2.6.38-2-686-bigmem" arch: "i386" Family: "unix"

    Mission accomplished.

  • manandbytes 10:25 on June 30, 2010 Постоянная ссылка |
    Метки: java, jgit, netbeans   

    NBGit with the latest JGit 0.8.4 

    NBGit, a module for the NetBeans IDE that adds support for working with the Git version control system, still uses an age-old version of the JGit library. But now NBGit uses the latest JGit 0.8.4:

    • JGit’s JARs, license, credits etc were updated, all usages of org.spearce.jgit.* packages were changed to org.eclipse.jgit.*, two simple methods for test case were overrided, removed couple calls to org.eclipse.jgit.lib.Repository’s refreshFromDisk(). By the way, kudos to Shawn Pearce for great commit message😉
    • JCraft’s Jsch removed from the NBGit’s distribution because NetBeans 6.8+ provides ‘Java Secure Channel integration’ module that wraps up Jsch.

    I’ve pushed my changes to GitHub (yes, ‘build from the sources’ is the single option for now) and there are actually two changesets to be considered:

    Two screenshots of NBGit in action, on both NetBeans 6.8 and 6.9:

  • manandbytes 02:21 on June 20, 2009 Постоянная ссылка |
    Метки: ant, architecture-rules, java,   

    Architecture Rules eats his own dog food 

    While adding support for YAML configuration files I introduced a cyclic dependency (shame on me 🙂 ) in our code base. If this means nothing to you there are some reasons why introducing cycles considered as a bad practice.

    How to catch problems like this one?

    Sounds obviously for you? For sure 😉

    As the problem popped up as soon as it was introduced, fixing it was a trivial task. I absolutely agree with a statement that every piece of code becomes «legacy» few hours after it’s written. Distributed development teams make such things even worse. `Individuals and interactions over processes and tools’ don’t work.

    How did I discovered this? First of all, this post is about eating your own dog food, right? One of the purposes of Architecture Rules is to report on cyclic dependencies among your project’s packages and classes. And my build system was ready to catch this with just running mvn test.

    How this looks like? As a plain old unit test’s failure:

    Results :
    Tests in error:
    Tests run: 99, Failures: 0, Errors: 1, Skipped: 0

    In my case more details are in the target/surefire-reports/org.architecturerules.SimpleArchitectureTest.txt:

    Test set: org.architecturerules.SimpleArchitectureTest
    Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.54 sec <<< FAILURE!
    testArchitecture(org.architecturerules.SimpleArchitectureTest)  Time elapsed: 0.532 sec  <<< ERROR!
    org.architecturerules.exceptions.CyclicRedundancyException: 2 cyclic dependencies found:
    	-- org.architecturerules.configuration.xml depends on 
    	|  |
    	|  |-- org.architecturerules.configuration
    	|	 |-- @ org.architecturerules.configuration.xml.DigesterConfigurationFactory
    	|	    \ while 
    	|	     |-- org.architecturerules.configuration.DefaultConfigurationFactory
    	|	       \ depends on org.architecturerules.configuration.xml
    	-- org.architecturerules.configuration depends on
    	|  |
    	|  |-- org.architecturerules.configuration.xml
    	|	 |-- @ org.architecturerules.configuration.DefaultConfigurationFactory
    	|	    \ while 
    	|	     |-- org.architecturerules.configuration.xml.DigesterConfigurationFactory
    	|	       \ depends on org.architecturerules.configuration
    	at org.architecturerules.services.CyclicRedundancyServiceImpl.buildCyclicRedundancyException(CyclicRedundancyServiceImpl.java:162)
    	at org.architecturerules.services.CyclicRedundancyServiceImpl.performCyclicRedundancyCheck(CyclicRedundancyServiceImpl.java:117)
    	at org.architecturerules.AbstractArchitectureRulesConfigurationTest.doTests(AbstractArchitectureRulesConfigurationTest.java:143)
    	at org.architecturerules.SimpleArchitectureTest.testArchitecture(SimpleArchitectureTest.java:51)

    Thanks to our Maven 2 plugin your build will fail too as soon as you introduce cycles in a dependency graph. Even if your project uses Apache Ant (sorry, it’s not my favorite tool 😉 ) as a build system, you can download and use our Ant task to get the same result.

    How-to setup Ant task? Sorry, it’s still not available and I have any clue. In a response to this post Mike provided this great how-to install and configure guide. Thank you, Mike!

  • manandbytes 14:07 on May 13, 2007 Постоянная ссылка |
    Метки: java   

    CruiseControl сэкономил $12,535? 

    Continuous Integration in the enterprise with CruiseControl:

    About 30 minutes after installation was complete, we had our first build breakage. Something was wrong. The build was broken. In the past, this type of bug usually wasn’t discovered for months. In the past, this bug would have lingered in the code for 6 months before anyone even realized it was a problem. But now, there was a simple, red light, flashing continuously, to let everyone know there was a problem. The light had gone off only 6 minutes after the code had been committed. Notice: not 6 months…but 6 minutes! Needless to say, the managers scurried to my cube. They wanted to know what this disruption was all about. I told them I just saved them $12,535!

cоздать новую запись
следующая запись/комментарий
предыдущая запись/комментарий
показать/скрыть комментарии
перейти наверх
Go to login
Показать/Скрыть помощь
shift + esc