Andrew E. Bruno
A sourceful of secrets

Archive for the 'Java' Category

Creating executable jars with Maven

Thursday, January 24th, 2008

After wrestling with Maven assemblies for while I finally figured out how to build executable jars. The Maven assembly plugin allows you to define ways to package up your project for distribution by creating various assembly descriptor files. Here's a quick example of a Maven assembly for building an executable jar (uberjar). For this example we'll create a brand new project from scratch but it should be easy to see how to integrate into an existing project.

First step lets create a test project:

$ mvn archetype:create -DgroupId=org.qnot.example -DartifactId=hello-world
$ cd hello-world

Next add a few dependencies to the project. In this example we'll add a few libraries from jakarta commons. The <dependencies/> section in the pom.xml should now look like this:

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>commons-cli</groupId>
      <artifactId>commons-cli</artifactId>
      <version>1.1</version>
    </dependency>
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.3</version>
    </dependency>
  </dependencies>

Create a META-INF/ directory to store the MANIFEST.MF file which defines the main class in the executable jar.

$ mkdir -p src/main/resources/META-INF/
$ echo 'Main-Class: org.qnot.example.App' > MANIFEST.MF

Create a src/assemble directory to store the assembly descriptor files

$ mkdir src/assemble

Next we'll create the actual assembly descriptor file which defines how to package up the jar. Create the file src/assemble/exe.xml with the following xml:

<assembly>
  <id>exe</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <outputDirectory></outputDirectory>
      <outputFileNameMapping></outputFileNameMapping>
      <unpack>true</unpack>
      <scope>runtime</scope>
      <includes>
        <include>commons-lang:commons-lang</include>
        <include>commons-cli:commons-cli</include>
      </includes>
    </dependencySet>
  </dependencySets>
  <fileSets>
    <fileSet>
      <directory>target/classes</directory>
      <outputDirectory></outputDirectory>
    </fileSet>
  </fileSets>
</assembly>

Inside the <dependecySets/> is where you can add all the libraries you'd like to include in the uberjar. These must also be defined in your pom.

Finally, add the maven-assembly-plugin to the pom:

  <build>
    <finalName>hello-world</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptors>
            <descriptor>src/assemble/exe.xml</descriptor>
          </descriptors>
          <archive>
            <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

To run the assembly and build the executable jar:

$ mvn assembly:assembly
$ java -jar target/hello-world-exe.jar
Hello World!

I tested the hello-world example using the latest Maven release (2.0.8) and maven-assembly-plugin-2.2-beta-1. If you run into any issues try and update your Maven plugins by running:

$ mvn -U compile

You can download the example hello-world project here.

Rotate Labels JFreeChart

Tuesday, August 14th, 2007

When creating a chart that has rather long labels for the x-axis it is sometimes desirable to rotate them a bit so they fit on the plot. The method to use is setCategoryLabelPositions(..) on the CategoryAxis class. Here's a quick example:

And the code..

import java.io.File;
import java.io.IOException;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.ChartColor;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.data.category.DefaultCategoryDataset;

public class RotateLabels {
    public static void main(String[] args) {
        DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
        dataSet.addValue(51, "series", "Colonel Forbin");
        dataSet.addValue(92, "series", "The Lizards");
        dataSet.addValue(33, "series", "Wilson");
        dataSet.addValue(77, "series", "Rutherford the Brave");
        dataSet.addValue(37, "series", "The Unit Monster");
        dataSet.addValue(97, "series", "The Famous Mockingbird");
        dataSet.addValue(67, "series", "Poster Nutbag");

        JFreeChart chart = ChartFactory.createBarChart(
            "Gamehendge",
            null,
            null,
            dataSet,
            PlotOrientation.VERTICAL,
            false,
            false,
            false
        );

        CategoryPlot plot = (CategoryPlot)chart.getPlot();
        CategoryAxis xAxis = (CategoryAxis)plot.getDomainAxis();
        xAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);

        chart.setBackgroundPaint(ChartColor.WHITE);
        try {
            ChartUtilities.saveChartAsPNG(new File("chart.png"), chart, 400, 300);
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

MySQL bigint types and iBATIS

Monday, July 16th, 2007

One nuance I recently ran into while using iBATIS was inserting data into MySQL bigint unsigned columns. iBATIS doesn't seem to have a way to handle BigInteger data types and throws an exception when attempting to do an insert. Fetching data out seemed to work OK because if iBATIS doesn't know how to handle a certain type it just returns a java.lang.Object. The way to go about inserting BigInteger types is to set up a type handler. Here's an example type handler for BigInteger types:

package org.qnot.util;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.sql.Types;

import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;

public class BigIntegerTypeHandler implements TypeHandlerCallback {

    public Object getResult(ResultGetter getter) throws SQLException {
        if(getter.wasNull()) {
            return null;
        }

        Object o = getter.getObject();
        if(o instanceof BigDecimal) {
            BigDecimal bd = (BigDecimal)o;
            return bd.toBigInteger();
        } else if(o instanceof BigInteger) {
            return (BigInteger)o;
        } else {
            return o;
        }
    }

    public void setParameter(ParameterSetter setter, Object parameter)
            throws SQLException {
        if (parameter == null) {
            setter.setNull(Types.BIGINT);
        } else {
            BigInteger i = (BigInteger) parameter;
            setter.setBigDecimal(new BigDecimal(i));
        }
    }

    public Object valueOf(String s) {
        return s;
    }
}

Then all you have to do is register the type handler in your sqlmap-config.xml file like so:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
    <settings useStatementNamespaces="true" />
    <typeHandler javaType="java.math.BigInteger" 
                 callback="org.qnot.util.BigIntegerTypeHandler"/>
    <sqlMap resource="sql/example.xml"/>
</sqlMapConfig>

Converting MIF to XML - Java Version

Wednesday, January 31st, 2007

In my previous post I discussed a tool called mif2xml for converting MIF files to an intermediate XML dialect. In this post I'll talk about the Java port of mif2xml called mif2xml-j which you can download here including just the executable jar or browse the source online via svn.

JFlex is a lexical analyzer generator for Java and is the library I chose to use for creating the MIF lexer. The first step was to get JFlex integrated into my build environment. For this project I decided to use ant but integrating JFlex into another build environment ...Read the rest of this entry »