Buscar este blog

domingo, 8 de noviembre de 2015

Java - Maven - Auto generate setter code for transformers class

I´ve been working with multi layered web applications for the last six years, and one thing I learned is that isolation is a fundamental concept. Each layer should only work with its own objects and should only know about objects of immediate next layer.
This is done by using DTOs (Data Transfer Objects) and transformers classes which convert between them. Usually the objects would have the same fields in different layers, over all if you are starting a project from scratch.

For example, suppose you have a class called UsuarioEntity in your Persistence Layer and a class Called Usuario in your Business Layer.
@Entity
@Table(name="USUARIO")
public class UsuarioEntity {
 @Id @GeneratedValue
 private Long id;

 private String nombre;

 private String nif;

 private String login;

 private String password;

 private Date fechaRegistro;

 private Boolean estaActivo;

 @ManyToOne(fetch=FetchType.EAGER)
 @JoinColumn(name="idTipo")
 private TipoUsuarioEntity tipo = new TipoUsuarioEntity();

(...)
}

public class Usuario {
 private Long id;
 private String nombre;
 private String nif;
 private String login;
 private String password;
 private Date fechaRegistro;
 private Boolean estaActivo;
 private TipoUsuario tipo = new TipoUsuario();

(...)
}

The class responsible for transform between UsuarioEntity and Usuario would receive a object UsuarioEntity and would return a object Usuario.

One option could be use Apache Commons BeanUtils.copyProperties (https://commons.apache.org/proper/commons-beanutils/javadocs/v1.8.3/apidocs/index.html) but I don't  like much because errors appear in runtime. If you change some property in Usuario, you would not notice until run the program.

So I prefer to use the setter/getter option, which leads to code like this:
public Usuario usuarioEntity2Usuario(UsuarioEntity usuarioEntity) {
 Usuario usuario = new Usuario();
 
 //bored setter and getter here
  
 return usuario;
}

But this is a tedious task, more tedious the more classes you have.
What I made was a java snippet that, by reflection, generates thesesetters using one of the classes involved. This is valid only when both classes are quite similar.
public class SetterGetterGeneratorServiceImpl implements SetterGetterGeneratorService {

    @Override
    public String generateSetters(final Class<?> clazz, final String objectSet, final String objectGet) {
        final StringBuilder codigoJava = new StringBuilder();

        for (final Method method : clazz.getDeclaredMethods()) {
            if (method.getName().startsWith("set")) {
                codigoJava.append(objectSet).append(".").append(method.getName()).append("(").append(objectGet)
                        .append(".").append(convertSetEnGet(method.getName())).append("()").append(");\n");
            }
        }

        return codigoJava.toString();
    }


    private String convertSetEnGet(final String methodSetName) {
        return "get" + methodSetName.substring(3);
    }
}

When you call this method with your object class, the name of the object to make the setter and the name of the object to make de getter, you "almost" get the java code you need for your transformer.
codigo = setterGetterGeneratorService.generateSetters(Usuario.class, "usuario", "usuarioEntity");

usuario.setId(usuarioEntity.getId());
usuario.setPassword(usuarioEntity.getPassword());
usuario.setEstaActivo(usuarioEntity.getEstaActivo());
usuario.setFechaRegistro(usuarioEntity.getFechaRegistro());
usuario.setNombre(usuarioEntity.getNombre());
usuario.setNif(usuarioEntity.getNif());
usuario.setLogin(usuarioEntity.getLogin());
//usuario.setTipo(usuarioEntity.getTipo());


Going one step further, I put this code in a Maven plugin so you can invoke it from command line. The  project is in GitHub: https://github.com/evazquezma/maven.

To use this Plugin, you need to configure it in the pom file, and set the dependencies with your project classes, so it will can access your entity and business classes.
<build>
 <plugins>
  <plugin>
   <groupId>es.sisifo.plugins</groupId>
   <artifactId>code-generator</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <dependencies>
    <dependency>
     <groupId>(...)</groupId>
     <artifactId>(...)</artifactId>
     <version>(...)</version>
    </dependency>    
   </dependencies>
  </plugin>
 </plugins>
</build>

To launch de plugin just:
mvn code-generator:setter-getter -DclassName=xxxxxx.Usuario -DobjectSet=usuario -DobjectGet=usuarioEntity

No hay comentarios:

Publicar un comentario