Monday, January 28, 2013

Como copiar as dependências do projeto com o Maven

Copiar os jars que o projeto depende, pode ser necessário dependendo do tipo do projeto, como desktop (Swing). O objetivo principal, seria simplificar a distribuição dos artefatos dessa projeto. Com o Maven é possível copiar todas as dependências (jars) do projeto para um diretório central.

Isso pode ser feito com o plugin dependency e o goal copy-dependencies. Veja um exemplo:
yaw-projeto$ mvn dependency:copy-dependencies

O Maven cria a pasta dependency, dentro de target (distribuição do projeto), e coloca lá todos os jars dependentes do projeto.

Saiba mais detalhes sobre essa funcionalidade na documentação oficial do Maven.

@edermag

Wednesday, January 16, 2013

Insert em table c/ id auto incremento utilizando JdbcTemplate do Spring JDBC

A classe JDBCTemplate é parte do Spring JDBC, utilizada para reduzir o volume de instruções/código na definição dos comandos para o banco de dados, executado via JDBC.

A seguir um trecho de código com um DAO para entidade Cliente, que demonstra como é simples utilizar o insert via JdbcTemplate:

import org.springframework.jdbc.core.JdbcTemplate;

public class ClienteDAO {
  
  private JdbcTemplate jdbcTemplate; //set p/ injecao...

  public void insert(Cliente clie) {
    final String sql = "INSERT INTO CLIENTES(NOME, CPF) VALUES (?, ?)";

    jdbcTemplate.update(sql, new Object[] { clie.getNome(), clie.getCpf() });
  }
}

É muito comum que o ID (chave primária) de um registro seja gerado pelo banco de dados. No MySQL isso é possível com o auto incremento, no caso do Oracle é possível via SEQUENCE.

A versão do método insert a seguir, demonstra como realizar o comando com JdbcTemplate e recuperar o ID gerado pelo banco através do KeyHolder. Utilizo a sobrecarga do método update, informando o PreparedStatementCreator do Spring MVC (gerador de PreparedStament).

  public void insert(final Cliente clie) {
    final String sql = "INSERT INTO CLIENTES(NOME, CPF) VALUES (?, ?)";

    PreparedStatementCreator psc = new PreparedStatementCreator() {
      @Override
      public PreparedStatement createPreparedStatement(Connection con)
        throws SQLException {
        //indico a coluna com valor gerado pelo banco de dados
        PreparedStatement ps = con.prepareStatement(sql, new String[] { "id" });

        //preencho os parametros (?, ?)
        ps.setString(1, clie.getNome());
        ps.setString(2, clie.getCpf());

        return ps;
      }
    }
    //recupera o valor gerado para o id
    KeyHolder keyHolder = new GeneratedKeyHolder();

    jdbcTemplate.update(psc, keyHolder);

    //atualizo a informacao do id, no objeto cliente
    cliente.setId(keyHolder.getKey().intValue());

  }

O detalhe é que durante a criação do PreparedStament, em Connection, eu passo o argumento com o nome da coluna gerada via auto incremento/SEQUENCE, nesse caso o "id". Esse código funciona com Oracle e MySQL.

@edermag

Monday, January 14, 2013

Como ler o arquivo MANIFEST.MF da própria aplicação

Uma aplicação Java, indepentende do tipo (web, server ou desktop), ao ser empacotada (build) deve distribuir junto com o artefato um arquivo com informações sobre o build. O arquivo MANIFEST.MF contido no diretório META-INF.

Nesse post, vou demonstrar como é possível ler o arquivo MANIFEST.MF da própria aplicação. Essa é uma implementação é muito simples, mas existe um importante detalhe.

Ao ler o MANIFEST.MF, o Java considera todos os jars disponíveis no classpath da aplicação. Por isso é importante criar algo que identifique o jar correto. Nesse exemplo vou considerar a propriedade Built-By.

import java.net.URL;
import java.util.Enumeration;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

public class ApplicationProperties {

  private static Manifest manifest;

  static {
    try {
      Enumeration<URL> resources = ApplicationProperties.class.getClassLoader()
        .getResources("META-INF/MANIFEST.MF");

      while (resources.hasMoreElements()) {
        Manifest m = new Manifest(resources.nextElement().openStream());
        if ("YaW Tecnologia".equalsIgnoreCase(
              m.getMainAttributes().getValue("Built-By"))) {
          manifest = m;
          break;
        }
      }
    } catch (Exception e) {
      System.err.println("Não foi possível ler o manifest do projeto: "
        +e.getMessage());
    }
  }

  /**
   * @return null se não encontrar o arquivo.
   */
  public static Manifest getManifestFile() {
    return manifest;
  }
}

Vale notar que a estratégia em usar o Built-By torna-se inválida quando existir mais do que um jar empacotado, por YaW Tecnologia, no classpath.

@edermag

Thursday, January 10, 2013

Gerar MANIFEST.MF no Maven com informações do Git

O arquivo MANIFEST.MF tem como finalidade armazenar atributos sobre o artefato (JAR / WAR / EAR ...). Informações como a versão, as dependências, desenvolvedores, a classe de entrada (para JARs executáveis), ou seja, qualquer informação relevante para a instalação e uso do artefato.

Por padrão, quando um JAR é gerado o MANIFEST.MF é criado automaticamente, dentro da pasta META-INF. Nesse post eu demonstro como utilizar o Maven para criar o MANIFEST.MF com informações e dinâmicas e pré-definidas. Uma informação dinâmica seria, por exemplo, a identificação do último commit realizado no sistema de controle de fontes, o git.

O plugin do Maven buildnumber gera um identificador de build (build number) acessando informações do SCM (svn / git / mercurial). Por exemplo, durante o desenvolvimento pode existir diversar iterações (e commits) para a mesma versão 1-0-SNAPSHOT. Com o plugin é possível aumentar a granularidade na identificação da versão/build do artefato.

Uma vez que o valor do build number é gerado, o plugin jar acessa essa informação para criar o artefato. Esse é o plugin em que definimos a estrutura do MANIFEST.MF que o Maven deve utilizar.

A seguir um exemplo de pom.xml com a url do git e as definições para o Maven criar o MANIFEST.MF:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>br.com.yaw.sjc</groupId>
  <artifactId>swing-jdbc-crud</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>swing-jdbc-crud</name>
  <url>http://maven.apache.org</url>

  <!-- Defino alguma propriedades, que serao utilizadas para o Manifest  -->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.title>Demo Swing c/ JDBC</project.title>
    <user.name>YaW Tecnologia</user.name>
    <site>http://www.yaw.com.br</site>
  </properties>

  <dependencies>
    <!-- omiti os trechos com as dependencias -->
  </dependencies>

  <!-- Url para o respositorio git (github), utilizada pelo buildnumber -->
  <scm>
    <connection>scm:git:https://github.com/yaw/swing-jdbc-crud.git</connection>
  </scm>

  <!-- Configuracoes (c/ plugins) para geracao do jar -->
  <build>
    <plugins>
      <!-- Plugin buildnumber, executado durante a fase validation -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>buildnumber-maven-plugin</artifactId>
        <version>1.1</version>
        <executions>
          <execution>
            <phase>validate</phase>
            <goals>
              <goal>create</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

      <!-- Plugin jar -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.1</version>
        <configuration>
          <archive>
            <manifest>
              <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
            </manifest>
            <manifestEntries>
              <!-- Atributos para o Manifest -->
              <Built-By>${user.name}</Built-By>
              <Implementation-Title>${project.title}</Implementation-Title>
              <!-- Aqui ele usa o buildNumber -->
              <Implementation-Build>${buildNumber}</Implementation-Build>
              <Implementation-Site>${site}</Implementation-Site>
            </manifestEntries>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>


Esse pom.xml foi baseado no projeto demontração Swing e JDBC, desenvolvido pela YaW.

@edermag

Wednesday, January 09, 2013

Compilar o projeto com Maven 3 e Java 7

Se você trabalha com várias JVMs, ou compila projetos em diferentes versões do Java com a mesma instância de Maven, você precisa indicar ao Maven qual é a versão do Java durante a compilação.

Para compilar um projeto com Maven 3, utilizando o Java 7, você pode configurar alguns paramêtros para o plugin de compilação.

A seguir um exemplo de como configurar o plugin compile, do Maven, para compilar o projeto utilizando o Java 7. Nesse caso as configurações são feitas no pom.xml:

<project>
  ...
  <build>
    ...
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>

Na página do plugin compile é possível visualizar maiores detalhes sobre o plugin.

@edermag