Pageable sorting problems with Spring JPA - spring

I'm haccing an issue with Spring JPA regarding sorting and paginating. Currently I'm receiving this warning:
WARN [NamedQuery] (NamedQuery.java:65) - Finder method public abstract org.springframework.data.domain.Page loc.starterkit.business.entities.application.repository.ApplicationRepository.findByNameLike(java.lang.String,org.springframework.data.domain.Pageable)
is backed by a NamedQuery but contains a Pageable parameter! Sorting delivered via this Pageable will not be applied!
My JPA interface code looks like this:
public interface ApplicationRepository extends PagingAndSortingRepository<Application,Long>{
Page<Application> findByNameLike(String name, Pageable pageable);
}
My entity factory configuration:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="packagesToScan" value="loc.starterkit.business"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceUnitName" value="general" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.connection.charSet">${hibernate.connection.charSet}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.use_sql_comments">${hibernate.use_sql_comments}</prop>
<prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
</props>
</property>
</bean>
I don't know why I cannot use sorting in pageable methods in this case . Any ideas?
EDIT:
My Application Entity
#Entity
#Table(name="APPLICATION")
public class Application {
#Id
#Column(name="ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name="NAME")
private String name;
#Column(name="DESCRIPTION")
private String description;
public Application() {
super();
}
.... (getters and setters here)
}
Changing PagingAndSortingRepository to JPARepository seems to throw same warning. BUT, after some tests, I've found out that this WARN means nothing. Things seems to work nicely:
Hibernate:
/* select
count(*)
from
Application as generatedAlias0
where
generatedAlias0.name like :param0 */ select
count(*) as col_0_0_
from
APPLICATION applicatio0_
where
applicatio0_.NAME like ?
Hibernate:
/* select
generatedAlias0
from
Application as generatedAlias0
where
generatedAlias0.name like :param0
order by
generatedAlias0.name asc */ select
applicatio0_.ID as ID0_,
applicatio0_.DESCRIPTION as DESCRIPT2_0_,
applicatio0_.NAME as NAME0_
from
APPLICATION applicatio0_
where
applicatio0_.NAME like ?
order by
applicatio0_.NAME asc limit ?
So I think that this WARN means nothing but I want to know why it's being issued

Related

Exception Illegal Argument - unknown entity JPA - Additional package to scan for entities in application-context.xml is not taken into consideration

I am working on a Spring application which has a persistence unit configured in the application-context.xml. I need to add an additional package in in order to use new entities.
Even though this part of the persistence.xml file looks like below, my entities from the additional package are not seen by the application and I get an exception saying that the entity is unknown.
<bean id="transactionManager_students" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryStudents" />
<qualifier value="clientTransaction" />
</bean>
<bean id="entityManagerFactoryStudents"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource_College" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan">
<list>
<value>com.load.model</value>
<value>com.students.entity</value>
</list>
</property>
<property name="persistenceUnitName" value="unit_stud" />
<property name="jpaProperties">
<props>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.hbm2ddl.auto">none</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>  
I also have to mention that I annotated the entities with #Entity and in the class where I am operating on the entities I have this ( the row with em.persist(student) is giving me the error )
#PersistenceContext(unitName = "unit_stud")
public EntityManager em;
public Student student;
#Transactional(value = "clientTransaction", propagation = Propagation.REQUIRED)
public long persistStudentObject() {
long studentId = 0;
try
{
logger.debug("Start Persisting...");
em.persist(student);
// unique ID
studentId = student.getId();
logger.debug("Persisting OK...");
}
catch (PersistenceException persistenceException)
{
logger.error("PersistenceException occur", persistenceException);
}
}
return studentId ;
}
The entity:
package com.students.entity;
#Entity
#Table(name = "STUDENTS", schema = "DEMO", catalog = "")
public class Student{
private long id;
private String firstname;
private String name;
private String streetnumber;
private String zipcodecity;
Can anyone help me? I do not know what to do in order to make my entities visible.

How to use HibernateTemplate?

I am performing retrieval operation to get list of students from database. But I am getting 'empty' data from database. Used HibernateTemplate in
Spring with Hibernate integration,
domain class:-
#Entity
#Table(name="student")
public class StdBO {
#Id
private int sno;
private String sname,sadd;
//setters and getters
}
How can I use HibernateCallBack() interface for search operation? This is my first time that integrating spring with hibernate, is the below way correct? I tried many ways to perform search operations using HibernateTemplate but failing to get the details
DAO
#Repository
public class StdDAO {
private HibernateTemplate ht;
public void setHt(HibernateTemplate ht) {
this.ht = ht;
}
public List<StdBO> select(){
List<StdBO> list = ht.executeFind(new HibernateCallback() {
public Object doInHibernate(Session ses)
throws HibernateException, SQLException {
Criteria criteria=ses.createCriteria(StdBO.class);
System.out.println("before printing sutdents");
List<StdBO> bos = criteria.list();
System.out.println("students are"+bos);//here getting empty list
return bos;
}
});
return list;
}
xml
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="annotatedClasses">
<list>
<value>com.nt.dao.StdDAO</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
</bean>
<bean id="template" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="dao" class="com.nt.dao.StdDAO">
<property name="ht" ref="template" />
</bean>
You need begin (and commit) a transaction to query data. You can do it manually by session.beginTransaction() or using #Transactional annotation. For using #Transactional annotation you will need to do some additional spring configuration:
Hibernate Transaction Annotation Configuration.

Spring Data JPA + Hibernate : Inject Catalog/Schema at runtime in to JPA Entities

We have a scenario where in the catalog/schema combination is different for the entity classes inside certain package from the default one used by all others. I am trying to set Catalog and Schema on #Table annotation using PersistenceUnitPostProcessors callback at runtime using javaassist as below.
The issue: The added member values on javaassist annotation are NOT getting reflected on to the actual class associated with it. Please help me in finding the wrong lines of code; OR if there are other ways to achieve this, more than happy to know.
Note: I do not want to create a separate EntityManagerFactory for each catalog/schema combination - it is not really required in our case as the datasource is same.
related content in spring context :
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
<bean name="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="mainUnit" />
<property name="packagesToScan" value="com.mycompany.lob.domain" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceUnitPostProcessors">
<list>
<bean class="com.mycompany.lob.jpa.CustomPersistenceUnitPostProcessor"/>
</list>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SqlmxDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">100</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.default_schema">DEFAULT_SCHEMA</prop>
<prop key="hibernate.default_catalog">DEFAULT_CATALOG</prop>
</props>
</property>
</bean>
PersistenceUnitPostProcessors callback :
public class CustomPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
#Value("${user.schema}")
private String userSchema;
#Value("${user.catalog}")
private String userCatalog;
private static final Logger LOGGER = LoggerFactory.getLogger(CustomPersistenceUnitPostProcessor.class);
#SuppressWarnings("unchecked")
#Override
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
LOGGER.info("MutablePersistenceUnitInfo : {} ",pui);
List<String> jpadomains = pui.getManagedClassNames();
for (Iterator<?> iterator = jpadomains.iterator(); iterator.hasNext();) {
String clazzName = (String) iterator.next();
if(clazzName.startsWith("com.mycompany.lob.domain.user")){
try {
//modify annotation attributes using JavaAssist
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get(clazzName);
ClassFile classFile = ctClass.getClassFile();
ConstPool constPool = classFile.getConstPool();
AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute)classFile.getAttribute(AnnotationsAttribute.visibleTag);
if(annotationsAttribute!=null){
//Get hold of #Table annotation
Annotation tableAnnotation = annotationsAttribute.getAnnotation("javax.persistence.Table");
if(tableAnnotation!=null){
tableAnnotation.addMemberValue("catalog", new StringMemberValue(userCatalog, constPool));
tableAnnotation.addMemberValue("schema", new StringMemberValue(userSchema, constPool));
annotationsAttribute.addAnnotation(tableAnnotation);
LOGGER.debug("Schema-Table : {} - {} ", ((StringMemberValue)tableAnnotation.getMemberValue("schema")).getValue(),
((StringMemberValue)tableAnnotation.getMemberValue("name")).getValue() );
//write the file back
ctClass.writeFile();
}
}
} catch (Exception e) {
LOGGER.error("Schema/Catalog could not be altered for {} ",clazzName);
}
}
}
}
}
Simple answer:
19. Multitenancy
Complex catalog mapping:
interface PhysicalNamingStrategy in Hibernate v5 is helpful.
public interface PhysicalNamingStrategy {
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment);
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment);
....
}
Check the Example 2. Example PhysicalNamingStrategy implementation in Hibernate 5 User Guide and how to config it

Spring: change EntityManager dynamically

for some reason the database (ugly!) that I should use contains all the tables twice; every table are duplicated into these modes: DB1_<table> and DB2_<table>.
The structures of these databases are the same!
The application that I am realizing uses Spring + Hibernate and should permit to the users to change the database on runtime; this mean that a user can start the application using database DB1 and after some minutes change to DB2, return to DB1 and so on.
I have tried to extend DefaultNamingStrategy for every databases:
// I have create also DB2
public class DB1 extends DefaultNamingStrategy {
private static final long serialVersionUID = 676544180324515651L;
#Override
public String tableName(String tableName) {
return "DB1_" + tableName;
}
}
and set the naming strategy through the property hibernate.ejb.naming_strategy of jpa dinamically but for a reason that I can't understand I can change the naming strategy only once, and all next callings trown an Exception.
Someone know why?
Configuration of entityManagerFactory:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="it.perfectquiz.entity" />
<property name="persistenceProviderClass" value="org.hibernate.jpa.HibernatePersistenceProvider" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
How I try to change naming strategy:
XmlWebApplicationContext context = (XmlWebApplicationContext) ContextLoader.getCurrentWebApplicationContext();
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
GenericBeanDefinition entityManager = (GenericBeanDefinition) beanFactory.getBeanDefinition("entityManagerFactory");
ManagedProperties jpaProperties = (ManagedProperties) entityManager.getPropertyValues().get("jpaProperties");
TypedStringValue namingStrategy = (TypedStringValue) jpaProperties.get(new TypedStringValue("hibernate.ejb.naming_strategy"));
// only for test!
String newNaming;
if (namingStrategy.getValue().equals(DB1.class.getCanonicalName()))
newNaming = DB2.class.getCanonicalName();
else
newNaming = DB1.class.getCanonicalName();
// only for test!
namingStrategy.setValue(newNaming);
beanFactory.registerBeanDefinition("entityManagerFactory", entityManager);
Thanks,
Regards

org.hibernate.AnnotationException: No identifier specified for entity - even when it was

I have the following configuration:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="jpaDataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.example.domain</value>
<value>com.example.repositories</value>
</list>
</property>
</bean>
I have my Geoname class in com.example.domain:
#Entity
#Table(name="geonames")
public class Geoname implements Serializable {
#Id
#Column(name="geonameid")
private Long geonameid = null;
}
yet, when running, I get the following exception:
Caused by: org.hibernate.AnnotationException: No identifier specified
for entity: com.example.domain.Geoname at
org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:277)
at
org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:224)
at
org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:664)
at
org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3449)
at
org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3403)
at
org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1330)
at
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1730)
Any ideas why?
side note: I am combining both mongodb and hibernate/ mysql on this project.
I had the following
import org.springframework.data.annotation.Id;
Naturally, it should be:
import javax.persistence.Id;
Thanks to #JB Nizet
I faced the same error.I solved it and figured out i didn't put #Id annotations in id field in my Entity class.
#Entity
#Table(name="geonames")
public class Geoname implements Serializable {
#Column(name="geonameid")
private Long geonameid = null;
}
try this
#Column(name="geonameid",unique=true,nullable=false)

Resources