Mapping a FunctionalJava Option with Hibernate

后端 未结 3 1769
萌比男神i
萌比男神i 2020-12-19 08:46

I have a hibernate-mapped Java object, JKL, which is full of a bunch of normal hibernate-mappable fields (like strings and integers).

I\'m added a new e

相关标签:
3条回答
  • 2020-12-19 08:58

    You can use Hibernate's custom mapping types. Documentation is here. Here is an analogous example of mapping Scala's Option to a Hibernate mapping.

    Simply put, you would need to extend the org.hibernate.UserType interface. You could also create a generic-typed base class with a JKL-typed sub-type, similar to what you see in the Scala example.

    0 讨论(0)
  • 2020-12-19 09:09

    I would suggest introducing FunctionalJava's Option in the accessors (getter and setter), while leaving Hibernate to handle a simple java field which is allowed to be null.

    For example, for an optional Integer field:

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

    You can map a Hibernate private field directly:

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

    You could then introduce Option at the accessor boundary:

    // Java
    public fj.data.Option<Integer> getMyField() {
        return fj.data.Option.fromNull(myField);
    }
    
    public void setMyField(fj.data.Option<Integer> value) {
        myField = value.toNull();
    }
    

    Does that work for your needs?

    0 讨论(0)
  • 2020-12-19 09:18

    I think using getter/setter is simpler, but here's an example of what I did to make it work :

    (It works fine for number and string, but not for date (error with @Temporal annotation)).

    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;
    }
    }
    
    0 讨论(0)
提交回复
热议问题