6

Tengo un objeto Java hibernado-mapeado, JKL, que está lleno de un montón de campos normales de hibernación (como cadenas y números enteros).Asignación de una opción FunctionalJava <Type> con Hibernate

Me han añadido un nuevo campo incrustado (que vive en la misma tabla, no una asignación), asdf, que es fj.data.Option<ASDF>. He hecho una opción para dejar en claro que este campo puede no contener nada (en lugar de tener que manejar null cada vez que accedo a él).

¿Cómo configuro la asignación en mi archivo JKL.hbm.xml? Me gustaría que hibernate convierta automáticamente un null en la base de datos a un none de fj.data.Option<ASDF> cuando recupera el objeto. También debe convertir una instancia no nula de ASDF en some de fj.data.Option<ASDF>. ¿Hay algún otro truco que deba hacer? Gracias.

Respuesta

12

que sugeriría la introducción de FunctionalJava Option en los descriptores de acceso (getter y setter), mientras que deja Hibernate para manejar un campo java simple que se le permite ser null.

Por ejemplo, para un Integer campo opcional:

// SQL 
CREATE TABLE `JKL` (
    `JKL_ID` INTEGER PRIMARY KEY, 
    `MY_FIELD` INTEGER DEFAULT NULL 
) 

Puede asignar un campo privado de hibernación directamente:

// Java 
@Column(nullable = true) 
private Integer myField; 

A continuación, puede introducir Option en el límite de acceso:

// Java 
public fj.data.Option<Integer> getMyField() { 
    return fj.data.Option.fromNull(myField); 
} 

public void setMyField(fj.data.Option<Integer> value) { 
    myField = value.toNull(); 
} 

¿Funciona para sus necesidades?

2

Puede usar los tipos de mapas personalizados de Hibernate. La documentación es here. Aquí hay un ejemplo análogo de mapping Scala's Option a un mapeo de Hibernate.

En pocas palabras, necesitaría ampliar la interfaz org.hibernate.UserType. También podría crear una clase base de tipo genérico con un subtipo de JKL, similar a lo que ve en el ejemplo de Scala.

0

Creo que usando getter/setter es más sencillo, pero aquí es un ejemplo de lo que hice para hacer que funcione:

(Funciona bien para el número y la cadena, pero no para la fecha (error con @Temporal anotación)).

import com.cestpasdur.helpers.PredicateHelper; 
import com.google.common.annotations.VisibleForTesting; 
import com.google.common.base.Optional; 
import org.apache.commons.lang.ObjectUtils; 
import org.apache.commons.lang.StringUtils; 
import org.hibernate.HibernateException; 
import org.hibernate.usertype.UserType; 
import org.joda.time.DateTime; 

import java.io.Serializable; 
import java.sql.*; 

public class OptionUserType implements UserType { 


@Override 
public int[] sqlTypes() { 
    return new int[]{ 
      Types.NULL 
    }; 
} 

@Override 
public Class returnedClass() { 
    return Optional.class; 
} 

@Override 
public boolean equals(Object o, Object o2) throws HibernateException { 
    return ObjectUtils.equals(o, o2); 

} 

@Override 
public int hashCode(Object o) throws HibernateException { 
    assert (o != null); 
    return o.hashCode(); 
} 

@Override 
public Optional<? extends Object> nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { 
    return Optional.fromNullable(rs.getObject(names[0])); 
} 

@VisibleForTesting 
void handleDate(PreparedStatement st, Date value, int index) throws SQLException { 
    st.setDate(index, value); 
} 

@VisibleForTesting 
void handleNumber(PreparedStatement st, String stringValue, int index) throws SQLException { 
    Double doubleValue = Double.valueOf(stringValue); 
    st.setDouble(index, doubleValue); 
} 

@Override 
public void nullSafeSet(PreparedStatement st, Object value, int index) throws SQLException { 

    if (value != null) { 
     if (value instanceof Optional) { 
      Optional optionalValue = (Optional) value; 
      if (optionalValue.isPresent()) { 
       String stringValue = String.valueOf(optionalValue.get()); 


       if (StringUtils.isNotBlank(stringValue)) { 

        if (PredicateHelper.IS_DATE_PREDICATE.apply(stringValue)) { 
         handleDate(st, new Date(DateTime.parse(stringValue).getMillis()), index); 
        } else if (StringUtils.isNumeric(stringValue)) { 
         handleNumber(st, stringValue, index); 
        } else { 
         st.setString(index, optionalValue.get().toString()); 
        } 
       } else { 
        st.setString(index, null); 
       } 


      } else { 
       System.out.println("else Some"); 
      } 

     } else { 
      //TODO replace with Preconditions guava 
      throw new IllegalArgumentException(value + " is not implemented"); 

     } 
    } else { 
     st.setString(index, null); 

    } 


} 

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

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

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

@Override 
public Object assemble(Serializable serializable, Object o) throws HibernateException { 
    return serializable; 
} 

@Override 
public Object replace(Object original, Object target, Object owner) throws HibernateException { 
    return original; 
} 
} 
Cuestiones relacionadas