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