martes, 18 de noviembre de 2014

JSF 2.0: dropdown menu a partir de una enumaración

Si nos basamos en el ejemplo Mapeando enumeraciones con Hibernate podemos implementar una clase entity como sigue,

public class Users implements Serializable {
    
    private Integer id;    
    private String username;
    private String password;
    private Roles roles;
        
    public Users() {
    }
  
    --- getters & setters ---
}

Esta clase será llamada en el ManagedBean junto con la clase Roles. Por tanto el ManagedBean quedaría como sigue,

@ManagedBean(name = "userBean")
@ViewScoped
public class UserBean implements Serializable {
    
    private Users newUser = new Users();
    private Roles[] roleses;
    
    private final Roles roleAdmin = Roles.ADMINISTRATOR;
    private final Roles roleUser = Roles.USER;

    --- getters & setters ---
}

En esta clase hemos declarado Roles como un array y por tanto su método Get correspondiente se puede implementar de la siguiente manera,

public Roles[] getRoleses() {
    roleses = Roles.values();
    return roleses;
}

con lo que recuperamos los valores de la enumeración como String. Entonces la página JSF se podría implementar de la siguiente manera,

<h:outputLabel for="userRoles" value="Roles" />
<h:selectOneMenu id="userRoles" value="#{userBean.newUser.roles}" >
    <f:selectItem itemLabel="Select role" noSelectionOption="true" />
    <f:selectItems value="#{userBean.roleses}" var="role"
        itemValue="#{role}" itemLabel="#{role.role}"/>
</h:selectOneMenu> 

Podemos encontrar una información completa en Stackoverflow.com

lunes, 17 de noviembre de 2014

Mapeando enumeraciones con Hibernate

Hibernate dispone de un mecanismo propio para mapear enumeraciones y relacionarlas directamente con las columnas de una tabla de una base de datos. Este mecanismo permite a su vez un mantenimiento del software más correcto y adecuado.Para explicar el funcionamiento de este mecanismo estableceremos un caso práctico.

Lo primero sería definir la enumeración,
public enum Roles implements PersistentEnum {
    
    ADMINISTRATOR("Administrator"), USER("User");
    
    private final String role;
    
    Roles(String role) {
        this.role = role;
    }
    
    @Override
    public String getRole() {
        return role;
    }
}


Hemos creado dos roles, el administrador para el backend de la página web y los usuarios para el frontend de la misma.

La interfaz PersistentEnum quedaría como sigue,
public interface PersistentEnum {
    public String getRole();
}


que en el caso de la clase enumeración implementaría el método getRole().

Ahora definimos el Hibernate User Type por medio de una clase abstracta que queda de la siguiente manera,
public abstract class PersistentEnumUserType<T extends PersistentEnum> implements UserType {
    
    private Class<T> clazz = null;
    private static final int[] SQL_TYPES = { Types.VARCHAR };

    protected PersistentEnumUserType(Class<T> c) {
        this.clazz = c;
    }

    @Override
    public int[] sqlTypes() {
       return SQL_TYPES;
    }

    @Override
    public Class returnedClass() {
        return clazz;
    }

    @Override
    public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor si, Object owner)
         throws HibernateException, SQLException {

        String name = resultSet.getString(names[0]);

        if (resultSet.wasNull())
            return null;
        
        for(Object value : returnedClass().getEnumConstants()) {
            if(name.equals(((PersistentEnum)value).getRole())) {
                return value;
            }
        }
        throw new IllegalStateException("Unknown " + returnedClass().getSimpleName() + " id");
    }

    @Override
    public void nullSafeSet(PreparedStatement preparedStatement, Object value,
         int index, SessionImplementor si) throws HibernateException, SQLException {

        if (null == value) {
            preparedStatement.setNull(index, Types.VARCHAR);
        } else {
            preparedStatement.setString(index, ((PersistentEnum)value).getRole());
        }
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return cached;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object replace(Object original, Object target, Object owner)
         throws HibernateException {
        return original;
    }
    
    public String objectToSQLString(Object value) {
        return '\'' + ((Enum) value).name() + '\'';
    }
 
    public String toXMLString(Object value) {
        return ((Enum) value).name();
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        return x.hashCode();
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        if (x == y)
            return true;
        if (null == x || null == y)
            return false;
        return x.equals(y);
    }
}


En este patrón lo principal son los métodos nullSafeGet() y nullSafeSet(). El primero es llamado cuando el resulset de la base de datos es mapeado a un Object, el segundo se llama para mapear los campos de un Object a los parámetros de una sentencia SQL (insert/update/delete). Finalmente el método returnedClass() será sobreescrito en las subclases para llamar a la enumeración,
public class RolesUserType extends PersistentEnumUserType<Roles> {
    
    public RolesUserType() {     
        super(Roles.class);
    }
    
    @Override
    public Class<Roles> returnedClass() {
        return Roles.class;
    }
}