Usando Spring Core com múltiplos projects

Olá Pessoal,

O post hoje é bem rápido e a ideia é compartilhar com vocês um problema comum quando temos mais de um projeto com dependência e precisamos usar o applicationContext que está em outro projeto.  São coisas que a gente não decora e que normalmente faz uma vez a cada novo projeto e que certamente esquecemos com o passar do tempo. E se algum livro fala sobre o assunto, certamente nem damos atenção à esse detalhe, pois estamos ansiosos em querer meter a mão na massa.

lets go…

 

Contexto

Recentemente tive que criar um projeto com module do maven. Veja a estrutura para ficar mais claro: 

—parent

—core

—web

–dependecy of core

 

Com o desenho simples acima estou dizendo que tenho um projeto parent (pai) que tem dois filhos: core e web. E o filho web depende do projeto core. 

No projeto core temos o back-end da aplicação, ou seja, regras de negócio e persistência vão estar nesse projeto. O projeto web vai cuidar do front-end. É nele que teremos o controller, os arquivos .html, xhtml, jsp, js etc. 

Então na prática o projeto web tem um .jar do projeto core: 

<dependency>

<groupId>com.handson.core</groupId>

<artifactId>xxx-core</artifactId>

<version>1.0.0</version>

</dependency>

 

Até aqui tudo bem. Nenhum problema, certo? 

Como falei, o projeto core tem o applicationContext do Spring, já que é lá que fazemos IoC, dizemos para o spring cuidar da sessionFactory etc. 

E qual o problema?

Quando precisamos usar o ApplicationContext no web. Esse é o problema. O código a seguir não vai funcionar quando aplicação subir:

 

 @Controller

@Path(“/user”)

public class UserController {

@Autowired

@Qualifier(“userServiceImpl”)

private UserService userService;

//código omitido

}

 

Por que não vai funcionar? Porque o applicationContext está dentro de .jar de outro projeto e ao subir a aplicação precisamos dizer isso para web.xml. Uma forma simples  é criar um arquivo applicationContext em web e importar o que temos no applicationContext no projeto core. Portanto, crie um app-context.xml em resource do projeto web:

 

springprojectwebresource

E no arquivo app-context que está no projeto web, faça isso:

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

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

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

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd”> 

<import resource=”classpath*:/META-INF/app-context.xml”/>

</beans> 

Esse caminho acima é porque o arquivo no projeto core está assim:

springappcontextcore

 

Agora no arquivo web.xml no projeto xx-web deixe assim:

 springwebxml

Assim, ao subir a aplicação o arquivo que está dentro do .jar do projeto core será carregado. E no import que fizemos anteriormente dizemos para importar esse arquivo para o contexto da aplicação web que está sendo carregada. 

Pronto. Salve as alterações e execute mvn install. Suba a aplicação. Se o Spring não conseguir fazer o @Autowired ele irá reclamar logo que subir. Mas o esperado é que não tenha problemas. 

Abraços! Vou ficando por aqui. Espero que tenham gostado da dica de hoje.

Série Spring: JEE:CRUD Hibernate com Spring 3 + JSF 2.0

 

Olá Pessoal,

Continuando a nossa série de post sobre o Spring vamos, ver hoje como fazer um simples CRUD com Spring + Hibernate + JSF.O objetivo maior, é para quem está chegando possa ver como juntar as tecnologias de maneira simples. E o melhor de tudo veremos como Spring  é uma mão na roda de verdade.

Lets go…

Starting…

A nossa aplicação será super simples, vamos fazer o cadastramento de carros, e exercitar o CRUD. Para exibição e cadastro dos veículos, vamos fazer uma página JSF de maneira mais simples possível e que seja funcional.  A seguir os requisitos:

Requisitos:

  • – MysqlSQL 5.x
  • – Hibernate 3.x
  • – Spring 3.x
  • – Tomcat 7.x
  • – JSF 2.x
  • – Jboss tools

Vou considerar que você vem acompanhando a série de posts  Spring no blog e alguns pontos que já foi tratado aqui, não estarei explicando novamente, dúvidas? Farei um link para o post referente. E sobre JSF 2.x também irei considerar que vc já brincou com o framework, mesmo que seja na versão anterior. Estou ressaltando isso, para que não entre no detalhes de cada ponto, e que o post fique mais direto e mão na massa.

 Configuração

Primeiro ponto é , criar um projeto JSF Project (é preciso ter o jboss tools instalado).

projetocrudspringcar

Escolha a opção JSF 2 na tela do assistente.  Em seguida crie os packages conforme a seguir, por enquanto eles estarão vazios, mas iremos daqui a pouco colocar carne no esqueleto : ).

Adicione os .jars na pasta lib do projeto:

webinflib

Criando o source unit/test

Observe que eu criei um source para os unit tests:

unitestscarcrud

Agora vamos criar o arquivo de configuração do Spring. Na verdade teremos dois, um para os unit tests e outro para aplicação. Apenas dupliquei, mas poderíamos otimizar o de unit tests importando apenas o que precisamos a partir do arquivo principal, mas não quis fazer isso por agora, vamos focar no CRUD.

Crie um arquivo springconfiguration.xml  dentro de WEB-INF, o nome poderia ser qualquer um, normalmente utiliza-se applicaiton-context.xml, mas quis fazer diferente para que você veja que o nome não importa.

Não irei adicionar o cabeçalho apenas o código, que não tem nada de diferente do que já vimos nos posts quando vimos hibernate com Spring.

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

<tx:annotation-driven/> 

<tx:advice id=“txAdvice”>

<tx:attributes>

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

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

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

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

</tx:attributes>

</tx:advice> 

<aop:config>

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

</aop:config> 

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

<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> 

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

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

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

<property name=“hibernateProperties”>

<props>

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

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

</props>

</property>

</bean>

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

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

</bean>

 

Agora precisamos fazer umas configurações no arquivo web.xml

<!– dizendo onde está meu arquivo de configuração –>

 <context-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>/WEB-INF/springconfiguration.xml,</param-value>

 </context-param>

 <!– configurando o context loader do Spring, esse cara permite carregar N arquivos de configuração –>

 <listener>

  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

 </listener>

 <!– esse cara permite dizer ao JSF que os beans serão gerenciados pelo Spring é requerido ter essa

 configuração –>

 <listener>

  <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>

 </listener>

 Testando.

Se você subir aplicação agora, não há nade especial, apenas vai subir o exemplo que temos no JSF Project que é criado pelo Jboss tols. Mas, é bom testar para garantir que as mudanças que fizemos no web.xml , não afetou nada da aplicação.

Arquivo de configuração do spring para unit tests

Agora vamos criar um arquivo de configuração para executar os unit tests. Mas, pq? Simplesmente pq a partir de uma classe de teste você não consegue ler um arquivo que está em web-inf, então você precisa ter o arquivo em source.

Noticia boa: o código é o mesmo que  do arquivo anterior, então duplique o XML apenas, o meu chamei de springconfiguration-test.xml e coloquei no JavaSource:

sourcespringconfiuration-test

Agora vamos começar a brincadeira, ou seja, desenvolver.

Development

Começaremos pelos testes claro. Para isso criaremos uma classe que testará o serviço que implicitamente testa as classes DAO.

Antes criaremos os testes precisamos entender que é importante entender que:

– após testes terem sido executados este deve dar rollback, para que os dados não fiquem no banco;

– os testes não podem ser dependentes de outro test, ou seja, um @Test não pode depender da execução de outro @Test

Por enquanto, ao criar os unit test é esperado que nem compile, já que não temos nenhuma classe pronto, mas é isso que queremos, que os testes nos ensinem a  desenvolver as regras de negocio que precisamos.

O primeiro teste vai nos permitir  testar o salvarOrUpdate  da nossa aplicação, poderia ter separado em dois testes um para save e outro para update, mas não quis entrar muito detalhes sobre testes aqui, senão o post ia fica 2x maior e sinceramente não curto muito posts grandes.

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={“classpath:springconfiguration-test.xml”})

@TransactionConfiguration(transactionManager=”transactionManager”,defaultRollback=true)

@Transactional

public class CarServiceImplTest {

      @Autowired

      private CarServices carServices;

      private Car car;

      @Before

      public void setUp() throws Exception {

      car = new Car();

      car.setDescription(“ferrari”);

      car.setPriceSale(BigDecimal.ZERO);

      car.setYear(“2010”);

      }

      @Test

      public void testSaveOrUpdate() {

            try{

                  carServices.saveOrUpdate(car);

            }catch (Exception e) {

                  fail(“not expected result”);

            }

      }

 

Observe que configuramos o rollback igual a true para tudo, então sempre será feito rollback e nada é inserido no banco. Mas,se você quer inserir no banco para um método especifico, basta anotarmos  no método assim: @Rollback(false) //isso faz inserir no banco 

Note: nesse exemplo não estou usando um banco em memória, então  é preciso que o Mysql esteja rodando para que os testes possam ser executados, o ideal é era fazer os testes rodarem em um banco em memória assim, não teríamos essa dependência, pois o banco seria iniciado sempre que os testes fossem executados.

Agora vamos criar as classes que o Eclipse está reclamando, vamos começar pela entidade Car:

@Entity(name=”SALE_CARS”)

public class Car implements Serializable{

      private static final long serialVersionUID = 2792374994901518817L;

      @Id

      @GeneratedValue

      private Long id;

      private String description;

      private BigDecimal priceSale;

      private String year;

//getters/setters omitidos

 

Services

Vamos criar os serviços, mas antes precisamos ter uma interface para os nossos serviços CRUD então:

public interface CarServices {

      void saveOrUpdate(Car car);

      void delete(Car car);

      List<Car> listAll();

}

 Agora vamos criar a classe em si:

@Service

public class CarServiceImpl implements CarServices {

      @Autowired

      private CarDAO carDAO;     

      public void saveOrUpdate(Car car) {

            carDAO.addCar(car);

      }

//setters CarDAO omitido. Não é preciso criar get.

DAO Interface

Também criaremos uma interface para o DAO e em seguida a implementação do método save

public interface CarDAO {

      void addCar(Car car);

      List<Car> readAll();

      void deleteCar(Long id);     

}

@Repository

public class CarDAOImpl implements CarDAO {

      @Autowired

      private SessionFactory sessionFactory;

           private Session getCurrentSession(){

            return sessionFactory.getCurrentSession();

      }

      public void addCar(Car car) {

            getCurrentSession().saveOrUpdate(car);

      }

//setters sessionFactory ommitido, não é preciso cria get.

Claro que os demais métodos da interface estarão sem código por enquanto, pois o objetivo agora é testar o create do CRUD.

Testando via Unit Tests

Agora vamos rodar o nosso teste e ver o resultado, se você não adicionou o JUNIT4 ao seu projeto, o Eclipse vai fazer a sugestão.

Note: Ao rodar o unit tests e você ter a exceção:

org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available

faça o download http://cglib.sourceforge.net/ e adicione a lib ao seu projeto na pasta web-inf/lib

O resultado

saveorupdategreen

Agora precisamos desenvolver o RUD.  A seguir os testes que foram criados e depois, o código com a resolução:

 @Test

public void testDelete() {

            try{carServices.saveOrUpdate(car);

                  carServices.delete(car);

            }catch (Exception e) {

String notExpectedResult = “Not expected result “+ e.getMessage();

                  fail(notExpectedResult);

            }

      }

      @Test

      public void testListAll() {

            carServices.saveOrUpdate(car);

            assertFalse(carServices.listAll().isEmpty());

      }

 Classe DAO

public List<Car> readAll() {

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

      } 

      public void deleteCar(Long id) {

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

            criteria.add(Restrictions.eq(“id”, id));

            Car car = (Car) criteria.uniqueResult();

            getCurrentSession().delete(car);

      }

 Classe de Serviço:

      public void delete(Car car) {

            carDAO.deleteCar(car.getId());

      } 

      public List<Car> listAll() {     

            return carDAO.readAll();

      } 

      public void setCarDAO(CarDAO carDAO) {

            this.carDAO = carDAO;

      }

Rodando todos os testes:

reusultadoAlltestescrud

Há um detalhe que fiz de propósito, observe que não tem um teste para validar o update, deixarei esse como motivação para você brincar mais com unit test  : ).

 

resultdbcrudspringunittests

Observe que nosso banco está vazio, ou seja, nada foi adicionado.

JSF

Agora que já sabemos que o nosso CRUD está funcionando, vamos trazer isso para o nosso front-end com JSF.:

Crie uma classe controller

@Controller

public class CarController {

      @Autowired

      private CarServices carServices;

      private Car car;     

      private List<Car> listCars;     

      public CarController() {

            car = new Car();

      }     

      public void save(){

            carServices.saveOrUpdate(car);

            car = new Car();

      } 

      public void delete(){

            carServices.delete(car);

            car = new Car();

      }     

      public List<Car> getListCars() {

            listCars = carServices.listAll();

            return listCars;

      }

                //setters/getters omitidos

Observe que nosso controller conecta com o nosso service. Só isso que precisamos. Se você já brinca com JSF nada de especial por aqui.

Criando  .xhtml

Na verdade vamos alterar o index.xhtml que foi criado por default pelo jboss tools:

<html><head><meta http-equiv=“Refresh” content=“0; URL=pages/sales-car.jsf”/></head></html>

 

Apenas fizemos um redirecionamento para uma página que vamos criar.

sales-car.xhtml

Crie um xhtml, com suporte facelets e adicione o código a seguir:

<body>

<h:form>

<h:commandLink action=“form-car” value=“::Cadastro”/>

</h:form>

</body>

 

Essa página vai levar para a tela de cadastro:

form-car.xhtml

Vamos por parte:

Primeiro temos o código do form:

<h:form>

<h:panelGrid columns=“2”>

<h:outputLabel value=“Car Description: “/>

<h:inputText value=“#{carController.car.description}”/>

<h:outputLabel value=“Sale Price: “/>

<h:inputText value=“#{carController.car.priceSale}” converter=“javax.faces.BigDecimal”/>

<h:outputLabel value=“year:”/>

<h:inputText value=“#{carController.car.year}”/>

<h:commandButton value=“Save” actionListener=“#{carController.save}”/>

</h:panelGrid>

Agora vamos ter o código de uma tabela que exibi o usuário adicionado e permite editar/deletar :

<h:dataTable id=“cartable” value=“#{carController.listCars}” var=“car” cellpadding=“10”>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Id”/>

</f:facet>

#{car.id}

</h:column>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Description”/>

</f:facet>

#{car.description}

</h:column>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Sale Price”/>

</f:facet>

<h:outputText value=“#{car.priceSale}”>

<f:convertNumber type=“currency” maxFractionDigits=“3”/>

</h:outputText>

</h:column> 

<h:column>

<f:facet name=“header”>

<h:outputText value=“Year”/>

</f:facet>

#{car.year}

</h:column> 

<h:column>

<f:facet name=“header”>

<h:outputText value=“Action”/>

</f:facet>

<h:commandLink value=“Delete” action=“#{carController.delete}”>

<f:setPropertyActionListener target=“#{carController.car}” value=“#{car}”/>

</h:commandLink>

<h:commandLink value=” | Edit “>

<f:setPropertyActionListener target=“#{carController.car}”  value=“#{car}”/>

</h:commandLink>

</h:column> 

</h:dataTable>

</h:form>

 

Pronto. Esse é o nosso front-end para testarmos o CRUD, vamos subir aplicação, clique com o botão direito  no projeto e escolha  Run as >> Run on Server

Note: Caso não tenha um servidor selecionado com o projeto o Eclipse vai solicitar que escolha um, no meu caso escolhi o tomcat e informei o local de instalação. Se der tudo certo você terá a tela a seguir:

screenaddjsfcars

Vamos para tela de cadastro clicando no botão “Cadastro”

 

cadcarscreenspring

addingcar

 

carsresultscreen

Verificando no bd:

 

checkingbdcars

Editando:

 

carrdseditjsf

Resultado Edição:

editresultjsfspring

E no banco:

 

editbdcars

 

Ufa! Post longo heim, e olha que reduzir. Mas, vou ficando por aqui. E espero que tenham gostado.

Abraços, see ya!!!

Série Spring: Spring AOP com annotations

 

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

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!! 

Série Spring:Rodando Unit Test com Spring Framework

Olá Pessoal,

Nesse post veremos como rodar nossos unit tests com o Spring framework, ou seja, aproveitar tudo de bom que tem o Spring e fazer nossos unit test funcionar normalmente. É bastante simples.

lets go…

Começando

Bem não vou entrar nos detalhes do que  é unit test, Spring, JUnit etc. Vamos direto ao ponto de maneira prática. Primeiro Crie um Java Project, o meu será SpringExampleUnitTest

note: claro que você precisa ter baixado o Spring framework core versão 3.x.

 

springexampleunittestproject

Note: adicione o arquivo commons-logging-1.1.1.jar  caso não tenha só baixar esse arquivo, basta digitar o nome no Google .

Desenvolvendo

Como bom baiano e pensando no carnaval de salvador vamos de chicletão. Temos uma interface que tem um método e uma classe que vai implementar:

 

package br.com.camilolopes;

public interface Competidor {

public void apresentar();

}

public class Chicletao implements Competidor {

                private Chicleteiro chicleteiroMusica;

                @Override

                public void apresentar() {

                               chicleteiroMusica.cantar();

                }

                public void setChicleteiroMusica(Chicleteiro chicleteiroMusica) {

                               this.chicleteiroMusica = chicleteiroMusica;

                }

}

 

public interface Musica {

void cantar();

}

public class Chicleteiro implements Musica {

                @Override

                public void cantar() {

                               System.out.println(“chicleteiro eu, chicleteira ela”);

                }

}

 

E no package conf, criamos um xml com as configurações do Spring:

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

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

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

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

 <!– classe normal –>

 <bean id=”chicleteiro” />

<!– classe que implementa a interface –>

 <bean id=”bell”>

                <property name=”chicleteiroMusica” ref=”chicleteiro”/>

 </bean>

</beans>

 

Pronto. Agora vamos criar a classe de teste.Porém, vamos entender o que acontece com a nossa aplicação. Quando o método apresentar() é invocado, a classe vai se apresentar com a musica que deseja, no caso da classe Chicleteiro, vai cantar: “chicleteiro eu, chicleteira ela”.

 

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={“classpath:conf/idolos.xml”})

public class ChicletaoTest {

                @Autowired

                private Chicleteiro chicleteiro;

               

                @Test

                public void testCantar() {

                Chicletao chicletao = new Chicletao();

                chicletao.setChicleteiroMusica(chicleteiro);

                try{

                               chicletao.apresentar();

                }catch (NullPointerException e) {

                               Assert.fail(“not expected result”);

                }

                }

 

Com Spring precisamos usar anotação @RunWith e informar qual framework vamos usar, no nosso caso usamos o JUNIT.Em seguida com anotações @ContextConfiguration estamos dizendo qual o xml que tem as configurações do Spring que usaremos para os testes. Que é o mesmo da aplicação. Em seguida fizemos um teste que apenas chama o método apresentar, e esperamos que nunca tenhamos um NullPointerException, mas para isso acontecer é apenas se a instância que chama o método for null, ou seja, não for instanciada. E com esse teste estamos validando duas coisas, uma que o Spring realmente está instanciando o atributo e que o resultado é o que esperamos. Veja:

springexampleunitestgreenresult

 

E assim temos nosso unit test integrado com o Spring. Simples não?

GitHub

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

Vou ficando por aqui!!

See ya!