Sunday, 27 November 2022

Hibernate 6: work with byte arrays

Hibernate maps byte[] and Byte[] values to the JDBC VARBINARY type by default.

 

Can I specify the byte array length?

We can set the maximum length of this byte array using length attribute of the Column annotation.

 

By any chance,  if the maximum length specified by you is too big to fit into the largest VARBINARY column supported by underlying database, Hibernate will automatically upgrade the column type to IMAGE, BLOB, or whatever is the equivalent type for your database.

 

Example

// mapped to 'arr1 varbinary(255)'
private byte[] arr1;

// mapped to 'arr2 varbinary(30)'
@Column(length = 30)
private byte[] arr2;

// mapped to 'arr3 varbinary(32600)'
@Column(length = Length.LONG)
private byte[] arr3;

Find the below working application.

 

Step 1: Create new maven project ‘hibernate-byte-array-demo’.

 

Step 2: Update pom.xml with maven dependencies.

 

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample.app</groupId>
    <artifactId>hibernate-byte-array-demo</artifactId>
    <version>1</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <java.version>15</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>

    </properties>

    <dependencies>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.1.214</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.1.2.Final</version>
        </dependency>

        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>javax.persistence-api</artifactId>
            <version>2.2</version>
        </dependency>


    </dependencies>
</project>

Step 3: Define entity class.

 

Demo.java

package com.sample.app.entity;

import org.hibernate.Length;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "demo")
public class Demo {
    @Id
    private int id;

    // mapped to 'arr1 varbinary(255)'
    private byte[] arr1;

    // mapped to 'arr2 varbinary(30)'
    @Column(length = 30)
    private byte[] arr2;

    // mapped to 'arr3 varbinary(32600)'
    @Column(length = Length.LONG)
    private byte[] arr3;

    public Demo(int id, byte[] arr1, byte[] arr2, byte[] arr3) {
        this.id = id;
        this.arr1 = arr1;
        this.arr2 = arr2;
        this.arr3 = arr3;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public byte[] getArr1() {
        return arr1;
    }

    public void setArr1(byte[] arr1) {
        this.arr1 = arr1;
    }

    public byte[] getArr2() {
        return arr2;
    }

    public void setArr2(byte[] arr2) {
        this.arr2 = arr2;
    }

    public byte[] getArr3() {
        return arr3;
    }

    public void setArr3(byte[] arr3) {
        this.arr3 = arr3;
    }

}

Step 4: Create hibernate.cfg.xml file under src/main/resources folder.

 

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

    <session-factory>
        <!-- JDBC Database connection settings -->
        <property name="connection.driver_class">org.h2.Driver</property>
        <property name="connection.url">jdbc:h2:mem:test</property>
        <property name="connection.username">admin</property>
        <property name="connection.password">admin</property>
        <property name="connection.pool_size">1</property>

        <property name="dialect">org.hibernate.dialect.H2Dialect</property>
        <!-- Echo the SQL to stdout -->
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="current_session_context_class">thread</property>
        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">create-drop</property>
        
        <!-- dbcp connection pool configuration -->
        <property name="hibernate.dbcp.initialSize">2</property>
        <property name="hibernate.dbcp.maxTotal">10</property>
        <property name="hibernate.dbcp.maxIdle">5</property>
        <property name="hibernate.dbcp.minIdle">3</property>
        <property name="hibernate.dbcp.maxWaitMillis">-1</property>

        <!-- mappings for annotated classes -->
        <mapping class="com.sample.app.entity.Demo" />

    </session-factory>

</hibernate-configuration>

Step 5: Define main application class.

 

App.java

package com.sample.app;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import com.sample.app.entity.Demo;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;

public class App {
    private static final SessionFactory SESSION_FACTORY = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {

            final StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
                    .configure("hibernate.cfg.xml").build();

            final Metadata metaData = new MetadataSources(standardRegistry).getMetadataBuilder().build();

            return metaData.getSessionFactoryBuilder().build();

        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }

    }

    private static <T> List<T> loadAllData(Class<T> clazz, Session session) {
        final CriteriaBuilder builder = session.getCriteriaBuilder();
        final CriteriaQuery<T> criteria = builder.createQuery(clazz);
        criteria.from(clazz);
        return session.createQuery(criteria).getResultList();
    }

    public static void main(final String args[]) throws IOException, SQLException {
        String msg = "Hello World";
        byte[] data = msg.getBytes();

        Demo e1 = new Demo(1, data, data, data);

        try (final Session session = SESSION_FACTORY.openSession()) {
            session.beginTransaction();

            session.persist(e1);

            session.flush();
            session.getTransaction().commit();

            List<Demo> records = loadAllData(Demo.class, session);

            for (Demo record : records) {
                int id = record.getId();
                System.out.println("id : " + id);

                byte[] arr1 = record.getArr1();
                byte[] arr2 = record.getArr2();
                byte[] arr3 = record.getArr3();
                
                System.out.println("arr1 : " + new String(arr1));
                System.out.println("arr2 : " + new String(arr2));
                System.out.println("arr3 : " + new String(arr3));
            }
        }

    }
}

Total project structure looks like below.




Run App.java, you will see below messages in the console.


Aug 17, 2022 2:58:54 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.1.2.Final
Aug 17, 2022 2:58:54 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Aug 17, 2022 2:58:54 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.h2.Driver
Aug 17, 2022 2:58:54 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:h2:mem:test]
Aug 17, 2022 2:58:54 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {password=****, user=admin}
Aug 17, 2022 2:58:54 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Aug 17, 2022 2:58:54 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 1 (min=1)
Aug 17, 2022 2:58:54 PM org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl logSelectedDialect
INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Aug 17, 2022 2:58:55 PM org.hibernate.metamodel.internal.EntityInstantiatorPojoStandard resolveConstructor
INFO: HHH000182: No default (no-argument) constructor for class: com.sample.app.entity.Demo (class must be instantiated by Interceptor)
Hibernate: 
    
    drop table if exists demo cascade 
Aug 17, 2022 2:58:55 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@4832f03b] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: 
    
    create table demo (
       id integer not null,
        arr1 varbinary(255),
        arr2 varbinary(30),
        arr3 varbinary(32600),
        primary key (id)
    )
Aug 17, 2022 2:58:55 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@1391af3b] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: 
    insert 
    into
        demo
        (arr1, arr2, arr3, id) 
    values
        (?, ?, ?, ?)
Hibernate: 
    select
        d1_0.id,
        d1_0.arr1,
        d1_0.arr2,
        d1_0.arr3 
    from
        demo d1_0
id : 1
arr1 : Hello World
arr2 : Hello World
arr3 : Hello World

You can download complete working application from this link.


 

Previous                                                    Next                                                    Home

No comments:

Post a Comment