miércoles, 28 de octubre de 2015

plugin eclipse para búsquedas rápidas InstaSearch

https://marketplace.eclipse.org/content/instasearch

jueves, 10 de septiembre de 2015

Propuesta de tecnologías de tests para integración continua

Para conseguir que en sonar aparezcan diferenciadas las coberturas de tests unitarios y tests de integración hemos llegado a lo siguiente.
A nivel de maven usamos los plugins:
  • Para configurar la ejecución de tests unitarios (UT):
          org.apache.maven.plugins
          maven-surefire-plugin
  • Para configurar la ejecución de tests de integración (IT):
          org.apache.maven.plugins
          maven-failsafe-plugin
  • Para publicar informes de cobertura en Sonar:
          org.jacoco
          jacoco-maven-plugin

Se optó por Jacoco para los informes de cobertura en Sonar debido a que nos permitía realizar una diferenciación entre la cobertura de tests unitarios y tests de integración. Descartamos el plugin Cobertura que no nos permitía realizar este paso
A nivel de tests usamos:
  • Junit+Jmockit+Podam para tests unitarios.Para los tests unitarios hemos probado varias librerías para mockear objetos y clases y finalmente nos hemos decantado por Jmockit http://jmockit.org/ . Esta librería es la que más encaja con surefire,failsafe,jacoco y sonar, además de momento es menos engorrosa. Descartamos Mockito y Powermockito debido a problemas con clases estáticas, aunque los tests funcionaban Jacoco no era capaz de generar informes de cobertura de ellas, esto era un bug conocido. Actualmente hay otro bug en Jacoco que no permite contar la cobertura de las lineas dentro de los "catch". Utilizamos Podam para generar clases con contenido dummy de forma rápida.
  • Junit+Spring para tests de integración. Utilizamos SpringBoot para arrancar un servidor embebido con la aplicación y RestTemplate para lanzar las llamadas a nuestros endpoints.

Propuesta de tecnologías java para la realización de tests unitarios y de integración.

Se realizan 2 tipos de tests a nivel general, tests unitarios y tests de integración. Los tests unitarios no levantarán spring ni tendrán ningún tipo de iteracción con sistemas externos y los tests de integración serán los que levanten un servidor embebido y se conecten a un entorno "controlado" tipo Test.

Tests unitarios por método público con JMockit.

Se realizarán tests junit de cada método hasta pasar por todos los caminos lógicos del método. Si nuestro método utiliza otros métodos públicos o de otras clases estos deberán ser mockeados con JMockit. De esta forma forma conseguimos tener tests unitarios totalmente independientes del entorno y de otras clases.
Estos tipos de tests serán desarrollados para:
  • métodos estáticos de clases de converters y de utilidades.
  • métodos de entrada de endpoint
    Y no los generaría para:
  • métodos de acceso a base de datos, cache o derivado.
A nivel de ordenación, en la carpeta de tests deberán existir los mismos paquetes y cada clase testeable deberá tener su clase de tests con el mismo nombre acabado en Test. Ejemplo: MiclaseService.java es la clase testeable y MiclaseServiceTest.java es su clase de tests.
De esta manera es fácil ver qué clases tienen ya tests implementados y cuales son.
Este tipo de tests al no levantar spring son rápidos y se puede tener una gran cantidad sin importar los tiempos.
Estos serán los tests que se ejecutan con nuestro entorno de integración continua para medir la cobertura y de los cuales sacará los informes Sonar.

Tests de integración utilizando el servidor embebido que nos ofrece spring-boot.

Estos tests levantarán un servidor embebido y se conectarán a un entorno "estable/controlado". Estos tests deberían realizar todas las llamadas de endpoints de la aplicación,  las clases que tienen la anotacion @Controller, con todos los posibles parámetros.
 Estos tests nos aseguran que todos los sistemas que se utilizan están alineados al desarrollo, bases de datos, ws de terceros, etc...

Utilidades extra

  • Tests de carga con junit
@RunWith(SpringJUnit4ClassExtendingParamsRunners.class) Utilizamos este Run para poder utilizar parámetros
Para más detalles de uso y posibilidades dejo el siguiente enlace: http://junitparams.googlecode.com

Ejemplo de uso JUnitParams con SpringBoot
Clase generada:
 package utils;  
 import java.lang.reflect.Method;  
 import org.junit.Ignore;  
 import org.junit.Test;  
 import org.junit.internal.runners.model.ReflectiveCallable;  
 import org.junit.internal.runners.statements.ExpectException;  
 import org.junit.internal.runners.statements.Fail;  
 import org.junit.internal.runners.statements.FailOnTimeout;  
 import org.junit.runner.Description;  
 import org.junit.runner.notification.RunNotifier;  
 import org.junit.runners.BlockJUnit4ClassRunner;  
 import org.junit.runners.model.FrameworkMethod;  
 import org.junit.runners.model.InitializationError;  
 import org.junit.runners.model.Statement;  
 import org.springframework.core.annotation.AnnotatedElementUtils;  
 import org.springframework.core.annotation.AnnotationAttributes;  
 import org.springframework.core.annotation.AnnotationUtils;  
 import org.springframework.test.annotation.ProfileValueUtils;  
 import org.springframework.test.annotation.Repeat;  
 import org.springframework.test.annotation.Timed;  
 import org.springframework.test.context.TestContextManager;  
 import org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks;  
 import org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks;  
 import org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks;  
 import org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks;  
 import org.springframework.test.context.junit4.statements.SpringFailOnTimeout;  
 import org.springframework.test.context.junit4.statements.SpringRepeat;  
 import org.springframework.util.ReflectionUtils;  
 import junitparams.JUnitParamsRunner;  
 import lombok.extern.slf4j.Slf4j;  
 /**  
  * {@code SpringJUnit4ClassRunner} is a custom extension of JUnit's {@link BlockJUnit4ClassRunner} which provides functionality of the  
  * Spring TestContext Framework to standard JUnit tests by means of the {@link TestContextManager} and associated support classes and  
  * annotations.  
  *  
  *  
  * The following list constitutes all annotations currently supported directly or indirectly by {@code SpringJUnit4ClassRunner}.  
  * (Note that additional  
  * annotations may be supported by various  
  * {@link org.springframework.test.context.TestExecutionListener TestExecutionListener}  
  * or {@link org.springframework.test.context.TestContextBootstrapper TestContextBootstrapper}  
  * implementations.)  
  *  
  *  
    *  
   {@link Test#expected() @Test(expected=...)}  
    *  
   {@link Test#timeout() @Test(timeout=...)}  
    *  
   {@link Repeat @Repeat}  
    *  
   {@link Ignore @Ignore}  
    *  
   {@link org.springframework.test.annotation.ProfileValueSourceConfiguration @ProfileValueSourceConfiguration}  
    *  
   {@link org.springframework.test.annotation.IfProfileValue @IfProfileValue}  
    *   
  *  
  *  
  * NOTE: As of Spring Framework 4.1, this class requires JUnit 4.9 or higher.  
  *  
  */  
 @SuppressWarnings("deprecation")  
 @Slf4j  
 public class SpringJUnit4ClassExtendingParamsRunners extends JUnitParamsRunner {  
   private static final Method WITHRULESMETHOD;  
   static {  
     WITHRULESMETHOD =  
       ReflectionUtils.findMethod(SpringJUnit4ClassExtendingParamsRunners.class, "withRules", FrameworkMethod.class, Object.class,  
         Statement.class);  
     if (WITHRULESMETHOD == null) {  
       throw new IllegalStateException("Failed to find withRules() method: SpringJUnit4ClassRunner requires JUnit 4.9 or higher.");  
     }  
     ReflectionUtils.makeAccessible(WITHRULESMETHOD);  
   }  
   private final TestContextManager testContextManager;  
   /**  
    * Constructs a new {@code SpringJUnit4ClassRunner} and initializes a {@link TestContextManager} to provide Spring testing functionality to  
    * standard JUnit tests.  
    *  
    * @param clazz the test class to be run  
    * @see #createTestContextManager(Class)  
    */  
   public SpringJUnit4ClassExtendingParamsRunners(final Class clazz) throws InitializationError {  
     super(clazz);  
     if (log.isDebugEnabled()) {  
       log.debug("SpringJUnit4ClassRunner constructor called with [" + clazz + "].");  
     }  
     testContextManager = createTestContextManager(clazz);  
   }  
   /**  
    * Creates a new {@link TestContextManager} for the supplied test class.  
    *  
    * Can be overridden by subclasses.  
    *  
    * @param clazz the test class to be managed  
    */  
   protected TestContextManager createTestContextManager(final Class clazz) {  
     return new TestContextManager(clazz);  
   }  
   /**  
    * Get the {@link TestContextManager} associated with this runner.  
    */  
   protected final TestContextManager getTestContextManager() {  
     return testContextManager;  
   }  
   /**  
    * Returns a description suitable for an ignored test class if the test is  
    * disabled via {@code @IfProfileValue} at the class-level, and  
    * otherwise delegates to the parent implementation.  
    *  
    * @see ProfileValueUtils#isTestEnabledInThisEnvironment(Class)  
    */  
   @Override  
   public Description getDescription() {  
     if (!ProfileValueUtils.isTestEnabledInThisEnvironment(getTestClass().getJavaClass())) {  
       return Description.createSuiteDescription(getTestClass().getJavaClass());  
     }  
     return super.getDescription();  
   }  
   /**  
    * Check whether the test is enabled in the first place. This prevents  
    * classes with a non-matching {@code @IfProfileValue} annotation from  
    * running altogether, even skipping the execution of {@code prepareTestInstance()} {@code TestExecutionListener} methods.  
    *  
    * @see ProfileValueUtils#isTestEnabledInThisEnvironment(Class)  
    * @see org.springframework.test.annotation.IfProfileValue  
    * @see org.springframework.test.context.TestExecutionListener  
    */  
   @Override  
   public void run(final RunNotifier notifier) {  
     if (!ProfileValueUtils.isTestEnabledInThisEnvironment(getTestClass().getJavaClass())) {  
       notifier.fireTestIgnored(getDescription());  
       return;  
     }  
     super.run(notifier);  
   }  
   /**  
    * Wraps the {@link Statement} returned by the parent implementation with a {@link RunBeforeTestClassCallbacks} statement, thus preserving the  
    * default functionality but adding support for the Spring TestContext  
    * Framework.  
    *  
    * @see RunBeforeTestClassCallbacks  
    */  
   @Override  
   protected Statement withBeforeClasses(final Statement statement) {  
     final Statement junitBeforeClasses = super.withBeforeClasses(statement);  
     return new RunBeforeTestClassCallbacks(junitBeforeClasses, getTestContextManager());  
   }  
   /**  
    * Wraps the {@link Statement} returned by the parent implementation with a {@link RunAfterTestClassCallbacks} statement, thus preserving the  
    * default  
    * functionality but adding support for the Spring TestContext Framework.  
    *  
    * @see RunAfterTestClassCallbacks  
    */  
   @Override  
   protected Statement withAfterClasses(final Statement statement) {  
     final Statement junitAfterClasses = super.withAfterClasses(statement);  
     return new RunAfterTestClassCallbacks(junitAfterClasses, getTestContextManager());  
   }  
   /**  
    * Delegates to the parent implementation for creating the test instance and  
    * then allows the {@link #getTestContextManager() TestContextManager} to  
    * prepare the test instance before returning it.  
    *  
    * @see TestContextManager#prepareTestInstance(Object)  
    */  
   @Override  
   protected Object createTest() throws Exception {  
     final Object testInstance = super.createTest();  
     getTestContextManager().prepareTestInstance(testInstance);  
     return testInstance;  
   }  
   /**  
    * Performs the same logic as {@link BlockJUnit4ClassRunner#runChild(FrameworkMethod, RunNotifier)},  
    * except that tests are determined to be ignored by {@link #isTestMethodIgnored(FrameworkMethod)}.  
    */  
   @Override  
   protected void runChild(final FrameworkMethod frameworkMethod, final RunNotifier notifier) {  
     final Description description = describeChild(frameworkMethod);  
     if (isTestMethodIgnored(frameworkMethod)) {  
       notifier.fireTestIgnored(description);  
     } else {  
       runLeaf(methodBlock(frameworkMethod), description, notifier);  
     }  
   }  
   /**  
    * Augments the default JUnit behavior {@link #withPotentialRepeat(FrameworkMethod, Object, Statement) with  
    * potential repeats} of the entire execution chain.  
    *  
    * Furthermore, support for timeouts has been moved down the execution chain in order to include execution of {@link org.junit.Before @Before} and  
    * {@link org.junit.After @After} methods within the timed execution. Note that this differs from the default JUnit behavior of executing  
    * {@code @Before} and {@code @After} methods in the main thread while executing the actual test method in a separate thread. Thus, the end effect  
    * is that {@code @Before} and {@code @After} methods will be executed in the same thread as the test method. As a consequence, JUnit-specified  
    * timeouts will work fine in combination with Spring transactions. Note that JUnit-specific timeouts still differ from Spring-specific timeouts  
    * in that the former execute in a separate thread while the latter simply execute in the main thread (like regular tests).  
    *  
    * @see #possiblyExpectingExceptions(FrameworkMethod, Object, Statement)  
    * @see #withBefores(FrameworkMethod, Object, Statement)  
    * @see #withAfters(FrameworkMethod, Object, Statement)  
    * @see #withPotentialRepeat(FrameworkMethod, Object, Statement)  
    * @see #withPotentialTimeout(FrameworkMethod, Object, Statement)  
    */  
   @Override  
   protected Statement methodBlock(final FrameworkMethod frameworkMethod) {  
     Object testInstance;  
     try {  
       testInstance = new ReflectiveCallable() {  
         @Override  
         protected Object runReflectiveCall() throws Throwable {  
           return createTest();  
         }  
       }.run();  
     } catch (final Throwable ex) {  
       return new Fail(ex);  
     }  
     Statement statement = methodInvoker(frameworkMethod, testInstance);  
     statement = possiblyExpectingExceptions(frameworkMethod, testInstance, statement);  
     statement = withBefores(frameworkMethod, testInstance, statement);  
     statement = withAfters(frameworkMethod, testInstance, statement);  
     statement = withRulesReflectively(frameworkMethod, testInstance, statement);  
     statement = withPotentialRepeat(frameworkMethod, testInstance, statement);  
     statement = withPotentialTimeout(frameworkMethod, testInstance, statement);  
     return statement;  
   }  
   /**  
    * Invoke JUnit's private {@code withRules()} method using reflection.  
    */  
   private Statement withRulesReflectively(final FrameworkMethod frameworkMethod, final Object testInstance, final Statement statement) {  
     return (Statement) ReflectionUtils.invokeMethod(WITHRULESMETHOD, this, frameworkMethod, testInstance, statement);  
   }  
   /**  
    * Returns {@code true} if {@link Ignore @Ignore} is present for the supplied {@link FrameworkMethod test method} or if the test method is  
    * disabled via {@code @IfProfileValue}.  
    *  
    * @see ProfileValueUtils#isTestEnabledInThisEnvironment(Method, Class)  
    */  
   protected boolean isTestMethodIgnored(final FrameworkMethod frameworkMethod) {  
     final Method method = frameworkMethod.getMethod();  
     return (method.isAnnotationPresent(Ignore.class) || !ProfileValueUtils.isTestEnabledInThisEnvironment(method, getTestClass().getJavaClass()));  
   }  
   /**  
    * Performs the same logic as {@link BlockJUnit4ClassRunner#possiblyExpectingExceptions(FrameworkMethod, Object, Statement)} except that the  
    * expected exception is retrieved using {@link #getExpectedException(FrameworkMethod)}.  
    */  
   @Override  
   protected Statement possiblyExpectingExceptions(final FrameworkMethod frameworkMethod, final Object testInstance, final Statement next) {  
     final Class expectedException = getExpectedException(frameworkMethod);  
     return expectedException != null ? new ExpectException(next, expectedException) : next;  
   }  
   /**  
    * Get the {@code exception} that the supplied {@link FrameworkMethod  
    * test method} is expected to throw.  
    *  
    * Supports JUnit's {@link Test#expected() @Test(expected=...)} annotation.  
    *  
    * @return the expected exception, or {@code null} if none was specified  
    */  
   protected Class getExpectedException(final FrameworkMethod frameworkMethod) {  
     final Test testAnnotation = frameworkMethod.getAnnotation(Test.class);  
     final Class junitExpectedException =  
       (testAnnotation != null && testAnnotation.expected() != Test.None.class ? testAnnotation.expected() : null);  
     return junitExpectedException;  
   }  
   /**  
    * Supports both Spring's {@link Timed @Timed} and JUnit's {@link Test#timeout() @Test(timeout=...)} annotations, but not both  
    * simultaneously. Returns either a {@link SpringFailOnTimeout}, a {@link FailOnTimeout}, or the unmodified, supplied {@link Statement} as  
    * appropriate.  
    *  
    * @see #getSpringTimeout(FrameworkMethod)  
    * @see #getJUnitTimeout(FrameworkMethod)  
    */  
   @Override  
   protected Statement withPotentialTimeout(final FrameworkMethod frameworkMethod, final Object testInstance, final Statement next) {  
     Statement statement = null;  
     final long springTimeout = getSpringTimeout(frameworkMethod);  
     final long junitTimeout = getJUnitTimeout(frameworkMethod);  
     if (springTimeout > 0 && junitTimeout > 0) {  
       final String msg =  
         "Test method [" + frameworkMethod.getMethod() + "] has been configured with Spring's @Timed(millis=" + springTimeout  
           + ") and JUnit's @Test(timeout=" + junitTimeout  
           + ") annotations. Only one declaration of a 'timeout' is permitted per test method.";  
       log.error(msg);  
       throw new IllegalStateException(msg);  
     } else if (springTimeout > 0) {  
       statement = new SpringFailOnTimeout(next, springTimeout);  
     } else if (junitTimeout > 0) {  
       statement = new FailOnTimeout(next, junitTimeout);  
     } else {  
       statement = next;  
     }  
     return statement;  
   }  
   /**  
    * Retrieves the configured JUnit {@code timeout} from the {@link Test @Test} annotation on the supplied {@link FrameworkMethod test method}.  
    *  
    * @return the timeout, or {@code 0} if none was specified.  
    */  
   protected long getJUnitTimeout(final FrameworkMethod frameworkMethod) {  
     final Test testAnnotation = frameworkMethod.getAnnotation(Test.class);  
     return (testAnnotation != null && testAnnotation.timeout() > 0 ? testAnnotation.timeout() : 0);  
   }  
   /**  
    * Retrieves the configured Spring-specific {@code timeout} from the {@link Timed @Timed} annotation on the supplied {@link FrameworkMethod test  
    * method}.  
    *  
    * @return the timeout, or {@code 0} if none was specified.  
    */  
   protected long getSpringTimeout(final FrameworkMethod frameworkMethod) {  
     final AnnotationAttributes annAttrs = AnnotatedElementUtils.getAnnotationAttributes(frameworkMethod.getMethod(), Timed.class.getName());  
     if (annAttrs == null) {  
       return 0;  
     } else {  
       final long millis = annAttrs.getNumber("millis").longValue();  
       return millis > 0 ? millis : 0;  
     }  
   }  
   /**  
    * Wraps the {@link Statement} returned by the parent implementation with a {@link RunBeforeTestMethodCallbacks} statement, thus preserving the  
    * default functionality but adding support for the Spring TestContext  
    * Framework.  
    *  
    * @see RunBeforeTestMethodCallbacks  
    */  
   @Override  
   protected Statement withBefores(final FrameworkMethod frameworkMethod, final Object testInstance, final Statement statement) {  
     final Statement junitBefores = super.withBefores(frameworkMethod, testInstance, statement);  
     return new RunBeforeTestMethodCallbacks(junitBefores, testInstance, frameworkMethod.getMethod(), getTestContextManager());  
   }  
   /**  
    * Wraps the {@link Statement} returned by the parent implementation with a {@link RunAfterTestMethodCallbacks} statement, thus preserving the  
    * default functionality but adding support for the Spring TestContext  
    * Framework.  
    *  
    * @see RunAfterTestMethodCallbacks  
    */  
   @Override  
   protected Statement withAfters(final FrameworkMethod frameworkMethod, final Object testInstance, final Statement statement) {  
     final Statement junitAfters = super.withAfters(frameworkMethod, testInstance, statement);  
     return new RunAfterTestMethodCallbacks(junitAfters, testInstance, frameworkMethod.getMethod(), getTestContextManager());  
   }  
   /**  
    * Supports Spring's {@link Repeat @Repeat} annotation by returning a {@link SpringRepeat} statement initialized with the configured repeat  
    * count or {@code 1} if no repeat count is configured.  
    *  
    * @see SpringRepeat  
    */  
   protected Statement withPotentialRepeat(final FrameworkMethod frameworkMethod, final Object testInstance, final Statement next) {  
     final Repeat repeatAnnotation = AnnotationUtils.getAnnotation(frameworkMethod.getMethod(), Repeat.class);  
     final int repeat = (repeatAnnotation != null ? repeatAnnotation.value() : 1);  
     return new SpringRepeat(next, frameworkMethod.getMethod(), repeat);  
   }  
 }  


Forma de uso:

@RunWith(SpringJUnit4ClassAndJUnitParamsRunners.class)

Utilidades extra

  • Categorización de tests
    Junit permite "categorizar" tests utilizando @Category, esto nos permite crear grupos de tests diferenciandolos por lo que queramos, como ejemplo básico he visto que se diferencian por SlowTest y FastTests, en principio no se me ocurren categorias útiles pero quizás si nos puedan ser útiles.
    La categorización nos sirve para realizar lanzamiento de tests personalizados. Imaginad que el total de tests tardará 7 horas, pero realmente solo quisieramos lanzar los tests rápidos que tardan 5 minutos.
    Tutorial de ejemplo:
    http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=JUnitTestRunners
  • Definición de timeouts para tests de integracion
    Junit provee de la opcion de definir timeouts, @Test(timeout=600000), esto deberíamos añadirlo al menos en los tests de integración, ya que si se nos queda algún test bloqueado por base de datos o cualquier otra cosa puede causar problemas a nivel de servidor de integración continua. 
  • Timeout a nivel global: @Rule public Timeout globalTimeout = new Timeout(600000);

maven-release-plugin configuración

COMANDOS PARA SU UTILIZACIÓN

Se recomiendo utilizar estos comandos con el IDE cerrado y por línea de comandos para evitar bloqueos de directorios.
Los comandos para usar la release son los siguientes y en el siguiente orden:

mvn release:clean  Despues de ejecutar prepare se quedan unos ficheros en local que se eliminan utilizando el clean.
mvn release:prepare  Este comando modifica los poms, comita a svn y crea el tag.
mvn release:perform -Dusername=developer -Dpassword=developer -DuseReleaseProfile=false  Después de crear el tag con prepare este comando generará la release. Despues ya podemos ejecutar mvn deploy para subir todos nuestros jars a archiva.

SI EL PASO PREPARE O EL PASO PERFORM DAN ALGÚN FALLO SE USARÁ ROLLBACK PARA VOLVER A LA VERSIÓN ANTERIOR
mvn release:rollback  En el caso de que al finalizar el release:prepare haya errores hay que ejecutar el rollback que elimina los cambios en local y la subida al trunk. Luego a mano se debería eliminar el tag ya que este no lo borra rollback.

Cosas a tener en cuenta:
Al realizar el comando "perform" se descarga en new-distribution-api/target el tag que se va a utilizar para hacer el deploy sobre tu repositorio de artefactos. Este directorio hay que limpiarlo a mano ya que a veces queda ahí.
Si falla el prepare se puede usar rollback sin problema, pero si falla el perform pero ya ha subido algún artefacto a archiva y usamos rollback nos encontraremos que la próxima vez que se intente realizar el perform de esa misma versión dará un mensaje de conflicto. Hay que eliminar a mano de archiva los jars subidos antes del error.

 <plugin>  
      <groupid>org.apache.maven.plugins</groupid>  
      <artifactid>maven-release-plugin</artifactid>  
      <version>2.5.1</version>  
      <configuration>  
           <autoversionsubmodules>true</autoversionsubmodules>  
           <allowtimestampedsnapshots>true</allowtimestampedsnapshots>  
           <preparationgoals>clean install -DignoreSnapshots=true</preparationgoals>  
           <username>${svn.username}</username>  
           <password>${svn.password}</password>  
           <tagbase>http://TUSUBVERSION/TUPROYECTO/tags/</tagbase>   
      </configuration>  
 </plugin>  

maven-checkstyle-plugin configuration usando la configuracion desde Sonar

 <plugin>  
      <groupid>org.apache.maven.plugins</groupid>  
      <artifactid>maven-checkstyle-plugin</artifactid>  
      <version>${maven-checkstyle-plugin-version}</version>  
      <configuration>  
           <includetestsourcedirectory>true</includetestsourcedirectory>  
           <configlocation>http://YOURSONARSERVER/profiles/export?format=checkstyle&amp;language=java&amp;name=YOURCHECKSTYLEFILERULES</configlocation>  
           <suppressionslocation>http://sonar.it.ods/checkstyle-suppressions.xml</suppressionslocation>    
           <suppressionsfileexpression>checkstyle.suppressions.file</suppressionsfileexpression>   
      </configuration>  
      <executions>   
           <execution>    
                <id>checkstyle</id>    
                <phase>validate</phase>    
                <goals>   
                     <goal>check</goal>   
                </goals>    
                <configuration>    
                     <failonviolation>true</failonviolation>  
                </configuration>  
           </execution>  
      </executions>  
      <dependencies>  
           <dependency>    
                <groupid>com.puppycrawl.tools</groupid>  
                <artifactid>checkstyle</artifactid>  
                <version>${checkstyle-version}</version>  
           </dependency>  
      </dependencies>   
 </plugin>  

Instalación JDK

Instalar el jdk recién bajado.  

Añadir o modificar las variables de entorno PATH y JAVA_HOME:   
    1. JAVA_HOME apuntando a la carpeta .....\Java\jdk1.8.0_25
    2. Añadir a la variable PATH ;%JAVA_HOME%\bin  
Para modificar de forma cómoda las variables de entorno en windows se puede usar la aplicación Rapid Environment Editor (http://www.rapidee.com/)

Configurar JDK en Eclipse
Window->Preferences->java:   En Installed JREs    -> Add -> Standard VM -> Directory -> Directory: y seleccionamos donde está el jdk recién instalado (...\Java\jdk1.8.0_25)
Una vez añadido, seleccionamos éste que acabamos de añadir.   En Compiler -> seleccionar JDK Compilance: jdk8
Si nuestros proyectos van con la misma versión de jdk, se aconseja quitar los demás jdks del IDE.

Uso de lombok en Eclipse

Utilizamos lombok para reducir la cantidad de código repetitivo mediante el uso de anotaciones. Es necesario instalar el plugin de lombok para compilar el proyecto.
 Lombok:  En C:\Maven3\org\projectlombok\lombok\{version utilizada en nuestro proyecto} -> doble click sobre el jar e instalar.  
Es necesario reiniciar el IDE para que cargue el plugin.

SPRING LOADED

Spring Loaded permite la creación y modificación de métodos “en caliente”.
Para hacer uso de esta herramienta hay que bajar el .jar de Spring Loaded de: https://github.com/spring-projects/spring-loaded (en el apartado installation).
Este jar lo metemos, por ejemplo, en la carpeta del eclipse.
Una vez bajado, en los VM Arguments que utilizamos para iniciar nuestra aplicación añadir el comando:
-javaagent:D:/sts-bundle/sts-3.6.1.RELEASE/spring-loaded/springloaded-1.2.1.RELEASE.jar –noverify

Siendo este comando válido para el jar “springloaded-1.2.1.RELEASE.jar”, que lo he copiado dentro de: D:/sts-bundle/sts-3.6.1.RELEASE/spring-loaded/

Unlocker por maven pre-clean

A veces windows bloquea ficheros del workspace, tipicamente de los target y da error al ejecutar mvn clean install debido a que no puede borrar estos ficheros bloqueados.
Para desbloquear directorios completos existe un programa windows llamado Unlocker http://unlocker.uptodown.com/
Después de instalarlo, con el visor normal de windows aparecerá en el botón derecho la opción "Unlocker".
Con este profile de maven llamado "unlockTargetFiles" que solo se activa en entornos windows. si encuentra en el path de windows Unlocker.java lo ejecutará automáticamente en la fase de pre-clean.
Para que esto funcione correctamente hay que añadir al PATH de windows la  ruta de instalacion del programa, por defecto es esta "C:\Program Files\Unlocker\" y  tambien la variable "UNLOCKER" con el valor "true".

   
 <profile>  
      <id>unlockTargetFiles</id>  
      <activation>  
           <os>  
                <family>windows</family>  
           </os>  
           <property>  
                <name>env.UNLOCKER</name>  
                <value>true</value>  
           </property>  
      </activation>  
      <build>  
           <plugins>  
                <plugin>  
                     <groupid>org.codehaus.mojo</groupid>  
                     <artifactid>exec-maven-plugin</artifactid>  
                     <version>1.4.0</version>  
                     <executions>  
                          <execution>  
                               <phase>pre-clean</phase>  
                               <goals>  
                                    <goal>exec</goal>  
                               </goals>  
                          </execution>  
                     </executions>  
                     <configuration>  
                          <executable>Unlocker</executable>  
                          <workingdirectory>${project.build.directory}</workingdirectory>  
                          <arguments>  
                               <argument>-L</argument>  
                          </arguments>  
                          <successcodes>  
                               <successcode>0</successcode>  
                               <successcode>1</successcode>  
                               <successcode>2</successcode>  
                          </successcodes>  
                     </configuration>  
                </plugin>  
           </plugins>  
      </build>  
 </profile>