Annotations com Spring 2.5 + Thinlet

O Spring Framework a partir de sua versão 2.5 introduziu uma quantidade considerável de annotations a disposição do desenvolvedor. Ainda é possível usar a configuração clássica em XML, mas agora além dos recursos de anotações é possível mesclar os dois no mesmo código.

Vou demonstrar através de um exemplo simples utilizando como GUI o Thinlet. O Thinlet é uma biblioteca que permite a criação de GUI através de definição em XML da interface, como se fosse um XUL, o que dá muita flexibilidade. O projeto de GUI está meio parado, acho que o ultimo release foi em 2005, mas mesmo assim, é uma biblioteca simples de se usar e principalmente muito leve.

Foi utilizado o Spring Framework 2.5 mas pode ser usado qualquer versão do mesmo sendo 2.5.x. Vamos ver como utilizar algumas anotações que o Spring introduziu aos seus usuários. Também vou abordar como integrar o uso dessas anotações com o desenvolvimento em XML clássico.



Dependências:
  • spring framework 2.5.x
  • commons-logging
  • spring-aspects
  • aspectjrt
  • thinlet
Todas as dependências exceto o Thinlet podem ser encontradas na pasta do Spring 2.5 se você baixou a versão com dependências.

A Definição da GUI via o Thinlet segue a baixo. Você deve chamar esse arquivo de
Calculator.XML.







Eu criei o Enumeration Operation para a representação das operações da calculadora. Segue o código a baixo.

package com.blogspot.diegopacheco.thinletspring25;

/**
* Enum que define as operações matematicas.
*
* @author Diego Pacheco
* @version 1.0
*/
public enum Operation {

SOMA {
return 0;
}
},
SUBTRACAO {
public int getValue() {
return 1;
}
},
DIVISAO {
public int getValue() {
return 2;
}
},
MULTIPLICACAO {
public int getValue() {
return 3;
}
};

public int getValue() {
return -1;
}
}

Para realizar as operações matemáticas eu criei um Service e chamei de CalculatorService. Segue a baixo.

pre
package com.blogspot.diegopacheco.thinletspring25;

import org.springframework.stereotype.Component;

/**
* Classe de Serviço da Calculadora
*
* @author Diego Pacheco
* @version 1.0
*/
@Component
public class CalculatorService {

public Double calculate(Double v1, Double v2, Operation op) {

Double result = 0d;

switch (op.getValue()) {
case 0:
result = v1 + v2;
break;
case 1:
result = v1 - v2;
break;
case 2:
result = v1 / v2;
break;
case 3:
result = v1 * v2;
break;

default:
throw new RuntimeException("A operacao[" + op
+ "] não é suportada pelo service.");
}

return result;
}
}

Esse Service possui o método calculate que recebe dois Double como parâmetros mais uma objeto do tipo Operation que é a operação que deve ser efetuada, a partir da instância do objeto de Operation o serviço decide qual operação deve ser efetuada.

@Component: Aqui que começa a brincadeira. Com essa anotações estamos dizendo para o Spring que essa classe é um componente, logo se a mesma for scaneada ela irá para a BeanFactory do Spring. Isso é o mesmo que fazer a declaração do Bean no xml informando id e class. Por default o id do bean será o nome da classe, mas essa informação pode ser modificada.

Agora vamos a tela. Classe Calculator

package com.blogspot.diegopacheco.thinletspring25;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import thinlet.Thinlet;

/**
* Esse é um gui definido atres do Thinlet.
* @author Diego Pacheco
* @version 1.0
*/
@Component(value="calc")
public class Calculator extends Thinlet {

private static final long serialVersionUID = 1L;

@Autowired
private CalculatorService cs;

public Calculator() throws Exception {
add(parse(Calculator.class.getSimpleName() + ".xml"));
}

public void calculate(String number1, String number2, String operation, Object result) {
try {
Double v1 = Double.parseDouble(number1);
Double v2 = Double.parseDouble(number2);

Operation op = null;
if("+".equals(operation)){
op = Operation.SOMA;
}else if("-".equals(operation)){
op = Operation.SUBTRACAO;
}else if("/".equals(operation)){
op = Operation.DIVISAO;
}else if("*".equals(operation)){
op = Operation.MULTIPLICACAO;
}

setString(result, "text", String.valueOf(cs.calculate(v1, v2,op)));
} catch (NumberFormatException nfe) {
getToolkit().beep();
}
}    

public CalculatorService getCs() {
return cs;
}
public void setCs(CalculatorService cs) {
this.cs = cs;
}    
}

@Component(value="calc"): Com isso estamos declarando que a classe Calculator é um componente no Spring, ou seja, um bean no contexto do Spring. Com o parametro value estou disendo que o identificador desse componente é "calc" que é na verdade o id do bean.

@Autowired private CalculatorService cs;: Com essa anotação estou fazendo uma injeção de dependências, como eu usei !Autoeired o spring ira aplicar auto-wire by type, nesse exemplo não exite problema pois estou lidando direto com a classe concreta porem cuidado com esse recurso ele pode dar muitas dores de cabeça se for usado impropriamente.

Para rodar a aplicação crie a classe MainApp. Segue a baixo.

package com.blogspot.diegopacheco.thinletspring25;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* Classe de entrada para aplicação.
* @author Diego Pacheco
* @version 1.0
*/
public class MainApp {
public static void main(String[] args) throws Exception{
ApplicationContext ac =  new ClassPathXmlApplicationContext("classpath:spring-beans.xml");
ac.getBean("frameLauncherPrincipal");         
}
}

Nessa classe o contexto do Spring é subido. E um bean é recuperado do contexto. Você ira entender mais sobre o que está aconetcendo no proximo tópico que é o contexto do spring.

spring-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"    
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"    
xsi:schemaLocation="http://www.springframework.org/schema/beans                              
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd                          
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"                                  
default-autowire="no"
default-dependency-check="none"
default-lazy-init="true"
>         
<context:annotation-config/>    
<context:spring-configured/>
<context:component-scan base-package="com.blogspot.diegopacheco" annotation-config="true" />    

<bean
id="frameLauncherPrincipal"
class="thinlet.FrameLauncher"
lazy-init="true"
>
<constructor-arg index="0" value="Calculatora Simples" />
<constructor-arg index="1">
<ref bean="calc" />
</constructor-arg>
<constructor-arg index="2" value="300" />
<constructor-arg index="3" value="80" />
</bean>

</beans>

Esse é o clássico xml de beans do Spring. Vocês podem notar de novo os nodos:

<context:annotation-config/>
<context:spring-configured/>
<context:component-scan base-package="com.blogspot.diegopacheco" annotation-config="true" />

Esses são os nodos necessários para o uso de anotações no Spring. Um recurso muito legal que o Spring introduziu é o context:compoment-scan com esse recurso o spring passa um scanner no seu class-path a procura de beans. Adivinhe que beans ele ira adicionar ao contexto? Ele irá adicionar o que contem a acontação @Component.

No final é definido o bean thinlet.FrameLauncher que é um utilitário do Thinlet para iniciar as aplicações. Ele foi definido como um bean normal do Spring, porem foi feito via constructor injection a injeção do bean "calc" que na verdade ira ser carregado pela scanner do Spring. Dessa forma conseguimos injetar beans oriundos de XML ou anotações, no spring 2.5 isso tudo é transparente.

Ainda existem muitos recursos no Spring 2.5 em relação a anotações. Vale a pena conferir. Mas por hoje é só. :)

Popular posts from this blog

Telemetry and Microservices part2

Installing and Running ntop 2 on Amazon Linux OS

Fun with Apache Kafka