Páginas

lunes, 29 de diciembre de 2008

Supervivencia a la hora de escribir código

"Always code as if the person who will maintain your code is a maniac serial killer that knows where you live"

Y es que, nunca se sabe si la persona que va a mantener tu código es un programador o un asesino en serie. Pero claro, qué fue antes, ¿el huevo o la gallina?, porque ¿a quienes no os ha entrado ganas de matar a alguien tras ver algunas líneas de código? A mí sí, es algo que ya sabéis.

Por otro lado, si queréis mantener vuestro puesto de trabajo para siempre, corriendo el riesgo de ser asesinado por un asesino en serie claro está, siempre podéis usar las técnicas de escritura de código inmantenible. Si echáis un vistazo a estas prácticas seguro que os daréis cuenta que sois habituales en algunas de ella aunque de forma menos exagerada (o quizás no). Tal vez sea nuestro instinto de supervivencia lo que nos hace escribir código inmantenible pero paradójicamente esto nos pueda llevar a ser asesinados  por un asesino en serie.

viernes, 5 de diciembre de 2008

Spring - JPA - Hibernate

Estos días he tenido que montar el esqueleto para un nuevo proyecto. Para mi sorpresa la combinación de Frameworks que se requerían no estaba entre las disponibles de Appfuse Light así que tuve que montarla casi desde cero.

Son muchos los ejemplos y la documentación que se puede encontrar que hablan acerca de cómo montar JPA con Spring, pero como suele suceder casi todos proceden de un ejemplo original por lo que al final todos quedan reducidos a muy pocos que para colmo, están incompletos. Así pues, voy a hacer mi pequeña aportación y describiré el archivo de Spring al completo. No describiré cómo se realizan Test o cómo se crean claves primarias compuestas porque son temas que ya tratan bien en otros blogs.

En primer lugar, empezaré definiendo una entidad, sobre la que girará el ejemplo: User.

package es.whatabout.model; @Entity @Table(name = "USER") public class User{ @Id @Column(name = "ID") private Integer idUser; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; ...get/set methods...


Como se puede ver, esta clase lleva anotaciones JPA que identifican a esta clase como un entidad, su clave primaria y el mapeo de sus atributos a la tabla y columnas correspondientes en la base de datos. Esta será la única clase que contenga anotaciones ya que el resto de la configuración, como la transaccionalidad, la configuraremos desde Spring.

Antes de definir la clase DAO crearemos un interfaz genérico y su implementación que proporcionará a nuestro dao particular y a todos los que generemos (y su implementaciones) de todos los métodos CRUD gracias a los tipos genéricos de Java.

import java.io.Serializable; import java.util.List; public abstract interface GenericDao <T, PK extends Serializable> { public abstract List<T> getAll(); public abstract T findByPK(PK id); public abstract void update(T object); public abstract void remove(T object); public abstract void insert(T object); }

Y su implementación.

package es.whatabout.dao.impl; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.orm.jpa.support.JpaDaoSupport; import es.whatabout.dao.GenericDao; public class GenericDaoImpl extends JpaDaoSupport implements GenericDao { private static Log logger = LogFactory.getFactory().getInstance(GenericDaoImpl.class); private Class persistentClass; public GenericDaoImpl() { this.persistentClass = (Class) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; } public void insert(T t) { getJpaTemplate().persist(t); } public T findByPK(PK id) { return getJpaTemplate().find(persistentClass, id); } public List getAll() { List entities = new ArrayList(); try { String s = "select c from " + persistentClass.getSimpleName() + " c"; entities = getJpaTemplate().find(s); } catch (Exception e) { logger.error(e.getStackTrace()); } return entities; } public void remove(T t) { getJpaTemplate().remove(getJpaTemplate().merge(t)); } public void update(T object) { getJpaTemplate().merge(object); } }


T será la entidad que maneje nuestra clase dao mientras que PK será la clase de la clave primaria de ésta, que puede ser de tipo simple o compuesta (composed primary key)

A continuación crearemos una interfaz para un dao particular y su implementación utilizando el interfaz y la implementación de éste antes definido.

package es.whatabout.dao; import es.whatabout.model.User; public interface UserDao extends GenericDao<User, Integer> { }

Vemos que nuestro interfáz es muy simple, ya que dispone de los métodos CRUD del interfaz GenericDao. Del mismo modo, su implementación también será muy simple ya que ésta extiende de la implementación de GenericDao, GenericDaoImpl

package es.whatabout.dao.impl; import es.whatabout.dao.UserDao; import es.whatabout.model.User; public class UserDaoImpl extends GenericDaoImpl<User, Integer> implements UserDao{ }

Sólo queda definir el archivo de configuración de Spring:

<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http:// www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- archivo de configuracion para los datos de conexion --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" /> </bean> <!-- Transaccionalidad para todas las clases del paquete indicado --> <aop:config> <aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* es.whatabout.dao.impl.*.*(..))" /> </aop:config> <!-- restringimos a solo lectura las transacciones metodos que comienzan por get --> <tx:advice id="txAdvice"> <tx:attributes> <tx:method name="get*" read-only="true" /> <tx:method name="*" /> </tx:attributes> </tx:advice> <!-- configuramos el transaction manager--> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="dataSource" ref="dataSource" /> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <!-- Conexion a bd con las propiedades del arhivo jdbc.properties--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- configuramos la Factory Manager, que trabajará con hibernate--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true" /> <property name="databasePlatform" value="${hibernate.dialect}" /> </bean> </property> <property name="jpaProperties"> <value>hibernate.show_sql=true</value> </property> </bean> <!-- configuramos LOG4J --> <bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetClass" value="org.springframework.util.Log4jConfigurer" /> <property name="targetMethod" value="initLogging" /> <property name="arguments"> <list> <value>classpath:log4j.xml</value> </list> </property> </bean> <!-- inyeccion del entityManagerFActory a nuestro Dao particular--> <bean id="userDao" class="es.whatabout.dao.impl.UserDaoImpl"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>


Con este archivo de configuración ya podemos disponer de nuestro dao capaz de realizar todas las operaciones CRUD sin ningún problema.

Referencia: The Spring Framework - Reference Documentation, chapter 9, Introduction to Spring 2 and JPA
Código: descargar