Simulación de properties
En Play, cuando estás definiendo el módelo, es normal declarar clases con atributos publicos. Cualquier desarrollador con la mínima experiencia en Java te dirá que esto es una mala práctica. Que deberías declarar esa variable como privada y crearle métodos getter y setter.
}
1
2
3
4
5
6
7
8
9
10
11
public class Entidad {
private String nombre;
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getNombre</span><span class="o">(){</span>
<span class="k">return</span> <span class="n">nombre</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setNombre</span><span class="o">(</span><span class="n">String</span> <span class="n">nombre</span><span class="o">){</span>
<span class="k">this</span><span class="o">.</span><span class="na">nombre</span> <span class="o">=</span> <span class="n">nombre</span><span class="o">;</span>
<span class="o">}</span>
Dialogo entre un ProJava y un AntiJava
ProJava - Esto está muy bien, es una buena convención. Provee un mayor encapsulamiento y produce un código más mantenible.
AntiJava - Pero… ¿no te parece demasiado código para simplemente declarar una variable?
ProJava - No importa, Eclipse tiene un botón que los genera automáticamente.
AntiJava - Pero… ¿a la hora de ver el código no hay demasiado código superfluo que no aporta nada? ¿Qué aporta exactamente ver la definición de un getter y un setter?
ProJava - Tienes razon, a veces es un poco engorro. Pero es el precio que hay que pagar tener un código más mantenible. Si declarases la variable pública ¿que pasaría si quisieras definir un setter, con alguna lógica antes de realizar la asignación?
AntiJava - Bueno, hay una forma de solucionar esto. Hacerlo al modo play.
Properties PlayStyle
Play genera automáticamente los getters y los setters por ti. La convención es que todas cualquier campo public, non-static, non-final es visto como una propiedad. Se crearán automáticamente los getters y los setters.
Por ejemplo, la clase :
1
2
3
public class Entidad {
public String nombre;
}
En realidad, producira el código:
}
1
2
3
4
5
6
7
8
9
10
11
public class Entidad {
private String nombre;
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getNombre</span><span class="o">(){</span>
<span class="k">return</span> <span class="n">nombre</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setNombre</span><span class="o">(</span><span class="n">String</span> <span class="n">nombre</span><span class="o">){</span>
<span class="k">this</span><span class="o">.</span><span class="na">nombre</span> <span class="o">=</span> <span class="n">nombre</span><span class="o">;</span>
<span class="o">}</span>
Cuando accedas al campo
1
2
Entidad entidad = new Entidad();
entidad.nombre;
En realidad es como si estuvieras escribiendo
1
2
Entidad entidad = new Entidad();
entidad.getNombre();
No te lo crees? Vamos a hacer una prueba.
Probando la creación automática de properties con JUnit
Vamos a crear un proyecto de prueba con un test de JUnit donde probaremos la creación automática de properties. Así de paso aprenderemos como crear test unitarios utilizando play.
play new bytecode
cd bytecode
play eclipsify
Importa el proyecto desde eclipse.
Crea la clase Entidad en app/models/Entidad.java
package models;
public class Entidad {
public String nombre;
}
Crea un nuevo test en test/BytecodeTest.java
import models.Entidad;
import org.junit.Assert;
import org.junit.Test;
import play.test.UnitTest;
public class BytecodeTest extends UnitTest {
@Test
public void bytecodetest() {
Entidad e = new Entidad();
e.nombre = "Play!";
Assert.assertEquals("Play!", e.nombre);
}
}
¿Cómo ejecutar un test?
Desde Eclipse
Botón derecho en la clase de los test Run As/JUnit Test
Desde linea de comando
play test
Accede a http://localhost:9000/@tests Verás una web donde puede seleccionar el test que quieres ejecutar y pulsar Start! para ejecutar el test. En el caso de que el test no se pasara, mostraría la información del error en el navegador directamente.
Desde línea de comando de forma automática
play auto-test
Simula la ejecución de un “play test”. Abriendo un navegador y ejecutando todos los test automáticamente. Muy útil para realizar integración continua.
Modificando el test
Es un test bastante sencillo estamos probando la asignación de una variable pública y comprobando que tiene el valor adecuado. Play está haciendo su magia, pero todavía no nos hemos dado cuenta. Vamos a hacer algunos cambios para poder verla.
Modificamos el archivo app/models/Entidad.java
package models;
public class Entidad {
public String nombre;
public String getNombre(){
return "Getter interceptado!";
}
}
Volvemos a ejecutar el test y vemos como el test ahora falla:
org.junit.ComparisonFailure: expected:<[Play]!> but was:<[Getter interceptado]!>
at org.junit.Assert.assertEquals(Assert.java:123)
at org.junit.Assert.assertEquals(Assert.java:145)
at BytecodeTest.bytecodetest(BytecodeTest.java:12)
...
¿Qué está pasando?
Cuando hacemos la llamada a “entidad.nombre”, play la está sustituyendo, en tiempo de compilación por una llamada a “entidad.getNombre()”.
¿Cómo hace esto play?
Básicamente lo que hace Play es utilizar la libería Javassist para realizar modificaciones en el bytecode de nuestra clase compilada.
Vamos a ver por encima cómo lo hace