Top Posts

MundoJ: RedMine Bug-Tracking

Continue lendo

Série Spring: Spring AOP com annotations

Posted by camilolopes | Posted in Series, Spring | Posted on 10-05-2013

1

 

Olá Pessoal,

No post de hoje vamos ver como usar annotations   para AOP é bem simples.Já vimos aqui  com XML e agora vamos para o que há de melhor  desde do Java 5 que é o uso de Annotations.

Lets go…

 Starting

O post é bem curto e procurei  ser bem objetivo, então considerando que você já tem seu arquivo de spring configurado  para usar aop, vamos apenas atualizar para habilitar o recurso de annotations  e aproveitei removi os beans  usando auto-discovering do Spring. Vamos começar pela configuração do arquivo springconfiguration.xml (o nome que dei ao meu arquivo de configuração).

Antes disso, crie um projeto novo e dê o nome que quiser.

Note: lembre-se de adicionar os .jars do Spring, AOP e AspectJ ao projeto:

 springaopannotationsproject

Configurando .xml do Spring

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xmlns:context=“http://www.springframework.org/schema/context”

xmlns:aop=“http://www.springframework.org/schema/aop”

xsi:schemaLocation=“http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.2.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.2.xsd”>

 <context:component-scan base-package=“*”/>

<aop:aspectj-autoproxy/>

 </beans>

 

Deixei seu arquivo de configuração assim. A única coisa nova de aop, foi que adicionar a linha <aop:aspectj-autorproxy/>  que nos permite usar annotations.

Criando o bean

A seguir vamos criar o bean , nada demais neles:

@Component

@Scope(value=”prototype”)

public class Student {

      private String name;

//    this is DI via annotations

      @Autowired

      private Course course;

      public String getName() {

            return name;

      }

      public void setName(String name) {

            if (name==null) {

                  throw new IllegalArgumentException();

            }

            this.name = name;

      }

      public Course getCourse() {

            return course;

      }

      public void setCourse(Course course) {

            this.course = course;

      }     

      public void teste(){           

      }

}

O outro bean:

@Component

public class Course {

      private String nameCourse; 

      public String getNameCourse() {

            return nameCourse;

      } 

      public void setNameCourse(String nameCourse) {

            this.nameCourse = nameCourse;

      } 

}

 

Agora vamos criar uma classe que será responsável  por registrar uma mensagem antes;após de determinados métodos, ou seja, as regras do AOP estarão aqui:

@Aspect

@Component

public class Audit {

//    aqui com o metodo especifico

      @Pointcut(“execution(* br.com.camilolopes.bean.Student.setName(..))”)

      public void aopteste(){} 

      @Pointcut(“execution(* br.com.camilolopes.bean.Course.setNameCourse(..))”)

      public void aopcourse(){}     

      @Pointcut(“execution(* *.*test*(..))”)

      public void aopanywhere(){}     

      @AfterReturning(“aopteste()”)

      public void register(){

            System.out.println(“Student registred”);

      }

      @After(“aopcourse()”)

      public void finished(){

            System.out.println(“Course finished”);

      }

      @AfterThrowing(“aopteste()”)

      public void problem(){

            System.out.println(“Happened problem here”);

      }

      @Before(“aopteste()”)

      public void starting(){

            System.out.println(“application is starting…”);

      }

      @AfterReturning(“aopanywhere()”)

      public void anywhere(){

            System.out.println(“anywhere test”);

      }

}

Observe que anotei a classe com @Component para que o Spring saiba que precisa registrar ela no contexto. Caso contrário, nada rola. Agora vamos entender os pointcuts criados:

  • Primeiro: criamos um pointcut que sempre será chamado quando um método especifico for chamado nesse caso o método  setName da classe Student.
  • Segundo: o mesmo que acima, exceto que para a classe Course.
  • Terceiro :  agora criamos um que estou dizendo: “de qualquer lugar da aplicação e qualquer método que comece com test e terminar com qualquer coisa.

E  os métodos a seguir é o que serão chamados  com base no que tipo de anotação que definimos, observe que temos um que será chamado apenas no caso de acontecer uma exceção quando no método setName da classe Student.

Testando

Para testar aplicação criei uma classe de teste

Classe de Test

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={“classpath:config/springconfiguration.xml”})

public class StudentTest {

      @Autowired

      private Student student;

      @Before

      public void setUp() throws Exception {

      } 

      @Test

      public void testNameCourse() {

            student.getCourse().setNameCourse(“TDD”);

            assertEquals(“TDD”,student.getCourse().getNameCourse());

      }     

      @Test

      public void testNameStudent(){

            student.setName(“Camilo”);

            assertEquals(“Camilo”, student.getName());

            student.teste();

      }

      @Test(expected=IllegalArgumentException.class)

      public void testNameIsNullException(){

            student.setName(null);

      }

}

Resultado:

resultaopunittest

Classe com o método main

Fiz uma pequena classe com método main, para quem não sabe unit test:

public class MainTest {

      public static void main(String[] args) {

            ApplicationContext  applicationContext = new ClassPathXmlApplicationContext(“config/springconfiguration.xml”);

            Student bean = (Student) applicationContext.getBean(“student”);

            bean.setName(“lopes”);

            bean.teste();           

      }

} 

O resultado será diferente pq as inovações são diferentes:

resultadoaopmaintest

 

Bom, pessoal. Vou ficando por aqui e espero que tenham gostado do post.

Abraços,

Série Spring: CRUD Spring 3 + Hibernate + Unit Tests

Posted by camilolopes | Posted in Series, Spring | Posted on 01-05-2013

0

Olá Pessoal,

No post de hoje veremos como fazer um simples CRUD usando o Spring, integrando com Hibernate e testando via unit tests com JUNIT4. No último posts vimos apenas uma integração com o Hibernate e também um CRUD usando HibernateTemplate, esse aqui  veremos que na versão 3 do Spring não precisamos mais do HiberanteTemplate e vamos testar nosso código com unit test.

Lets go…

Starting…

Primeiro passo é que  estarei assumindo que você já tem .jars necessário  para o ambiente. Já que esse não é o primeiro post da série, caso contrário terá que baixar os .jars para: driver Mysql 5, Hibernate 3.6, AOP, AspectJ, Spring 3.x.

Antes de começarmos a desenvolver, vamos primeiro estruturar nosso projeto e packages conforme a imagem a seguir:

springrentcarproject

Nosso CRUD será o cadastro  de veículos  que serão alugados. Claro que há muito mais regras de negócios do que a que veremos no exemplo a seguir, porém o nosso objetivo é explorar o framework Spring e não tratar todas as regras de negócio em um post.

  1. Crie a estrutura conforme a imagem acima
  2. Crie o arquivo de configuração de Spring, o qual chamei de springconfiguration.xml, e coloque dentro do package config.
  3.    Agora vamos colocar a carne no nosso XML

Cabeçalho fica assim:

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xmlns:context=“http://www.springframework.org/schema/context”

xmlns:tx=“http://www.springframework.org/schema/tx”

xmlns:aop=“http://www.springframework.org/schema/aop”

xsi:schemaLocation=“http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.2.xsd”>

 

Estarei comentando mais na frente ou in line apenas o que  ainda não foi abordado nos posts anteriores.

O cara que busca os beans: 

<context:component-scan base-package=“*”/>

 Colocando translation

<!– esse cara faz as traduções das exception checked para as unchecked do Spring –>

<bean class=“org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor”/>

Data source

<!– pelo nome diz, data source para conexão com o DB –>

<bean id=“dataSource” class=“org.springframework.jdbc.datasource.DriverManagerDataSource”>

<property name=“driverClassName” value=“com.mysql.jdbc.Driver”/>

<property name=“url” value=“jdbc:mysql://localhost/test”/>

<property name=“username” value=“root”/>

<property name=“password” value=“camilo2593”/>

</bean>

 

Configurando a SessionFactory

<!– Aqui estamos definido como será a parte de persistêcia, e dizemos que faremos via annotation –>

<bean id=“sessionFactory” class=“org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”>

<!– informando a quem estaremos conectado –>

<property name=“dataSource” ref=“dataSource”/>

<!– dizendo onde estão as classes dominio, ele saberá devido anotação @Entity  –>

<property name=“packagesToScan” value=“br.com.camilolopes.rentcar.domain.bean”/>

<!– configurando coisas especificas do Hibernate –>

<property name=“hibernateProperties”>

<props>

<prop key=“hibernate.dialect”>org.hibernate.dialect.MySQL5InnoDBDialect</prop>

<prop key=“hibernate.hbm2ddl.auto”>update</prop>

</props>

</property>

</bean>

 

Definindo Transaction

 <!– definindo quem vai gerenciar as transaction, ou seja, será o Hibernate –>

<bean id=“transactionManager” class=“org.springframework.orm.hibernate3.HibernateTransactionManager”>

<property name=“sessionFactory” ref=“sessionFactory”/>

</bean>

</beans>

Há duas formas de declararmos as transaction no Spring por XML ou Annotation.  Veremos as duas formas, no nosso caso de usarmos o XML faremos com AOP e você entenderá o  motivo:

Via XML

<!– todo medoto que começa com add é required uma transaction –>

<tx:advice id=“txAdvice”>

<tx:attributes>

<tx:method name=“add*” propagation=“REQUIRED”/>

<tx:method name=“update*” propagation=“REQUIRED”/>

<tx:method name=“*” propagation=“SUPPORTS” read-only=“true”/>

</tx:attributes>

</tx:advice>

<!– toda classe que extends a interface terá uma referência para o advisor –>

<aop:config>

<aop:advisor pointcut = “execution(* *..RentCar.*(..)))” advice-ref=“txAdvice”/>

</aop:config>

 

Em alguns contexto dessa forma é bem mais prático que usar Annotations.

 

Via annotation

Remove todo o código XML acima e apenas adiciona a seguinte linha:

<tx:annotation-driven/>

 

Claro que teremos que anotar nas classes/métodos como @Transaction e informar como esse deve se comportar , seguindo o exemplo do XML acima seria algo  assim:

@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)

public class myClass{  }

 

Normalmente você colocaria isso na camada de serviço.Mas, se você está brincando  e não tem uma camada de serviço, pode colocar direto no DAO.

E o método que faria uma das operações de banco ficaria assim:

@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)

      public void save(Car car) {

            getCurrentSession().save(car);}

 

No nosso exemplo vamos não vamos usar Annotations e exploraremos o benefício de usar a versão do XML conforme acima, se vc deixar a tag para annotation no arquivo de configuração o Spring não vai se importar com isso.

Desenvolvimento

Após toda essa configuração, vamos agora desenvolver nossas classes .java. Começando pela classe de domínio:

@Entity

@Table(name=”CARS”)

public class Car implements Serializable{

private static final long serialVersionUID = -2896368465389020843L;

      @Id

      @GeneratedValue

      private Long id;

      private String manufacter;

      private String description;

      private BigDecimal marketValue;

                //getters/setters omitidos

Basicamente isso .

Interface DAO

public interface RentCarDAO {

      void save(Car car);

      List<Car> findAll();

      List<Car> findAllByDescription(String description);

      void update(Car car);

      void delete();

}

Implementação da Interface:

@Repository

public class RentCarDAOImpl implements RentCarDAO {

      @Autowired

      private SessionFactory sessionFactory;

      public Session getCurrentSession(){

            return sessionFactory.getCurrentSession();

      }

      @Override

      public void save(Car car) {

            getCurrentSession().save(car);

      }

      public void setSessionFactory(SessionFactory sessionFactory) {

            this.sessionFactory = sessionFactory;

      }

      @Override

      public List<Car> findAll() {

            return getCurrentSession().createCriteria(Car.class).list();

      }

      @Override

public List<Car> findAllByDescription(String description) {

Criteria createCriteria = getCurrentSession().createCriteria(Car.class);

createCriteria.add(Restrictions.ilike(“description”, description));

            return (List<Car>) createCriteria.list();

      }

      @Override

      public void update(Car car) {

            getCurrentSession().update(car);

      }

      @Override

      public void delete() {

Query query = getCurrentSession().createQuery(“delete from Car where id >0”);

            query.executeUpdate();

      }

Interface de Serviço

@Service

public interface RentCar {

      void addNewCar(Car car);

      List<Car> findAll();

      List<Car> findCarByDescription(String description);

      void updateCar(Car car);

      void delete();

}

Classe que implementa o Serviço

@Service

public class RentCarServiceImpl implements RentCar {

      @Autowired

      private RentCarDAO rentCarDAO;

      @Override

      public void addNewCar(Car car) {

            rentCarDAO.save(car);

      }

      public void setRentCarDAO(RentCarDAO rentCarDAO) {

            this.rentCarDAO = rentCarDAO;

      }

      @Override

      public List<Car> findAll() {           

            return rentCarDAO.findAll();

      }

      @Override

      public List<Car>findCarByDescription(String description) {

           return (List<Car>) rentCarDAO.findAllByDescription(description);

      }

      @Override

      public void updateCar(Car car) {

            rentCarDAO.update(car);

      }

      @Override

      public void delete() {

      rentCarDAO.delete();     

      }

}

 

Unit Test

Se não reparou quando criou o projeto, temos um source  apenas  para os unit tests, conforme a imagem a seguir:

springrentcarunittestssource

Agora crie a classe de teste. A seguir mostrarei apenas dois simples testes, você deve criar os demais para validar os cenários, não coloquei todos para não ficar mais longo ainda o post.

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={“classpath:config/springconfiguration.xml”})

public class RentCarServicesTest {

      @Autowired

      private RentCar rentCarServicesImpl;

      private Car car;

      @Before

      public void setUp() throws Exception {

            car = new Car();

      }

      @Test

      public void testAddingNewCarWithSuccess(){

            try{

                  car.setDescription(“Civic”);

                  car.setManufacter(“Honda”);

                  car.setMarketValue(new BigDecimal(740000));

                  rentCarServicesImpl.addNewCar(car );

            }catch (Exception e) {

                  Assert.fail(“not expected result”);

            }

      }

      @Test

      public void testListAllCarIsNotEmpty(){

            assertFalse(rentCarServicesImpl.findAll().isEmpty());

      }

 Resultado

Lembre-se que seu BD precisa está rodando

springhibernateunittestresult

 

Ufa! Esse post foi longo heim, mas não tinha outra forma de mostrar tudo se não fosse assim, e olha que busquei resumir ao máximo possível. Enfim, vou ficando por aqui.

GitHub

Acesse o repositório no github com todos os projetos da série Spring:  https://github.com/camilolopes/workspacespring

Espero que tenham gostado do post.

Abraços, see ya!!