Home » Java » java – How to pass a parameter to the hibernate AttributeConverter-Exceptionshub

java – How to pass a parameter to the hibernate AttributeConverter-Exceptionshub

Posted by: admin February 25, 2020 Leave a comment

Questions:

If I have a AttributeConverter that changes the length of the input before persisting it in the database, what would be the correct way to make sure that the modified input doesn’t exceed the maximum length allowed by that column (without hardcoding it in the converter) ?

@Column(length = 1024)
@Convert(converter = MyConverter.class)
private String comment;

public class MyConverter implements AttributeConverter<String, String> {

   @Override
   public String convertToDatabaseColumn(String attribute) {
      return "hello world " + attribute;
   }
   ...
}
How to&Answers:

You can achieve what you want with hibernate custom basic type that implements DynamicParameterizedType interface.

Below you can see a simple example of declaration custom type that read the length property of @Column annotation.

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Objects;
import java.util.Properties;

import javax.persistence.Column;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.DynamicParameterizedType;
import org.hibernate.usertype.UserType;

public class PersistableString implements UserType, DynamicParameterizedType
{
   private int sqlType;
   private int columnLength;

   public PersistableString()
   {
      this.sqlType = Types.VARCHAR;
   }

   @Override
   public void setParameterValues(Properties parameters)
   {
      ParameterType reader = (ParameterType) parameters.get(PARAMETER_TYPE);
      this.columnLength = getLength(reader);
   }

   private int getLength(ParameterType reader)
   {
      int length = -1; // default length
      for (Annotation annotation : reader.getAnnotationsMethod()){
         if (annotation instanceof Column) {
            length =  ((Column) annotation).length();
         }
      }
      return length;
   }

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

   @Override
   public Class<?> returnedClass()
   {
      return String.class;
   }

   @Override
   public boolean equals(Object x, Object y) throws HibernateException
   {
      return Objects.equals(x, y);
   }

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

   /*
      This method will be called when hibernate initializes your entity's
      field from the appropriate database table row
   */
   @Override
   public Object nullSafeGet(ResultSet rs,
         String[] names,
         SharedSessionContractImplementor session,
         Object owner) throws HibernateException, SQLException 
   {
      // you can use this.columnLength here
      return rs.getString(names[0]);
   }

   /*
      This method will be called when hibernate persists your entity's field
      to the appropriate database table row
   */
   @Override
   public void nullSafeSet(PreparedStatement st,
         Object value,
         int index,
         SharedSessionContractImplementor session) throws HibernateException, SQLException
   {
      // you can use this.columnLength here
      if (value == null) {
         st.setNull(index, sqlType);
      }
      else {
         String val = (String) value;
         st.setString(index, val);
      }
   }

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

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

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

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

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

and usage:

import org.hibernate.annotations.Type;


@Entity
@Table
public class Account
{

   @Column(name = "acc_name", length = 50)
   @Type(type = "com.example.hibernate.PersistableString")
   private String name;

   @Column(name = "acc_pass", length = 30)
   @Type(type = "com.example.hibernate.PersistableString")
   private String pass;

   @Column(name = "acc_email", length = 355)
   @Type(type = "com.example.hibernate.PersistableString")
   private String email;
}