Home > Software design >  Hibernate don't work in CommandLineRunner
Hibernate don't work in CommandLineRunner

Time:02-17

I am trying to make a simple hibernate application and when I am trying to run it using usual java class it works well, but when I am trying to run it using CommandLineRunner using Spring Boot it fails with an error

java.lang.IllegalStateException: Failed to execute CommandLineRunner
Caused by: org.hibernate.PropertyAccessException: Could not set field value [1] value by reflection : [class springboottest.entity.Item.id] setter of springboottest.entity.Item.id
Caused by: java.lang.IllegalArgumentException: Can not set int field springboottest.entity.Item.id to springboottest.entity.Item

when session.save(item1); executed.
CommandLineRunner works well, for example

@Service
public class DBInit implements CommandLineRunner
{
    @Override
    public void run(String[] args)
    {
        System.out.println("woring");
    }
}

prints "working" as expected.
Hibernate also works well if used with normal java class with main(), but Hibernate don't working inside run() in CommandLineRunner.
I don't use none of Spring Boot features here like dependency injection or something else, just plain java code.
So why I have an error and how to make it work?

// don't working
@Service
public class DBInit implements CommandLineRunner
{
    @Override
    public void run(String[] args)
    {
        Configuration configuration = new Configuration().configure();
        configuration.addAnnotatedClass(Item.class);
        SessionFactory sessionFactory = configuration.buildSessionFactory();

        try (Session session = sessionFactory.openSession())
        {
            Item item1 = new Item("itemName");
            session.beginTransaction();
            session.save(item1);
            session.getTransaction().commit();
        }
    }
}
// working well
public class DBInit
{
    public static void main(String[] args)
    {
        Configuration configuration = new Configuration().configure();
        configuration.addAnnotatedClass(Item.class);
        SessionFactory sessionFactory = configuration.buildSessionFactory();

        try (Session session = sessionFactory.openSession())
        {
            Item item1 = new Item("itemName");
            session.beginTransaction();
            session.save(item1);
            session.getTransaction().commit();
         }
    }
}

Item class

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;

@Entity
@Table(name = "items")
@NoArgsConstructor
public class Item
{
    @Id
    @GeneratedValue
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    @Getter
    @Setter
    private int id;
    
    @Getter
    @Setter
    @Column(nullable = false)
    private String name;
    
    public Item(String name)
    {
        this.name = name;
    }
}

hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="http://www.hibernate.org/xsd/orm/cfg">
    <session-factory>
        <property name="connection.url">jdbc:postgresql://localhost:5432/postgres</property>
        <property name="connection.driver_class">org.postgresql.Driver</property>
        <property name="connection.username">postgres</property>
        <property name="connection.password">123</property>
        <property name="dialect">org.hibernate.dialect.PostgreSQL94Dialect</property>
        <property name="show_sql">true</property>
        <property name="hbm2ddl.auto">create</property>
        <property name="format_sql">true</property>

        <mapping />
    </session-factory>
</hibernate-configuration>

CodePudding user response:

That code is mixing "old style" and spring boot. When DBInit.main runs without spring, it creates SessionFactory and when spring boot CommandLineRunner runs spring initialize EntityManagerFactory that provides all sessions after.

The difference is "sessionFactory" uses "hibernate.cfg.xml" it already has <mapping /> therefore it works as expected, but EntityManagerFactory does not use hibernate.cfg.xml, so mapping is broken. Check this for more details.

How to solve it, for spring you should use @Repository. The blog and here is the solution

package springboottest.entity;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ItemRepository  extends CrudRepository<Item, Integer> {
}

and DBinit service should be like below

@Service
public class DBInit implements CommandLineRunner
{
    @Autowired
    ItemRepository repo;

    @Override
    public void run(String[] args)
    {
        System.out.println("CommandLineRunner run() executing...");
        repo.save(new Item("ItemName"));
    }
}

cfg xml is not required and add properties

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=123
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.format-sql=true

that will make spring work properly.

PR: https://github.com/Denys-coder/Hibernate_dont_work_in_CommandLineRunner/pull/1

my repo

  • Related