I'm developing a web app and deploying it on Tomcat 7.0. My app uses a MySQL database. I've already configured connection between app and database and wanted to add Hibernate 5.2.5 support. I can communicate with database via Hibernate console with configuration below, and it works when I use it in non-web app. The problem is only when I deploy it on server. I get warning
no persistent classes found for query class: from entities.UserH
and then 500 server error caused by it.
My entity class:
#Entity
#Table(name = "users", uniqueConstraints = {#UniqueConstraint(columnNames = {"id"})})
public class UserH {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, unique = true, length = 11)
private int id;
#Column(name = "login", nullable = false, length = 45)
private String login;
#Column(name = "name", nullable = false, length = 45)
private String name;
#Column(name = "surname", nullable = false, length = 45)
private String surname;
/* getters and setters*/
}
My hibernate-annotation.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection properties - Driver, URL, user, password -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/web-database</property>
<property name="hibernate.connection.username">username</property>
<property name="hibernate.connection.password">password</property>
<!-- org.hibernate.HibernateException: No CurrentSessionContext configured! -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- Mapping with model class containing annotations -->
<mapping class="entities.UserH"/>
</session-factory>
</hibernate-configuration>
Method that should get users:
public List<UserH> getAllUsers() {
try (Session session = HibernateUtils.getSessionAnnotationFactory().getCurrentSession()) {
session.beginTransaction();
Query<UserH> usersQuery = session.createQuery("from entities.UserH", UserH.class);
List<UserH> usersList = usersQuery.getResultList();
session.getTransaction().commit();
return usersList;
}
}
As I mentioned - it works ok with normal app, but not with Tomcat. I added all available elements to web artifacts, but it didn't help. I even tried to add JPA support with persistance.xml, but still with no luck.
What else could be the problem?
edit: My HibernateUtils class:
public class HibernateUtils {
private static SessionFactory sessionAnnotationFactory;
private static SessionFactory buildSessionAnnotationFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
Configuration configuration = new Configuration();
configuration.configure("hibernate-annotation.cfg.xml");
System.out.println("Hibernate Annotation Configuration loaded");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
System.out.println("Hibernate Annotation serviceRegistry created");
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionAnnotationFactory() {
if (sessionAnnotationFactory == null)
sessionAnnotationFactory = buildSessionAnnotationFactory();
return sessionAnnotationFactory;
}
}
Maybe this is not a proper answer fot my question, but this is what actually worked for me. I replaced hibernate with JPA configuration + hibernate.
So instead of using hibernate-annotation.cfg.xml + Session I used persistance.xml + EntityManager:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="NewPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>entities.UserH</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/web-database"/>
<property name="javax.persistence.jdbc.user" value="Admin"/>
<property name="javax.persistence.jdbc.password" value="password2#"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
getEntityManager:
public static EntityManager getEntityManager() {
EntityManager entityManager = Persistence
.createEntityManagerFactory("NewPersistenceUnit")
.createEntityManager();
return entityManager;
}
getAllUsers:
public List<UserH> getAllUsers() {
EntityManager entityManager = HibernateUtils.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
TypedQuery<UserH> usersQuery = entityManager.createQuery("from UserH ", UserH.class);
List<UserH> usersList = usersQuery.getResultList();
transaction.commit();
entityManager.close();
return usersList;
}
However, I still don't understand why this configurations works while hibernate alone didn't. Any comments/suggestions would be appreciated.
You should just change your query to reference only the class name:
session.createQuery( "FROM UserH", UserH.class )
The only time the package is important would be when you're defining entities as inner classes.
For those cases, you'd need to use the full class name, com.c.SomeOutterClass$MyEntity. Another alternative is to change the #Entity annotation so that it includes the name attribute so you explicitly name your entity class:
public class SomeOutterClass {
#Entity(name = "MyEntity")
public static class MyEntity {
}
}
Related
i want to create and add to database user with enum
but cannot create instance
Required type:javax.management.relation.Role
Provided: cinema.entity.Role
how to fix it
user class
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String login;
private String password;
#Enumerated(EnumType.STRING)
#Column(name = "role")
private Role role;
}
enum
public enum Role {
USER, MANAGER, ADMIN
}
db
hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:postgresql://localhost:5432/cinema</property>
<property name="connection.username">user</property>
<property name="connection.password">user</property>
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQL10Dialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<mapping class="cinema.entity.User"/>
<mapping class="cinema.entity.Film"/>
<mapping class="cinema.entity.Ticket"/>
<mapping class="cinema.entity.Role"/>
<!-- DB schema will be updated if needed -->
<!-- <property name="hibernate.hbm2ddl.auto">update</property> -->
</session-factory>
</hibernate-configuration>
trying to run
public class Runner {
public static void main(String[] args) {
Configuration configuration = new Configuration();
// либо в cfg прописать
// configuration.addAnnotatedClass(User.class);
// configuration.addAnnotatedClass(Ticket.class);
// configuration.addAnnotatedClass(Film.class);
configuration.configure();
try (SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession()) {
session.beginTransaction(); // начало
User user = User.builder()
.login("ivan#gmal.com")
.password("pass")
// Required type:javax.management.relation.Role
// Provided: cinema.entity.Role
.role(Role.USER) //got an error
.build();
session.save(user);
session.getTransaction().commit();//конец
}
}
}
i want to create and add to database user with enum
but cannot create instance
Required type:javax.management.relation.Role
Provided: cinema.entity.Role
how to fix it
i just found out about the #Formula Annotation in Hibernate, but cannot get it to work.
I Tried using a hibernate Session to access the entites as well as a JPA Entitymanager with persistence.xml, in both cases my #Formula annotated field remains "null".
my Entity (copied from an Example):
#Entity(name = "Account")
public static class Account {
#Id
#GeneratedValue( strategy = GenerationType.IDENTITY )
private Long id;
private Double credit;
private Double rate;
#Formula(value = "credit * rate")
private Double interest;
//Getters and setters omitted for brevity
}
My Test-Setup (initializing a Session an an entitymanager for Test cases):
private SessionFactory sessionFactory;
private Session session = null;
EntityManager em;
#Before
public void before() {
EntityManagerFactory emf=Persistence.createEntityManagerFactory("test-pu");
em=emf.createEntityManager();
Configuration configuration = new Configuration();
configuration.addAnnotatedClass(TestEntity.class);
configuration.addAnnotatedClass(Account.class);
configuration.setProperty("hibernate.dialect",
"org.hibernate.dialect.PostgreSQL94Dialect");
configuration.setProperty("hibernate.connection.driver_class",
"org.postgresql.Driver");
configuration.setProperty("hibernate.connection.url",
"jdbc:postgresql://localhost:5432/Archiv");
configuration.setProperty("hibernate.hbm2ddl.auto",
"create");
configuration.setProperty("hibernate.connection.username",
"postgres");
configuration.setProperty("hibernate.connection.password",
"postgres");
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.openSession();
}
The persistence.xml for the entitymanager:
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="test-pu" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.test.ORMTest$Account</class>
<class>com.test.ORMTest$TestEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL94Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/Archiv"/>
<property name="hibernate.connection.username" value="postgres"/>
<property name="hibernate.connection.password" value="postgres"/>
<property name="hibernate.format_sql" value="true"/>
<property name="javax.persistence.validation.mode" value="NONE"/>
<property name="hibernate.service.allow_crawling" value="false"/>
<property name="hibernate.session.events.log" value="true"/>
</properties>
</persistence-unit>
</persistence>
And last but not least, the Test Code:
#Test public void emTest(){
em.getTransaction().begin();
Account account = new Account();
account.credit=100.0;
account.rate=0.1;
em.persist(account);
em.getTransaction().commit();
em.getTransaction().begin();
Account account1 = em.find(Account.class, 1l);
Double d = account1.getInterest();
System.out.println(d);
em.getTransaction().commit();
}
#Test
public void sessionTest() {
Transaction transaction = session.beginTransaction();
Account account = new Account();
account.credit=100.0;
account.rate=0.1;
session.save(account);
transaction.commit();
transaction = session.beginTransaction();
Account account1= session.get(Account.class, 1);
Double d = account1.getInterest();
System.out.println(d);
transaction.commit();
}
Both Cases print "null" for d.
According to the examples both cases should work. Anyone firm with Hibernate to tell me where i went wrong ?:/
Make sure that the object you expect to be set with Formula, is not getting loaded from the cache(where it having the same not set)
i'm trying to make a simple multitenant example to run, using Eclipselink 2.5.2, and MySQL.
When trying to persist an entity asigned to a tenant id, mysql server throws an error: "Table 'jpatest.tenant1_userdata' doesn't exist". (userdata being the entity, jpatest the database name, and tenant1 the tenant-id)
The table indeed doesn't exist, the database jpatest do exist. I was expecting eclipselink to autogenerate the tables each time i try to persist with a new tenant id.
So the question would be:
How can i force Eclipselink to create the tables?
If that is not possible; How can i create tables at runtime?
Here's the code:
Entity:
#Entity
#Table(name = "userdata")
#Multitenant(value = MultitenantType.TABLE_PER_TENANT)
#TenantTableDiscriminator(type = TenantTableDiscriminatorType.PREFIX, contextProperty = "tenant-id")
public class UserData implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private static final long serialVersionUID = 1L;
private String name;
.
.
.
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="MultiTeanantTest" transaction-type="RESOURCE_LOCAL">
<class>UserData</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpatest" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.create-database-schemas" value="true"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
Main class:
public class Main {
public static void main(String[] args) {
UserData ud = new UserData();
ud.setNombre("John);
Map properties = new HashMap<>();
properties.put("tenant-id", "tenant1");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MultiTeanantTest", properties );
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(ud);
em.getTransaction().commit();
}
}
Hope someone can give me a tip in what i'm doing wrong.
DDL generation will not be supported in a Multitenant Scenario by Eclipselink.
Refer to this link for more information, https://wiki.eclipse.org/EclipseLink/DesignDocs/Multi-Tenancy/TablePerTenant
I am porting a java fat client from JDBC SQLite to Hibernate H2.
Until now I tried to separate all my database code in separate classes, like
TableTeam or TableMember, which have methods like .getAllTeams() or .updateTeam(Team t). These methods acted as a wrapper around their sql queries they executed.
Now with hibernate I tried to leave the interface as good as possible and just change the SQL queries to hibernate functions, which mostly works.
With one exception: updating elements.
team = new Team(-1, "Team Name", Collections.<Member>emptySet());
#Test
public void testUpdateTeam() throws Exception {
table.addTeam(team);
team.setName("New Name");
table.updateTeam(team);
Team f = table.getAllTeams().get(0);
Assert.assertEquals(team, f);
}
results in the following exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ch.tiim.sco.database.model.Team.members, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:576)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:215)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:156)
at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:160)
at java.util.AbstractSet.equals(AbstractSet.java:92)
at org.hibernate.collection.internal.PersistentSet.equals(PersistentSet.java:441)
at ch.tiim.sco.database.model.Team.equals(Team.java:81)
at org.junit.Assert.isEquals(Assert.java:131)
at org.junit.Assert.equalsRegardingNull(Assert.java:127)
at org.junit.Assert.assertEquals(Assert.java:111)
at org.junit.Assert.assertEquals(Assert.java:144)
at ch.tiim.sco.database.TableMemberTest.testEditTeam(TableMemberTest.java:45)
The code for .updateTeam(Team t) is the following:
public void updateTeam(Team t) {
Session s = sessionFactory.getCurrentSession();
s.beginTransaction();
s.update(t);
s.getTransaction().commit();
}
And the same for .addTeam(Team t) but s.save(t) instead of s.update(t)
And Team looks like this:
#Entity
#Table(name = "team")
public class Team implements Model {
#Id
#GeneratedValue
#Column(name = "team_id")
private int id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "club_id")
private Club club;
#ManyToMany
#JoinTable(name = "team_members",
joinColumns = {#JoinColumn(name = "team_id")},
inverseJoinColumns = {#JoinColumn(name = "member_id")}
)
private java.util.Set<Member> members;
//I stripped the constructor and the setters/getters
}
Now how do I get rid of this error, without guaranteeing that every call to hibernate is from the same thread?
Edit Here is the hibernate configuration
<?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>
<!-- Database connection settings -->
<property name="connection.driver_class">org.h2.Driver</property>
<!--property name="connection.url">jdbc:h2:./test</property-->
<property name="connection.username">user</property>
<property name="connection.password">pass</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<!--property name="show_sql">true</property-->
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
</session-factory>
</hibernate-configuration>
For Junit testcases you need to bind an opened Session to the current Thread.
SessionFactory sf = null;
Session s = null;
SessionHolder holder = null;
#Override
protected void onSetUp() throws Exception {
System.out.println("On SetUP----");
sf = (SessionFactory) beanFactory.getBean("sessionFactory");
s = sf.openSession();
TransactionSynchronizationManager.bindResource(sf, new SessionHolder(s));
}
#Override
protected void onTearDown() throws Exception {
System.out.println("On onTearDown----");
// unbind and close the session.
holder = (SessionHolder)TransactionSynchronizationManager.getResource(sf);
s = holder.getSession();
s.flush();
TransactionSynchronizationManager.unbindResource(sf);
SessionFactoryUtils.releaseSession(s, sf);
// teardown code here
}
If you want to no more care about LazyInitialisationException read this, its well explain what happens, and how to resolve the problem definitely
Can you post your hibernate.cfg? I suspect? you don't have a configured session context:
E.g
thread
I'm using Hibernate 4.3.6 and Glassfish 4.0 for my ejb project.
My test Dao class :
#PersistenceContext
private EntityManager entityManager;
public void saveTest(){
Foo testFoo = new Foo();
testFoo.setSomething("test");
entityManager.persist(testFoo);
entityManager.flush();
}
and POJO class Foo.class:
#Entity
#Table(name = "FOO")
public class Foo implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String something;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "T_ID", unique = true, nullable = false, precision = 15, scale = 0)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "T_SOMETHING", length = 50)
public String getSomething() {
return something;
}
public void setSomething(String something) {
this.adi = something;
}
}
persistence.xml :
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="TestAppUnit" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/TestApp</jta-data-source>
<class>com.example.test.Foo</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9iDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
I can list table data, get data with query and i can remove data from table. But i can't persist or merge.
Exception is:
IllegalArgumentException occurred calling getter of com.example.test.Foo.id
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:192)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:346)
at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4746)
at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:4465)
at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:243)
at org.hibernate.event.internal.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:511)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:100)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:684)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:676)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:671)
....
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:169)
Where am I doing wrong?
This project working on Glassfish 3.1 with persistence.xml version 1.0(jpa) and without this line :
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
Thanks in advance
I found it. Maybe others they encounter this problem. I wanted to share the solution.
The problem caused from Hibernate and "#PersistenceContext" annotation.
I change to Hibernate version to 4.3.5 and problem solved. Hibernate 4.3.6 and 4.3.7 has same problem. It's caused by different classloaders. Ejb Classloader and web app Classloader is different.