7.1 Nggawe konverter jinis sampeyan dhewe

Kadhangkala ana kahanan nalika sampeyan pengin nyimpen jinis data sing cukup rumit ing siji kolom tabel. Yen Hibernate ngerti carane ngowahi menyang senar (lan bali), banjur kabeh iku apik. Yen ora, sampeyan kudu nulis konverter data dhewe.

Ayo dadi ngomong wong mutusaké kanggo nyimpen taun panganggo kang lair ing database minangka YY.MM.DD, contone 98.12.15:. Sampeyan uga kudu ngowahi menyang tanggal biasa 15/12/1998:. Banjur sampeyan kudu nulis konverter dhewe.

Kanggo nindakake iki, sampeyan kudu ngleksanakake antarmuka AttributeConverter<EntityType, DbType>.


@Converter(autoApply = true)
public class DateConverter implements AttributeConverter<java.time.LocalDate, String> {
 
    public String convertToDatabaseColumn(java.time.LocalDate date) {
    	return date.format("YY.MM.DD");
    }
 
    public java.time.LocalDate convertToEntityAttribute(String dbData) {
    	String[] data = dbData.split(".");
    	return LocalDate.of(data[2], data[1], "19"+data[0]);
    }
}

Lan, mesthi, konverter iki bisa ditambahake menyang lapangan apa wae (yen cocog karo jinis):


@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;
 
   @Column(name="join_date")
   @Convert(converter = DateConverter.class)
   public java.time.LocalDate date;
}

Konverter asring banget kudu digunakake yen sampeyan ora ngrancang database. Data ing kono bisa uga ana ing "format aneh". Tanggal bisa disimpen minangka strings, Booleans minangka CHAR kanthi nilai Y lan N, lan liya-liyane.

7.2 Nggawe jinis data kita dhewe

Elinga tabel kanthi dhaptar jinis sing dikenal kanggo Hibernate? Aku ngomong babagan jinis sing ditemtokake bebarengan karo anotasi @Type. Sampeyan bisa nulis jinis data dhewe, sing bisa digunakake kanthi cara sing padha karo jinis dibangun ing Hibernate.

Contone, kita pengin duwe jinis LocalTime, sing bakal disimpen ing database ora minangka TIME, nanging minangka VARCHAR. Lan, contone, kita duwe akses menyang database kuwi, lan kita ora diijini kanggo ngganti jinis data ing kolom sawijining. Banjur kita bisa nulis jinis Hibernate kita dhewe. Ayo diarani LocalTimeString.

Pisanan kita butuh kelas cilik sing bakal nggambarake jinis anyar kita:

public class LocalTimeStringType extends AbstractSingleColumnStandardBasicType<<LocalTime> {

    public static final LocalTimeStringType  INSTANCE = new LocalTimeStringType ();

    public LocalTimeStringType () {
    	super(VarcharTypeDescriptor.INSTANCE, LocalTimeStringJavaDescriptor.INSTANCE);
    }

    @Override
    public String getName() {
    	return "LocalTimeString";
    }
}

Iku soko saka jinis Enum kang kasusun saka siji nilai. Set saka enams siji kuwi kabeh jinis dikenal Hibernate.

Kita uga butuh kelas - analog saka konverter, sing bakal ngemot rong cara - wrap()lan unwrap()kanggo ngowahi nilai jinis LocalTime menyang String.

Iki bakal katon tanpa ngetrapake metode:

public class LocalTimeStringJavaDescriptor extends AbstractTypeDescriptor<LocalTime> {

    public static final LocalTimeStringJavaDescriptor INSTANCE =  new  LocalTimeStringJavaDescriptor();

    public LocalTimeStringJavaDescriptor() {
    	super(LocalTime.class, ImmutableMutabilityPlan.INSTANCE);
    }

    public <X> X unwrap(LocalTime value, Class<X> type, WrapperOptions options) {

    }

    public <X> LocalTime wrap(X value, WrapperOptions options) {

    }

}

Saiki ayo nulis implementasine metode kasebut:

public <X> X unwrap(LocalTime value, Class<X> type, WrapperOptions options) {

    if (value == null)
    	return null;

    if (String.class.isAssignableFrom(type))
    	return (X) LocalTimeType.FORMATTER.format(value);

    throw unknownUnwrap(type);
}

Lan cara kapindho:

@Override
public <X> LocalTime wrap(X value, WrapperOptions options) {
    if (value == null)
    	return null;

    if(String.class.isInstance(value))
    	return LocalTime.from(LocalTimeType.FORMATTER.parse((CharSequence) value));

    throw unknownWrap(value.getClass());
}

siyap. Sampeyan bisa nggunakake kelas iki kanggo nyimpen wektu minangka string:


@Entity
@Table(name="user")
class User
{
   @Id
   @Column(name="id")
   public Integer id;
 
   @Column(name="join_time")
   @Type(type = "com.codegym.hibernate.customtypes.LocalTimeStringType")  
   public java.time.LocalTime time;
}

7.3 Ndhaptar jinis sampeyan

Sampeyan uga bisa ndhaptar jinis data sajrone konfigurasi Hibernate. Iki rada ora pati penting.


ServiceRegistry serviceRegistry = StandardServiceRegistryBuilder()
    .applySettings(getProperties()).build();
                                                                                                                                                              	                                        	 
    MetadataSources metadataSources = new MetadataSources(serviceRegistry);
    Metadata metadata = metadataSources
  	.addAnnotatedClass(User.class)
  	.getMetadataBuilder()
  	.applyBasicType(LocalTimeStringType.INSTANCE)
  	.build();
                                                                                                                                                              	                                        	 
    SessionFactory factory =  metadata.buildSessionFactory();

Sampeyan kudu entuk MetadataSources, entuk MetadataBuilder saka iku, lan gunakake kanggo nambah kelas sampeyan. Iku bisa liwat hibernate.cfg.xml, nanging uga sethitik cumbersome.

Nanging sawise registrasi, sampeyan bisa nulis kaya iki:


@Entity
@Table(name="user")
class User
{
   @Id
   @Column(name="id")
   public Integer id;
 
   @Column(name="join_time")
   @Type(type = "LocalTimeString")  
   public java.time.LocalTime time;
}