Inyección de dependecias con @Autowired, @Qualifier y @Resource
Spring proporciona dos anotaciones para la inyección de dependencias: @Autowired y @Qualifier.
@Autowired funciona por tipo, y es que ella sola se encarga de buscar un bean de la clase correspondiente:
@Autowired private ExampleService exampleService;
La gran limitación de esta anotación es que no es posible hacer inyección por nombre (¿qué pasa si tenemos varios beans del mismo tipo?), por lo que la solución pasa por complementarla con @Qualifier:
@Autowired
@Qualifier("exampleService")
private ExampleService exampleService;
Mientras no llega la versión 3.0 de Spring, una alternativa menos verbosa sería usar la anotación @Resource (perteneciente al JSR-250):
@Resource(name="exampleService") private ExampleService exampleService;
Profiling SQL con P6Spy
P6Spy es una “pequeña” utilidad que nos permite analizar las consultas SQL que lanza una aplicación y su rendimiento. En realidad es un wrapper de nuestro driver JDBC que intercepta y registra las sentencias en un log que posteriormente podemos analizar.
Esto es especialmente útil si queremos ver qué consultas se están generando al utilizar por ejemplo Hibernate o EJB, o cuáles pueden llegar a ser un cuello de botella al poder ver el tiempo total de ejecución de cada una.
Para empezar a usarlo hay que seguir los siguientes pasos:
- Instalación: si se realiza a través de Maven, tan fácil como añadir la dependencia:
<dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>1.3</version> </dependency>En caso contrario, habría que copiar los archivos
p6spy.jaryspy.propertiesa nuestro classpath. - Configuración del datadsource: una vez tengamos la librería en nuestra aplicación, tenemos que cambiar el datadsource para utilizar el nuevo driver. En este caso es
com.p6spy.engine.spy.P6SpyDriver. Con Spring sería algo como:<bean id="dataSourceTarget" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>oracle.jdbc.driver.OracleDriver</value> </property> <property name="url"> <value>jdbc:oracle:thin:@localhost:1521:xe</value> </property> <property name="username"><value>test_app</value></property> <property name="password"><value>test_app</value></property> </bean> <bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource"> <constructor-arg> <ref local="dataSourceTarget"/> </constructor-arg> </bean> - Configuración P6Spy: ahora tenemos que indicarle a P6Spy cuál es en realidad el driver que debe utilizar, por ejemplo
oracle.jdbc.driver.OracleDriver. Creamos un archivospy.propertiesen nuestro classpath donde le indicamos el archivo de log y el driver real de la aplicación:module.log=com.p6spy.engine.logging.P6LogFactory realdriver=oracle.jdbc.driver.OracleDriver logfile=p6spy.log
Después de estos 3 pasos probamos a ejecutar de nuevo la aplicación, y veremos cómo se va escribiendo en el archivo de log todas las consultas que se ejecutan. El problema es que este registro es poco legible, por lo que podemos usar alguna de estas herramientas gráficas:
- SQL Profiler
- P6Spy viewer (plugin para Eclipse)
Google Collections
Una de las cosas más irritantes de Java es su API de colecciones. Es verdaderamente frustante tener que usar tal cantidad de verbosidad y ceremonia para simplemente inicializar una lista, y no digamos ya para realizar operaciones más complejas como filtrar los elementos.
Si el cambiar a un lenguaje dinámico no es solución, quizá ayude la librería del buscador gigante Google Collections.
Un par de ejemplos rápidos, primero incializando una lista:
List<Integer> list1 = Lists.newArrayList(1, 2, 3); // nótese que List es de tipo java.util.List
System.out.println(Joiner.on(", ").join(list1)); // imprime "1, 2, 3"
y otro utilizando un filtro:
List<Integer> list = Lists.newArrayList(1, 2, 3, null);
Iterable<Integer> filter = Iterables.filter(list, new Predicate<Integer>() {
public boolean apply (Integer input) {
return input == null || (input > 2);
}
});
System.out.println(Joiner.on(", ").useForNull("100").join(filter)); // imprime 3, 100
Google Collections está disponible en la versión 1.0-rc2 a través de Maven:
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0-rc2</version>
</dependency>
o en descarga directa desde su web.
Como vemos no pretende reemplazar a las colecciones nativas de Java, sino que las complementa, las extiende e incluso proporciona alguna nueva.
Enlace | Google Collections
Vídeo presentación | Parte 1 (~40min) y Parte 2 (~53min)
Aprendiendo Groovy && Grails
Ya hacía tiempo (algo así como 3 meses) que no escribía nada; el verano, la jornada intensiva y una mudanza tienen parte de culpa
.
El caso es que después de hacer el examen de SCJP veo Java por todas las esquinas, así que he decidido que es hora de aprender algo nuevo. Mi primera opción siempre fue Ruby, pero tras varios intentos infructuosos he acabado dejándolo y apostando por Groovy (al menos el cambio no es tan brusco).
Ahora mismo estoy enfrascado con Grails in Action, y estoy realmente sorprendido con el lenguaje y con el framework (aunque de Grails sólo he visto un par de cosas). Basta un ejemplo para hacerse una idea:
def sortItems(items, property) {
items.sort { a, b -> a."${property}" <=> b."${property}" }
}
class Person { String name }
people = [ new Person(name: "Adrián"), new Person(name: "Rubén"), new Person(name: "Lucas") ]
sortItems(people, "name").each { print it.name + " " }
// salida: "Adrián Lucas Rubén"
En las escasas 5 líneas de aquí arriba:
- Se declara un método para ordenar una colección según una propiedad de los objetos. Esto mismo en Java supondría unas cuantas líneas más (clase anónima implementando
Comparator, introspección…). - Se declara una clase
Personcon una única propiedad. No hay getters ni setters, se construyen automáticamente. - Se crea una lista con 3 personas. Todo en una sola línea, sin necesidad de crear una colección indicando su interfaz, su implementación concreta, y luego añadir de uno en uno los elementos (o crear un array para añadirlos todos).
- Se ordena la lista anterior según el nombre de las personas, y se imprime esta propiedad.
Buena muestra del potencial del lenguaje, que no olvidemos se ejecuta sobre la JVM y se puede usar sin problemas en nuestros proyectos Java, al que por el momento sólo veo ventajas.
En definitiva, aconsejado echarle un vistazo para todos aquellos que trabajen con la plataforma Java (y sin olvidar otros lenguajes más que interesantes, como Clojure o Scala). Seguiremos informando.
Sobreescribir métodos estáticos en Java
Menudo título más puñetero para este post… y es que los métodos estáticos no se pueden sobreescribir en Java, en realidad se ocultan. Aunque esta cuestión es algo compleja.
Empecemos con los ejemplos:
class A {
static void method1() {
System.out.println("method1 from A");
}
}
class B extends A {
static void method1() {
System.out.println("method1 from B");
}
}
Si ahora creamos instancias de cada una de estas clases, vemos como parece que el método de B sobreescribe a A:
A a = new A(); a.method1(); // imprime "method1 from A" B b = new B(); b.method1(); // imprime "method1 from B"
Pero la gran y enorme diferencia entre sobreescribir y ocultar sale a la luz cuando queremos hacer uso del polimorfismo:
void someMethod(A a) {
a.method1();
}
// ...
B b = new B();
someMethod(b); // imprime "method1 from A"
Si el método estuviera realmente redefinido por B, entonces el código anterior debería imprimir "method1 from B". Pero como vemos esto no ocurre…
Lo que realmente está pasando guarda relación con el “fallo” de diseño de Java en el acceso a los miembros estáticos. La llamada a method1 se hace sobre el tipo sin importar si la variable tiene una referencia a una instancia o no ni de qué tipo sea ésta. Y someMethod sólo sabe que la variable es de tipo A, por lo que se ejecuta el método estático de esta clase.
Este tipo de llamadas deberían hacerse siempre sobre la clase y no sobre una instancia:
void someMethod(A a) {
// a.method1(); <- NO
A.method1();
}
Por otra parte, si queremos acceder al method1 de A desde B tenemos dos opciones, la primera la acabamos de ver y la segunda es utilizando super (desde un método no estático, claro):
class B extends A {
static void method1() {
A.method1(); // imprime "method1 from A"
super.method1(); // error! no se puede acceder desde un método estático
method1(); // ups, bucle infinito!
}
void method2() {
A.method1(); // imprime "method1 from A"
super.method1(); // imprime "method1 from A"
method1(); // imprime "method1 from B"
}
}
Ya por último un par de notas. Un método de instancia no puede sobreescribir ni ocultar a otro estático, y viceversa un método de clase no puede sobreescribir ni ocultar a otro de instancia. Cualquiera de estas situaciones se traduce en un error de compilación.
¿Enrevesado? Pues acabamos de empezar… welcome to Java world!
Log con plantillas de código en Eclipse
Lo más fácil para usar un logger en nuestras clases en Eclipse es crear una plantilla de código que inserte automáticamente el código y las importaciones necesarias.
Para crear una plantilla o “template” tenemos que entrar en Preferencias -> Java -> Editor – > Templates:

Creamos entonces una nueva plantilla para declarar e instanciar nuestro logger:
${imp:import(org.slf4j.Logger,org.slf4j.LoggerFactory)}
private static final Logger log = LoggerFactory.getLogger(${enclosing_type}.class);
Ojo: los imports automáticos están disponibles a partir de Eclipse Ganymede (3.4).
Y ya que estamos, creamos otra plantilla con una función de guarda para depuración:
if (log.isDebugEnabled())
log.debug("${cursor}");
Programar mediante autocompletado, qué bonito es.
Accediendo a miembros estáticos de una clase desde una instancia
En Java es posible acceder a miembros estáticos (ya sean métodos o propiedades) de una clase desde una instancia de la misma (al contrario de lo que ocurre en C# o Ruby, por ejemplo). Nada mejor que mostrarlo en código para verlo:
String cadena = "cadena";
// el método valueOf es un método estático de la clase String
cadena.valueOf("otra cadena");
Esto está permitido, aunque el compilador lanza un warning para advertir de la situación; es algo que debería evitarse y que muchos piensan es un error de diseño de Java.
Lo curioso y algo que puede llevar a malentendidos es que no hace falta que la variable tenga una referencia a una instancia, ya que el acceso al método estático se hace a través del tipo de la variable.
public class Test {
static String cadena;
public static void main(String[] args) {
System.out.println(cadena.valueOf("cadena")); // imprime "cadena"
}
}
O más chocante (aunque viene a ser lo mismo de arriba):
String cadena = null;
cadena.valueOf("cadena"); // funciona!
Un ejemplo con enumerados (los valores de un enumerado son instancias estáticas del tipo del enumerado):
enum Animals { MONKEY, DONKEY }
Animals a;
void doSomething() {
System.out.println(a.MONKEY.DONKEY.MONKEY); // y así podríamos seguir...
}
Redefiniendo toString() con ToStringBuilder
El método toString es más que útil al imprimir logs y/o depurar una aplicación; sin embargo el redefinirlo en cada uno de nuestros objetos puede ser un verdadero coñazo.
Una forma fácil de hacerlo es utilizar la clase ToStringBuilder, de los commons de Apache.
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
Mediante reflexión este método accede a todas las propiedades del objeto y las imprime en un formato que podemos elegir. Si sólo queremos imprimir unos atributos determinados, podemos indicarlo del siguiente modo:
@Override
public String toString() {
return ToStringBuilder(this).append("name", name).append("age", age).toString();
}
Cuidado al sobreescribir el método hashCode()
Modificar los métodos equals y hashCode de nuestros objetos no es algo trivial, y puede traer efectos secundarios no muy buenos para nuestra aplicación.
Para qué sirve el código hash
Por defecto, hashCode devuelve un entero diferente para cada objeto basándose en la dirección del mismo (aunque esto depende de la implementación). Su uso principal es la optimización de las colecciones basadas en hashtables, como pueden ser HashMap o HashSet.
De modo gráfico, imaginemos una colección como una serie de cajas. En la caja 1 guardaremos los objetos que tengan hashcode 1, en la caja 2 los que tengan un hashcode 2… y así respectivamente. Cuando busquemos un objeto, sólo tenemos que mirar en la caja donde debería estar (mediante su hashcode).
En esta caja puede haber más objetos; por ejemplo, si sobreescribimos el método hashCode para que devuelva la longitud de un string:
private class CustomObject {
private String attribute;
public void setAttribute(String attribute) {
this.attribute = attribute;
}
@Override
public int hashCode() {
return this.attribute.length();
}
}
y tenemos dos objetos, uno con attribute="a" y otro con attribute="b", ambos irán a parar a la caja 1. Por tanto una vez dentro de la caja correspondiente debemos buscar el objeto mediante el método equals.
Esto es más eficiente que recorrer todos los elementos de la colección (siguiendo con el ejemplo anterior, sólo buscaremos en los strings de longitud 1, descartando el resto de elementos nada más empezar) como pasaría en un ArrayList, por ejemplo.
Peligro, ¡cuidado al sobreescribir!
En condiciones normales no deberíamos (ni necesitaremos, seguramente) sobreescribir el método hashCode. El problema viene cuando redefinimos equals (por ejemplo, para ejecutar tests), lo cual implica que también debemos hacer lo mismo con hashCode para mantener la coherencia (dos objetos iguales según equals deben tener el mismo código hash, sino puede ocurrir que por ejemplo tengamos dos instancias idénticas en un conjunto, cuando esto no puede -o no debería- ocurrir).
Dos objetos distintos según equals pueden producir el mismo código hash; por ejemplo:
@Override
public int hashCode() {
return 2;
}
Este código sería válido pero ineficiente, todos los objetos irían a parar a la misma caja, por lo que las búsquedas posteriores serían secuenciales perdiendo la principal ventaja de usar hashtables.
Otro gran peligro que existe al sobreescribir el método hashCode es el siguiente:
// creamos una colección de tipo HashSet
Set<CustomObject> testSet = new HashSet<CustomObject>();
// creamos un objeto de tipo CustomObject
// y lo añadimos a la colección
CustomObject customObject = new CustomObject();
customObject.setAttribute("attribute");
testSet.add(customObject);
// comprobamos que esté en el conjunto
System.out.println(testSet.contains(customObject)); // true
// modificamos su atributo y comprobamos
// de nuevo que esté en la colección
customObject.setAttribute("another attribute");
System.out.println(testSet.contains(customObject)); // false
Como vemos, al modificar la variable privada de customObject el código hash del objeto cambia (se utiliza en el cómputo), y cuando queremos comprobar si el objeto pertenece a la colección el método contains busca en la caja que no es. El objeto ya no está en la colección.
En definitiva, no tocar
Esto se puede complicar todavía mucho más si ponemos sobre la mesa objetos serializables y variables transient (no debemos utilizar variables de este tipo en el método hashCode, ya que al recuperar el objeto serializado tendrán el valor por defecto).
Este tema es importante y está presente en muchas situaciones, por ejemplo en las entidades de Hibernate (que puede completar los objetos de una colección con valores autogenerados cambiando el hashcode de los mismos y provocando el lío que vimos anteriormente) y los tests.
Lo mejor es, mientras no sea estrictamente necesario, no tocar.
Wicket en Google App Engine
A pesar de las limitaciones de la “nube” de Google, parece que en general los frameworks web van funcionando… Después de ver cómo hacer funcionar Struts en AppEngine, ahora le toca el turno a Wicket.
Lo primero es activar el soporte de sesiones, algo esencial en este framework con estado. Para ello debemos escribir la siguiente línea en el archivo appengine-web.xml:
<sessions-enabled>true</sessions-enabled>
Siguiendo con las sesiones, también debemos decirle a Wicket que las almacene en memoria. Sobreescribimos pues el método newSessionStore en el objeto de configuración de la aplicación:
public class ExampleApp extends WebApplication {
public ExampleApp() { }
@Override
protected ISessionStore newSessionStore() {
return new HttpSessionStore(this);
}
}
Por último, ya sólo nos queda inhabilitar el thread que recarga los recursos (html y demás), ya que como sabemos GAE no permite que las aplicaciones creen nuevos hilos.
public class ExampleApp extends WebApplication {
public ExampleApp() { }
@Override
protected ISessionStore newSessionStore() {
return new HttpSessionStore(this);
}
@Override
protected void init() {
super.init();
this.getResourceSettings().setResourcePollFrequency(null);
}
}
Y con esto, todo listo. No debería haber mayores problemas, aunque parece que con Ajax no todo funciona como debería (más info).


