Hibernate Envers - org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update - hibernate-envers

I am using Hibernate Envar for Audit purpose.
Here is my code and configuration
hibernate.cfg.xml file configuration
<!-- Audit -->
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-insert"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-update"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-delete"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-update"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-remove"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-collection-recreate"/>
One Sample Entity Annoted with #Audited
#Entity
#Table(name = "Users")
#Audited
public class User extends GenericDomain implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(length=100)
private String name;
#Column(length=60)
private String username;
#Column(length=130)
private String password;
// Getter and setter with more fields
}
I have created a RevistionEntity to log audit for logged in user, for whom we are logging audit as
#Entity
#Table(name = "REVISIONS")
#RevisionEntity(CustomRevisionListener.class)
public class CustomRevisionEntity {
#Id
#GeneratedValue
#RevisionNumber
private int id;
#RevisionTimestamp
private long audit_timestamp;
private String username;
private Long userid;
// Getter and Setter
}
Here is my listener class
public class CustomRevisionListener implements RevisionListener {
public void newRevision(Object revisionEntity) {
CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity;
revision.setUsername("username"); //for testing
}
}
For Insert/Delete it works fine.
But for Update query it is giving following exception as
[ERROR] [http-8080-1 06:05:26] (JDBCExceptionReporter.java:logExceptions:101) Duplicate entry '1085-3' for key 1
[ERROR] [http-8080-1 06:05:26] (AbstractFlushingEventListener.java:performExecutions:324) Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:179)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
at org.hibernate.envers.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:157)
at org.hibernate.envers.synchronization.AuditProcess.beforeCompletion(AuditProcess.java:164)
at org.hibernate.transaction.JDBCTransaction.notifyLocalSynchsBeforeTransactionCompletion(JDBCTransaction.java:274)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:140)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy106.deleteSaleRecord(Unknown Source)
at org.commission.controller.salerecord.SaleRecordController.delete(SaleRecordController.java:753)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.commission.util.SessionFilter.doFilter(SessionFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.BatchUpdateException: Duplicate entry '1085-3' for key 1
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2018)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 46 more
Here is my generic update code for all entities
public E update(E entity) {
getSession().update(entity);
return entity;
}

Unfortunately without the full stacktrace and the SQL definition of the tables, its hard to say whats happening here. These are the things I would check:
Constraints/PK on the audit tables? - is it possible your primary key is missing the revision number AND revision type - I had this occur because an update and a delete happened in the same session for a particular entity (I think it had something to do with a Cascade operation, but I cannot recall now), and I was expecting the revision number + PK of the entity table to be enough to uniquely identify each row in the audit tables.
Remember that by default deleted entities only contain the revision number, revision type, and the ID/PK of the original entity. If you have a NOT NULL constraint on the audit table, that could cause the failure. You can work around that by setting the org.hibernate.envers.store_data_at_delete property to true.

Related

Issue with projection when using #Lob and #Query

Entity:
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer price;
#Lob
private String description;
}
Interface for Projection:
public interface NameAndDesc {
String getAlias();
String getDesc();
}
Repository:
public interface ItemRepository extends JpaRepository<Item, Long> {
#Query(value = "SELECT NAME AS ALIAS, DESCRIPTION AS DESC FROM ITEM WHERE ID IS :#{#id}",nativeQuery = true)
NameAndDesc findNameAndDesc(#Param("id") Long id);
}
When I try to call .getDesc() on the query above, I get this exception:
java.lang.IllegalArgumentException: Projection type must be an interface!
at org.springframework.util.Assert.isTrue(Assert.java:118)
at org.springframework.data.projection.ProxyProjectionFactory.createProjection(ProxyProjectionFactory.java:100)
at org.springframework.data.projection.SpelAwareProxyProjectionFactory.createProjection(SpelAwareProxyProjectionFactory.java:45)
at org.springframework.data.projection.ProjectingMethodInterceptor.getProjection(ProjectingMethodInterceptor.java:131)
at org.springframework.data.projection.ProjectingMethodInterceptor.invoke(ProjectingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.ProxyProjectionFactory$TargetAwareMethodInterceptor.invoke(ProxyProjectionFactory.java:245)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy105.getDesc(Unknown Source)
at com.example.demo.DemoApplicationTests.contextLoads(DemoApplicationTests.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
When I remove the "#Lob" annotation from "description" the projection is working without any problem.
It seems that the problem is the CLOB what returns from the DB. When I change the projection interface method to clob "java.sql.Clob getDesc();" it seems to start working again, but not the best solution.
Is it right behaviour when using projections, like this?
I found a somewhat similar issue when it was a bug in ProxyProjectionFactory:
Issue with projection in SpringDataRest and #Lob attribute
The idea behind a projection is to limit the columns returned and (ideally requested) from the database.
There isn't much conversion support build in because this is normally handled by JPA but this doesn't happen because you are using a native query.
I therefore see two options how to solve the issue:
Convert the LOB into a VARCHAR2 or similar in the database.
How this is done depends on your database.
This answer seems to work for SQL Server.
I'm sure you'll find an alternative for whatever database you are using.
Get JPA back in the game by using a JPQL query.
That should be database independent but I assume you had a reason for using a native query, to begin with.
One way around this is to use the Spring Content community project. This project allows you to associate content with Spring Data entities. The content is managed separately leaving only "managed" content-related metadata on the Entity. This won't mess your projections. Think Spring Data but for Content (or Unstructured data).
This is pretty easy to add to your existing projects. I am not sure if you are using Spring Boot, or not. I'll give a non-spring boot example:
pom.xml
<!-- Java API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-jpa</artifactId>
<version>0.5.0</version>
</dependency>
<!-- REST API (if desired)-->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest</artifactId>
<version>0.5.0</version>
</dependency>
Configuration
#Configuration
#EnableJpaStores
#Import("org.springframework.content.rest.config.RestConfiguration.class")
public class ContentConfig {
// schema management
//
#Value("/org/springframework/content/jpa/schema-drop-mysql.sql")
private Resource dropContentTables;
#Value("/org/springframework/content/jpa/schema-mysql.sql")
private Resource createContentTables;
#Bean
DataSourceInitializer datasourceInitializer() {
ResourceDatabasePopulator databasePopulator =
new ResourceDatabasePopulator();
databasePopulator.addScript(dropContentTables);
databasePopulator.addScript(createContentTables);
databasePopulator.setIgnoreFailedDrops(true);
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource());
initializer.setDatabasePopulator(databasePopulator);
return initializer;
}
}
To associate content, add Spring Content annotations to your account entity.
Item.java
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer price;
// replace #Lob field with
#ContentId
private String contentId;
#ContentLength
private long contentLength = 0L;
// if you have rest endpoints
#MimeType
private String mimeType = "text/plain";
}
Create a "store":
ItemContentStore.java
#StoreRestResource(path="itemsContent)
public interface ItemContentStore extends ContentStore<Item, String> {
}
This is all you need to create REST endpoints # /itemsContent. When your application starts, Spring Content will look at your dependencies (seeing Spring Content JPA/REST), look at your ItemContentStore interface and inject an implementation of that interface for JPA. It will also inject a #Controller that forwards http requests to that implementation. This saves you having to implement any of this yourself whch I think is what you are after.
So...
For to access content through a Java API, auto-wire ItemContentStore and use its methods.
Or to access content through a REST API:
curl -X POST /itemsContent/{itemId}
with a multipart/form-data request will store the image in the database and associate it with the account entity whose id is itemId.
curl /itemsContent/{itemId}
will fetch it again and so on...supports full CRUD.
There are a couple of getting started guides here. The reference guide is here. And there is a tutorial video here. The coding bit starts about 1/2 way through.
HTH

spring boot + hibernate table names queried in lower case

I'm new to Spring boot and hibernate.
Below is my application prop file and the naming strategy implementation file.
When I try to push data to DB the below exception occurs ERROR: relation "nickname" does not exist.
I want access table name and column name always in uppercase.
Please help me to understand what went wrong.
NickName.java
#Entity
#Table(name="NICKNAME")
public class NickName {
application.properties
spring.datasource.url=jdbc:postgresql://192.168.239.129:5432/maindb
spring.datasource.username=pgdbuser
spring.datasource.password=pgdbuser
spring.jpa.generate-ddl=false
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=DEBUG
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL82Dialect
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
PhysicalNamingStrategyImpl.java
import java.io.Serializable;
import org.apache.commons.lang.StringUtils;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable{
public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();
#Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
String nameModified = StringUtils.upperCase(name.getText());
// Do whatever you want with the name modification
return new Identifier(nameModified, name.isQuoted());
}
#Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
String nameModified = StringUtils.upperCase(name.getText());
// Do whatever you want with the name modification
return new Identifier(nameModified, name.isQuoted());
}
}
Exception:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:242) ~[spring-orm-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225) ~[spring-orm-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527) ~[spring-orm-5.0.5.RELEASE.jar:5.0.5.RELEASE]
......
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
.......
Caused by: org.postgresql.util.PSQLException: ERROR: relation "nickname" does not exist
Position: 460
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433) ~[postgresql-42.2.2.jar:42.2.2]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178) ~[postgresql-42.2.2.jar:42.2.2]
Update 1: changed app.prop file as below
spring.datasource.url=jdbc:postgresql://192.168.239.129:5432/maindb
spring.datasource.username=pgdbuser
spring.datasource.password=pgdbuser
spring.jpa.generate-ddl=false
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=DEBUG
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL95Dialect
spring.jpa.hibernate.naming.physical-strategy=com.theroot.rester.PhysicalNamingStrategyImpl
Note :
In my sql client just now checked
select * from "NICKNAME"; --Works
select * from NICKNAME; --doesn't Work
This should work :
1) Get rid of PhysicalNamingStrategyImpl.java
2) Make changes in application.properties as below :
spring.jpa.properties.hibernate.dialect =
org.hibernate.dialect.PostgreSQL95Dialect spring.jpa.hibernate.naming.implicit-
strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=
org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
3) In #Table add schema as well. ie., #Table(name="table", schema="schemaname")
This worked for me with Postgresql 10 with Hibernate 5.x and Spring Boot 2.1.x. If you are using an older version of Postgresql, then use appropriate PostgreSqlxxDialect from Spring.

JPA could not locate parameter while working with Stored procedure using Postgres

Any efforts in following problem would be highly appreciable.
I am trying to invoke stored procedure using #NamedStoredProcedureQueries
Here is the code snippet of my entity class
#Entity
#Table(name = "tx_oppertunity")
#NamedStoredProcedureQueries({ //
#NamedStoredProcedureQuery(name = "oppertunity.pastOppertunities", procedureName = "pastOppertunities",resultSetMappings="myMapping")})
#SqlResultSetMappings({
#SqlResultSetMapping(
name = "myMapping",
classes = #ConstructorResult(targetClass = DataHolder.class, columns = { #ColumnResult(name = "oppertunityid") }))
})
public class Oppertunity {
/** The oppertunity id. */
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "GEN_TX_OPPERTUNITY_SEQ")
#SequenceGenerator(allocationSize = 1, name = "GEN_TX_OPPERTUNITY_SEQ", sequenceName = "tx_oppertunity_seq")
#Column(name = "oppertunity_id", nullable = false, unique = true)
private Long oppertunity_id;
// other fields to follow
}
My stored procedure is written in postgres and looks like this.
CREATE OR REPLACE FUNCTION pastOppertunities()
RETURNS TABLE(oppertunityid integer) AS
$BODY$
BEGIN
RETURN QUERY select cast((opp.oppertunity_id) as integer) from tx_oppertunity opp where (opp.end_date)< (NOW() - INTERVAL '2 days');
END;
$BODY$
LANGUAGE plpgsql
Since I am using SQL Resultset mapping to map my result from stored procedure I have defined target class to hold those values as DataHolder.class which looks like this.
public class DataHolder implements Serializable{
private Integer oppertunityid;
/**
* #return the oppertunityid
*/
public Integer getOppertunityid() {
return oppertunityid;
}
/**
* #param oppertunityid the oppertunityid to set
*/
public void setOppertunityid(Integer oppertunityid) {
this.oppertunityid = oppertunityid;
}
public DataHolder(Integer oppertunityid) {
this.oppertunityid = oppertunityid;
}
}
However If I try to run the procedure using, JPA repository
#Procedure(name = "oppertunity.pastOppertunities")
public List<DataHolder> findPastOppertunities();
It gives me following exception,
11:51:07.200 [http-nio-8000-exec-7] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Could not locate parameter registered using that position [1]; nested exception is java.lang.IllegalArgumentException: Could not locate parameter registered using that position [1]] with root cause
org.hibernate.procedure.NoSuchParameterException: Could not locate parameter registered using that position [1]
at org.hibernate.procedure.internal.ProcedureCallImpl.getParameterRegistration(ProcedureCallImpl.java:338) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
at org.hibernate.procedure.internal.ProcedureOutputsImpl.getOutputParameterValue(ProcedureOutputsImpl.java:68) ~[hibernate-core-4.3.10.Final.jar:4.3.10.Final]
at org.hibernate.jpa.internal.StoredProcedureQueryImpl.getOutputParameterValue(StoredProcedureQueryImpl.java:276) ~[hibernate-entitymanager-4.3.10.Final.jar:4.3.10.Final]
at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.extractOutputValue(StoredProcedureJpaQuery.java:120) ~[spring-data-jpa-1.7.3.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.JpaQueryExecution$ProcedureExecution.doExecute(JpaQueryExecution.java:298) ~[spring-data-jpa-1.7.3.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:74) ~[spring-data-jpa-1.7.3.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:99) ~[spring-data-jpa-1.7.3.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:90) ~[spring-data-jpa-1.7.3.RELEASE.jar:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:415) ~[spring-data-commons-1.9.3.RELEASE.jar:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:393) ~[spring-data-commons-1.9.3.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$DefaultMethodInvokingMethodInterceptor.invoke(RepositoryFactorySupport.java:506) ~[spring-data-commons-1.9.3.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) ~[spring-tx-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122) ~[spring-data-jpa-1.7.3.RELEASE.jar:na]
I am not sure what exactly I am missing here all parameters are specified correctly in #SQLREsultSetMapping and I added explicit typecast in procedure to compulsory return Integer value.
There was some post which was suggesting to use Entity manager to call stored procedure, after a long fight I made call using entity manager and it worked like a charm
public List<DataHolder> findPastOppertunities() {
// TODO Auto-generated method stub
StoredProcedureQuery spq = em.createStoredProcedureQuery("pastOppertunities");
List<DataHolder> resultList = spq.getResultList();
return resultList;
//return oppRepo.findPastOppertunities();
}
However I want to understand if its bug with JPA repositories, Why JPA is not able to map result from strored procedure using #SqlResultSetMapping.
Thanks,
Dipesh

JPA static metamodel classes in EclipseLink throw NullPointerException when accessing attributes

I have a problem with generated static metamodel classes in EclipseLink.
In my project I firstly generated static metamodel classed for my entities using:
1) org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor and IntelliJ IDEA
and this classes have been generated to: target/generated-sources
Then I try to use such Hibernate generated metamodel classes (ex. below) with EclipseLink (GlassFish embedded), but lines of code that contains references to metamodel attributes throws NullPointerException exception:
SingularAttribute<Employee, String> descriptionAttr = Employee_.description;
predicates.add(criteriaBuilder.like(employee.get(descriptionAttr), "%" + description + "%"));
Here emploee.get( >> null << ) throws exception.
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(Employee.class)
public abstract class Employee_ extends pl.salonea.entities.NaturalPerson_ {
public static volatile SetAttribute<Employee, Skill> skills;
public static volatile SetAttribute<Employee, ProviderService> suppliedServices;
public static volatile SetAttribute<Employee, EmployeeRating> receivedRatings;
public static volatile SingularAttribute<Employee, String> description;
public static volatile SetAttribute<Employee, Education> educations;
public static volatile SingularAttribute<Employee, String> jobPosition;
public static volatile SetAttribute<Employee, TermEmployeeWorkOn> termsOnWorkStation;
}
2) Next I thought that this metamodel classes maybe are implementation specific. So I generated them analogically with EclipseLink using
org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor and target/generated-sources-eclipselink (as on picture)
At the end I have something like this directory stracture with metamodel:
3) I am also using in build.gradle such configuration to as I think include this generated sources in project:
if(hasProperty('jboss')) {
sourceSets {
main {
java {
srcDir 'target/generated-sources/'
}
}
}
} else {
sourceSets {
main {
java {
srcDir 'target/generated-sources-eclipselink/'
}
}
}
}
This way I want to use Hibernate generated classes with Jboss and EclipseLink generated classes with EclipseLink.
4) Such configuration works only if running on WilfFly/Hibernate but not on GlassFish/EclipseLink here is this NullPointerException
5) In persistence.xml I have more over EclipseLink generation using such property for one Persistence Unit
<property name="eclipselink.canonicalmodel.subpackage" value="metamodel" />
and such property for second Persistence Unit (to avoid duplicate conflict)
<property name="eclipselink.canonicalmodel.subpackage" value="metamodel_local" />
But I'm trying not to use this generation. It is in subpackage and in my code I only import previously generated metamodel classes.
The reason is that I would like to have in the same namespace metamodel classes generated by Hibernate/Eclipse and use them appropriately.
However if Hibernate generated metamodel classes could be also work with EclipseLink there won't be problem to using only one generation.
6) Moreover I cant use metamodel classes generated by EclipseLink persistence.xml property as they are regenerated each time I run/build my project. And I need in my code to manually modify two metamodel classes as they are inherited from single abstract metamodel class. Here I am overriding in subclasses AbstractType with ConcreteType on SetAttribute of metamodel class.
7) At the end I paste error I'm getting while running integration test with such configuration of metamodel classes
Caused by: java.lang.NullPointerException
at org.eclipse.persistence.internal.jpa.querydef.FromImpl.get(FromImpl.java:263)
at pl.salonea.ejb.stateless.EmployeeFacade.findByMultipleCriteria(EmployeeFacade.java:295)
at pl.salonea.ejb.stateless.EmployeeFacade.findByMultipleCriteria(EmployeeFacade.java:269)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081)
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153)
at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4786)
at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:656)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:46)
at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:52)
at sun.reflect.GeneratedMethodAccessor113.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:140)
at sun.reflect.GeneratedMethodAccessor141.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:369)
at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:4758)
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4746)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
... 149 more
-I'm checking EclipseLink sources:
public <Y> Path<Y> get(SingularAttribute<? super X, Y> att){
if (att.getPersistentAttributeType().equals(
PersistentAttributeType.BASIC)) {
return new PathImpl<Y>(
this, this.metamodel, att.getBindableJavaType(),
this.currentNode.get(att.getName()), att);
} else {
Class<Y> clazz = att.getBindableJavaType();
Join join = new JoinImpl<X, Y>(
this, this.metamodel.managedType(clazz),
this.metamodel, clazz,
this.currentNode.get(att.getName()), att);
this.joins.add(join);
return join;
}
}
FromImpl.java:263 is condition of if statement so it looks like att.getPersistentAttributeType() returns null.
It would be good if you'll file a bug against EclipseLink on https://bugs.eclipse.org/bugs/enter_bug.cgi?product=EclipseLink
Component is JPA. Please copy-paste this description there and provide some test-case (sample application with this metamodel) to let us reproduce it and develop some fix.
The problem can be in the failed initialization Canonical Metamodel.
You can investigate yours eclipselink log for checking something like that:
Could not load the field named [...] on the class [...]
IllegalArgumentException: Can not set static ... field ... to ...
In my case after fixing initialization, NPE had gone.
I know this is an old ticket but i still wanted to let you guys know how we fixed the problem. Especially the last nullpointer exception.
The problem is that your entitimanager is not loaded when you are using your Criteriabuilder for the first time.
To solve this problem you can set following in you persistence.xml
<property name="eclipselink.deploy-on-startup" value="true" />

Entity bean 3.0 composite key issue

1: I have a table as shown below :
Name Null? Type
ATX_ID NOT NULL NUMBER(16)
ATX_GLM_CD NOT NULL NUMBER(5)
ATX_CRDR_FLG NOT NULL VARCHAR2(1)
ATX_AMT NOT NULL NUMBER(15,2)
ATX_STTS NOT NULL VARCHAR2(1)
ATX_TCM_ID NOT NULL NUMBER(16)
ATX_TXN_DT NOT NULL DATE
ATX_CRTE_BY NOT NULL VARCHAR2(30)
ATX_CRTE_DT NOT NULL DATE
The columns ATX_ID,ATX_GLM_CD and ATX_CRDR_FLG form a composite primary key.
2: I have created an entity bean class for the above table as follows :
#Entity
public class AcctngTxns implements Serializable {
private BigDecimal atxAmt;
private String atxStts;
private BigDecimal atxTcmId;
private Date atxTxnDt;
private String atxCrteBy;
private Date atxCrteDt;
#EmbeddedId
private AcctngTxnsPK acctngTxnsPK;
public AcctngTxns() {
//super();
}
/*getters and setters*/
}
#Embeddable
public class AcctngTxnsPK implements Serializable {
private long atxId;
private long atxGlmCd;
private String atxCrdrFlg;
private static final long serialVersionUID = 1L;
public AcctngTxnsPK() {
//super();
}
/*necessary overrides*/
}
3: /orm.xml/
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
4: /persistence.xml/
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
DataSource
com.nseit.ncfm2.data.ejb.entity.AcctngTxns
5: While accessing the entity bean via a session bean,I am getting the following exception :
<[weblogic.servlet.internal.WebAppServletContext#1a1bc8f - appName: '_auto_generated_ear_', name: 'AWebApp', context-path: '/AWebApp', spec-version: '2.5'] Servlet failed with Exception
javax.ejb.EJBException: EJB Exception: ; nested exception is:
org.apache.openjpa.persistence.ArgumentException: Fields "com.nseit.ncfm2.data.ejb.entity.AcctngTxns.acctngTxnsPK" are not a default persistent type, and do not have any annotations indicating their persistence strategy. If you do not want these fields to be persisted, annotate them with #Transient.
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.unwrapRemoteException(RemoteBusinessIntfProxy.java:105)
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:87)
at $Proxy127.gottaAccessEntity3(Unknown Source)
at jsp_servlet.__result.jspService(_result.java:115)
at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
Truncated. see log file for complete stacktrace
org.apache.openjpa.persistence.ArgumentException: Fields "com.nseit.ncfm2.data.ejb.entity.AcctngTxns.acctngTxnsPK" are not a default persistent type, and do not have any annotations indicating their persistence strategy. If you do not want these fields to be persisted, annotate them with #Transient.
at org.apache.openjpa.persistence.PersistenceMetaDataFactory.validateStrategies(PersistenceMetaDataFactory.java:399)
at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:205)
at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:474)
at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:294)
at org.apache.openjpa.kernel.BrokerImpl.newObjectId(BrokerImpl.java:1114)
Truncated. see log file for complete stacktrace
7: Certainly,I do not want the primary key fields to be updated.
8: I tried to figure out the implementation of the below points mentioned in JPA documentation :
A composite primary key must be represented and mapped to multiple fields or properties of the entity class, or must be represented and mapped as an embeddable class.
If the class is mapped to multiple fields or properties of the entity class, the names and types of the primary key fields or properties in the primary key class must match those of the entity class.
8: Please help me in resolving the issue.
Thanks !
I found a solution by trial-and-error method. It seems that with JPA 1.0,it is necessary to mention the embedded-id in orm.xml file as follows :
Thanks.