Calling stored function in hibernate - spring

I have tried multiple ways to call stored function in hibernate---
1) Via Session.doWork callback method
session.doWork(new Work() {
#Override
public void execute(Connection conn)
throws SQLException {
CallableStatement stmt = conn.prepareCall("{? = call test(?)}");
stmt.registerOutParameter(1, Types.INTEGER);
stmt.setString(2, "callIndex");
stmt.execute();
eventVal = stmt.getInt(1);
}
});
This works fine but cannot return any thing from here, so doesn't solve my purpose.
2) Via Native query
StringBuilder query = new StringBuilder();
query.append("Select test() from dual");
SQLQuery sqlQuery = session.createSQLQuery(query.toString());
List resultList = sqlQuery.list();
events = new ArrayList<Events>();
Object result = null;
if (events != null && !events.isEmpty()) {
for (int i = 0; i < events.size(); i++) {
result = resultList.get(i);
}
}
This doesn't work and gives me some No Dialect mapping for JDBC type -10, not sure of the reason.
3) Via named query
My entity class is ---
#NamedNativeQueries({
#NamedNativeQuery(name = "testCall",
query = "? = call test()",
hints = {#QueryHint(name = "org.hibernate.callable", value = "true" )},
resultClass = Events.class
)
})
#Entity
#Table(name = "EVENTS")
public class Events implements Serializable {
private static final long serialVersionUID = -24850323296832289L;
/** The id. */
#Id
#Column(name = "EVENT_SID")
private Integer eventId;
/** The processed status. */
#Column(name = "EVENT_STATUS")
private String eventStatus;
/** The event type. */
#Column(name = "EVENT_TYPE_NAME")
private String eventType;
/** The live event. */
#Column(name = "IS_LIVE_EVENT")
private Integer liveEvent;
/** The event message. */
#Lob
#Column(name = "EVENT_MESSAGE")
private String eventMessage;
public Integer getEventId() {
return eventId;
}
public void setEventId(Integer eventId) {
this.eventId = eventId;
}
public String getEventStatus() {
return eventStatus;
}
public void setEventStatus(String eventStatus) {
this.eventStatus = eventStatus;
}
/**
* Gets the event type.
*
* #return the event type
*/
public String getEventType() {
return eventType;
}
/**
* Sets the event type.
*
* #param eventType
* the new event type
*/
public void setEventType(String eventType) {
this.eventType = eventType;
}
/**
* Gets the live event.
*
* #return the live event
*/
public Integer getLiveEvent() {
return liveEvent;
}
/**
* Sets the live event.
*
* #param liveEvent
* the new live event
*/
public void setLiveEvent(Integer liveEvent) {
this.liveEvent = liveEvent;
}
/**
* Gets the event message.
*
* #return the event message
*/
public String getEventMessage() {
return eventMessage;
}
/**
* Sets the event message.
*
* #param eventMessage
* the new event message
*/
public void setEventMessage(String eventMessage) {
this.eventMessage = eventMessage;
}
}
The DAO through which I am making call have method ---
public Integer callSqlBlock(){
int event = 0;
Session session = getHibernateTemplate().getSessionFactory().getCurrentSession();
List<Events> events = null;
events = session.getNamedQuery("testCall").list();
return events.get(0).getEventId();
}
stored function on the DB end ---
create or replace
function test return SYS_REFCURSOR
as
p_order_recordset SYS_REFCURSOR;
begin
open p_order_recordset FOR SELECT EVENT_SID,EVENT_STATUS,EVENT_TYPE_NAME,IS_LIVE_EVENT FROM events;
return p_order_recordset;
end ;
execution of stored function via named query is giving me invalid column index
Please let me know where I am going wrong on this, and if possible please provide some example also

Related

How to avoid casting to a JAXBElement while making a SOAP webservice call?

I am having a spring boot java application. I am calling a soap web service using spring webservice template . the webservice call always return a JAXBElement. the following is my code snippet.
JAXBElement<ItemResponse> itemResponse = (JAXBElement<ItemResponse> ) getWebServiceTemplate().marshalSendAndReceive(
this.cconfServiceConfiguration.getServices().getLocation(), itemRequest,
new SoapActionCallback(this.cconfServiceConfiguration.getServices().getGetItemAction()));
return itemResponse.getValue();
The marshalSendAndReceive returns a JAXBElement. Is there any way i can rewrite the code so that it will return an Object of ItemResponse so that i can avoid casting.
The following is the ItemResponse class declaration.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ItemResponse", propOrder = {
"result",
"item"
})
public class ItemResponse {
#XmlElement(required = true)
protected Result result;
protected Item item;
/**
* Gets the value of the result property.
*
* #return
* possible object is
* {#link Result }
*
*/
public Result getResult() {
return result;
}
/**
* Sets the value of the result property.
*
* #param value
* allowed object is
* {#link Result }
*
*/
public void setResult(Result value) {
this.result = value;
}
/**
* Gets the value of the item property.
*
* #return
* possible object is
* {#link Item }
*
*/
public Item getItem() {
return item;
}
/**
* Sets the value of the item property.
*
* #param value
* allowed object is
* {#link Item }
*
*/
public void setItem(Item value) {
this.item = value;
}
}
really appreciate if you can throw some information

What are the best practice for audit log(user activity) in micro-services?

In our microservice architecture, we are logging user-activity to mongo database table? Is there any good way to store and retrieve audit log?
You can think of a solution something similar to the below by storing AuditLogging into the Mongo db by using DAO pattern.
#Entity
#Table(name = "AuditLogging")
public class AuditLogging implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "auditid", updatable = false, nullable = false)
private Long auditId;
#Column(name = "event_type", length = 100)
#Enumerated(EnumType.STRING)
private AuditingEvent event;
#Column(name = "event_creator", length = 100)
#Enumerated(EnumType.STRING)
private EventCreator eventCreator;
#Column(name = "adminid", length = 20)
private String adminId;
#Column(name = "userid", length = 20)
private String userId;
#Column(name = "event_date")
private Date eventDate;
}
public class Constants {
public static final String EVENT_TYPE = "eventType";
public static final String EVENT_CREATOR = "eventCreator";
public static final String NEW_EMAIL_ID = "newEmailId";
public static final String OLD_EMAIL_ID = "oldEmailId";
}
public enum AuditEvent {
USER_REGISTRATION,
USER_LOGIN,
USER_LOGIN_FAIL,
USER_ACCOUNT_LOCK,
USER_LOGOFF,
USER_PASSWORD_CHANGE,
USER_PASSWORD_CHANGE_FAIL,
USER_FORGOT_PASSWORD,
USER_FORGOT_PASSWORD_FAIL,
ADMIN_LOGIN
}
public enum EventCreator {
ADMIN_FOR_SELF,
USER_FOR_SELF,
ADMIN_FOR_USER
}
public interface AuditingDao {
/**
* Stores the event into the DB/Mongo or Whatever
*
* #param auditLogging
* #return Boolean status
*/
Boolean createAuditLog(final AuditLogging auditLogging);
/* Returns the log occurrence of a specific event
*
* #param event
* #return List of logged events by type
*/
List<AuditLogging> getLogsForEvent(final AuditingEvent event);
}
public interface AuditingService {
/**
* Creates an Audit entry in the AuditLogging table using the
* DAO layer
*
* #param auditingEvent
* #param eventCreator
* #param userId
* #param adminId *
* #return {#link Boolean.TRUE} for success and {#link Boolean.FALSE} for
* failure
*/
Boolean createUserAuditEvent(final AuditEvent auditEvent,
final EventCreator eventCreator, final String userId, final String adminId,
final String newEmailId,final String oldEmailId);
/**
*
* Returns all event for a user/admin based on the id
*
* #param id
* #return List of logged events for an id
*/
List<AuditLogging> fetchLoggedEventsById(final String id);
/***
* Returns all event based on event type
*
* #param eventName
* #return List of logged events for an event
*/
List<AuditLogging> fetchLoggedEventsByEventName(final String eventName);
}
#Service("auditingService")
public class AuditServiceImpl implements AuditingService {
#Autowired
private AuditingDao auditingDao;
private static Logger log = LogManager.getLogger();
#Override
public Boolean createUserAuditingEvent(AuditEvent auditEvent,
EventCreator eventCreator, String userId, String adminId,
String newEmailId,String oldEmailId) {
AuditLogging auditLogging = new AuditLogging();
auditLogging.setEvent(auditingEvent);
auditLogging.setEventCreator(eventCreator);
auditLogging.setUserId(userId);
auditLogging.setAdminId(adminId);
auditLogging.setEventDate(new Date());
return Boolean.TRUE;
}
#Override
public List<AuditLogging> fetchLoggedEventsByEventName(
final String eventName) {
AuditEvent event = null;
try {
event = AuditingEvent.valueOf(eventName);
} catch (Exception e) {
log.error(e);
return Collections.emptyList();
}
return auditingDao.getLogsForEvent(event);
}
public void setAuditingDao(AuditingDao auditingDao) {
this.auditingDao = auditingDao;
}
}
Writing an aspect is always good for this type of scenarios by pointing to the appropriate controller method to trigger the event.
#Aspect
#Component("auditingAspect")
public class AuditingAspect {
#Autowired
AuditingService auditingService;
/* The below controllers you can think of your microservice endpoints
*/
#Pointcut("execution(* com.controller.RegistrationController.authenticateUser(..)) ||execution(* com.controller.RegistrationController.changeUserPassword(..)) || execution(* com.controller.RegistrationController.resetPassword(..)) ||execution(* com.controller.UpdateFunctionalityController.updateCustomerDetails(..))")
public void aroundPointCut() {}
#Around("aroundPointCut()")
public Object afterMethodInControllerClass(ProceedingJoinPoint joinPoint)
throws Throwable {
joinPoint.getSignature().getName();
joinPoint.getArgs();
// auditingService
Object result = joinPoint.proceed();
ResponseEntity entity = (ResponseEntity) result;
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
if(!((request.getAttribute(Constants.EVENT_TYPE).toString()).equalsIgnoreCase(AuditEvent.USER_LOGIN.toString()) || (((request.getAttribute(Constants.EVENT_TYPE).toString()).equalsIgnoreCase(AuditEvent.ADMIN_LOGIN.toString()))))){
auditingService.createUserAuditEvent(
(AuditingEvent) request.getAttribute(Constants.EVENT_TYPE),
(EventCreator) request.getAttribute(Constants.EVENT_CREATOR),
(request.getAttribute(Constants.USER_ID)!= null ? request.getAttribute(Constants.USER_ID).toString():""), null,
(request.getAttribute(Constants.NEW_EMAIL_ID) == null ? ""
: request.getAttribute(Constants.NEW_EMAIL_ID).toString()),
(request.getAttribute(Constants.OLD_EMAIL_ID) == null ? ""
: request.getAttribute(Constants.OLD_EMAIL_ID).toString()));
}
return entity;
}
}
From the REST controller the Aspect will be triggered when it finds the corresponding event.
#RestController
public class RegistrationController {
#RequestMapping(path = "/authenticateUser", method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
/* This method call triggers the aspect */
#ResponseBody
public ResponseEntity<String> authenticateUser(HttpServletRequest request, #RequestBody User user)
throws Exception {
request.setAttribute(Constants.EVENT_TYPE, AuditingEvent.USER_LOGIN);
request.setAttribute(Constants.EVENT_CREATOR, EventCreator.USER_FOR_SELF);
request.setAttribute(Constants.USER_ID, user.getUserId());
ResponseEntity<String> responseEntity = null;
try {
// Logic for authentication goes here
responseEntity = new ResponseEntity<>(respData, HttpStatus.OK);
} catch (Exception e) {
request.setAttribute(Constants.EVENT_TYPE, AuditEvent.USER_LOGIN_FAIL);
responseEntity = new ResponseEntity<>(respData, HttpStatus.INTERNAL_SERVER_ERROR);
}
return responseEntity;
}
}
I hope this answer make sense and you can implement similar functionality for Mongo as well.
Cheers !

gson.toJson() throws StackOverflowError and I dont have a circular dependency

I am trying to generate a JSON
Gson gson = new Gson();
String json = gson.toJson(item);
But every time i try to I keep getting a stackoverflow error:
java.lang.StackOverflowError: null
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:968)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:968)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:112)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:239)
It is caused when i try to convert DataTableResults class which contains a list of Transactions.class as its property field to a string.
The DataTableResult class looks like this :
public class DataTableResults<T> {
/** The draw. */
private String draw;
/** The records filtered. */
private String recordsFiltered;
/** The records total. */
private String recordsTotal;
/** The list of data objects. */
#SerializedName("data")
List<T> listOfDataObjects;
/**
* Gets the draw.
*
* #return the draw
*/
public String getDraw() {
return draw;
}
/**
* Sets the draw.
*
* #param draw the draw to set
*/
public void setDraw(String draw) {
this.draw = draw;
}
/**
* Gets the records filtered.
*
* #return the recordsFiltered
*/
public String getRecordsFiltered() {
return recordsFiltered;
}
/**
* Sets the records filtered.
*
* #param recordsFiltered the recordsFiltered to set
*/
public void setRecordsFiltered(String recordsFiltered) {
this.recordsFiltered = recordsFiltered;
}
/**
* Gets the records total.
*
* #return the recordsTotal
*/
public String getRecordsTotal() {
return recordsTotal;
}
/**
* Sets the records total.
*
* #param recordsTotal the recordsTotal to set
*/
public void setRecordsTotal(String recordsTotal) {
this.recordsTotal = recordsTotal;
}
/**
* Gets the list of data objects.
*
* #return the listOfDataObjects
*/
public List<T> getListOfDataObjects() {
return listOfDataObjects;
}
/**
* Sets the list of data objects.
*
* #param listOfDataObjects the listOfDataObjects to set
*/
public void setListOfDataObjects(List<T> listOfDataObjects) {
this.listOfDataObjects = listOfDataObjects;
}
}
while the Transactions.class looks like this
#Entity
#Table(name = "TRANS")
public class Transactions extends DefaultEntity {
public enum TRANSACTIONTYPE{WITHDRAW, DEPOSIT, WIN, LOSS}
#ManyToOne(targetEntity = User.class)
#JoinColumn(name="player")
private User player;
private double amount;
#Enumerated(EnumType.STRING)
private TRANSACTIONTYPE transactiontype;
private String referenceID;
private String detail;
private String token;
public TRANSACTIONTYPE getTransactiontype() {
return transactiontype;
}
public Transactions setTransactiontype(TRANSACTIONTYPE transactiontype) {
this.transactiontype = transactiontype;
return this;
}
public double getAmount() {
return amount;
}
public Transactions setAmount(double amount) {
this.amount = amount;
return this;
}
public String getReferenceID() {
return referenceID;
}
public Transactions setReferenceID(String referenceID) {
this.referenceID = referenceID;
return this;
}
public String getDetail() {
return detail;
}
public Transactions setDetail(String detail) {
this.detail = detail;
return this;
}
public String getToken() {
return token;
}
public Transactions setToken(String token) {
this.token = token;
return this;
}
public User getPlayer() {
return player;
}
public Transactions setPlayer(User player) {
this.player = player;
return this;
}
}
according to this post, it is supposed to be caused by a circular dependency, but in my case it is not cause i dont have one. What else could cause such error ?
You should remove extends DefaultEntity, you don't need it and may bring circular dependency.
Also you have a #ManyToOne relationship with User, that may cause circular dependency if User also have a reference to Transactions.
If you have it in both parts, you should exclude it from serialization with transient on one part at least.

Synchronous Message send and receive using JMS template and Spring Boot

I am after sending/receiving call to JMS queue synchronously using JMS Template and Spring boot. I went through official spring doc for JMS template but of no help.
I am not too sure about calling receive() method specifically or it will automatically receive message once send() is invoked. Since this is synchronous call I only need to receive message that I've sent (with the correlation Id).
Any help in this regard would be appreciated. Please let me know if you need any further info.
Update!!
Below is my spring boot code.
JMSSConfig.java
#Configuration
#EnableJms
public class JMSConfig {
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
return factory;
}
#Bean
public MarshallingMessageConverter createMarshallingMessageConverter(final Jaxb2Marshaller jaxb2Marshaller) {
System.out.println("executing createMarshallingMessageConverter");
return new MarshallingMessageConverter(jaxb2Marshaller);
}
#Bean
public Jaxb2Marshaller createJaxb2Marshaller(#Value("${context.path}") final String contextPath, #Value("${schema.location}") final String schemaLocaation) {
System.out.println("executing Jaxb2Marshaller");
Resource schemaResource = new ClassPathResource(schemaLocaation);
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath(contextPath);
jaxb2Marshaller.setSchema(schemaResource);
Map<String, Object> properties = new HashMap<>();
properties.put(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxb2Marshaller.setMarshallerProperties(properties);
return jaxb2Marshaller;
}
}
Sender and receiver code
#Component
public class Receiver {
#Autowired
JmsTemplate jmsTemplate;
#JmsListener(destination = "mailbox", containerFactory="myFactory")
public void receiveMessage(CacheMsgType submitEventType) {
System.out.println("Received <" + submitEventType + ">");
}
public void send(CacheMsgType submitEventType) {
jmsTemplate.convertAndSend("mailbox", submitEventType);
System.out.println("Successfully sent a message.");
}
}
JAXB Generated classes
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "SubmitEventType", namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", propOrder = {
"eventType",
"clientApplication",
"clientReferenceID",
"systemDate",
"transactionAcceptTime",
"bsb",
"accountNumber",
"productcode",
"accttypecode",
"trancode",
"meid",
"baiCode",
"baiDecs",
"tranamount",
"amountonhold",
"recordedlimit",
"currentbalance",
"availablebalance",
"description",
"reference",
"payer"
})
public class SubmitEventType {
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String eventType;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String clientApplication;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String clientReferenceID;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String systemDate;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String transactionAcceptTime;
#XmlElement(name = "BSB", namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String bsb;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String accountNumber;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String productcode;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String accttypecode;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String trancode;
#XmlElement(name = "MEID", namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String meid;
#XmlElement(name = "BAICode", namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String baiCode;
#XmlElement(name = "BAIDecs", namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String baiDecs;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String tranamount;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String amountonhold;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String recordedlimit;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String currentbalance;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String availablebalance;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String description;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String reference;
#XmlElement(namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected String payer;
/**
* Gets the value of the eventType property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getEventType() {
return eventType;
}
/**
* Sets the value of the eventType property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setEventType(String value) {
this.eventType = value;
}
/**
* Gets the value of the clientApplication property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getClientApplication() {
return clientApplication;
}
/**
* Sets the value of the clientApplication property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setClientApplication(String value) {
this.clientApplication = value;
}
/**
* Gets the value of the clientReferenceID property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getClientReferenceID() {
return clientReferenceID;
}
/**
* Sets the value of the clientReferenceID property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setClientReferenceID(String value) {
this.clientReferenceID = value;
}
/**
* Gets the value of the systemDate property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getSystemDate() {
return systemDate;
}
/**
* Sets the value of the systemDate property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setSystemDate(String value) {
this.systemDate = value;
}
/**
* Gets the value of the transactionAcceptTime property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getTransactionAcceptTime() {
return transactionAcceptTime;
}
/**
* Sets the value of the transactionAcceptTime property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setTransactionAcceptTime(String value) {
this.transactionAcceptTime = value;
}
/**
* Gets the value of the bsb property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getBSB() {
return bsb;
}
/**
* Sets the value of the bsb property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setBSB(String value) {
this.bsb = value;
}
/**
* Gets the value of the accountNumber property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getAccountNumber() {
return accountNumber;
}
/**
* Sets the value of the accountNumber property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setAccountNumber(String value) {
this.accountNumber = value;
}
/**
* Gets the value of the productcode property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getProductcode() {
return productcode;
}
/**
* Sets the value of the productcode property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setProductcode(String value) {
this.productcode = value;
}
/**
* Gets the value of the accttypecode property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getAccttypecode() {
return accttypecode;
}
/**
* Sets the value of the accttypecode property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setAccttypecode(String value) {
this.accttypecode = value;
}
/**
* Gets the value of the trancode property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getTrancode() {
return trancode;
}
/**
* Sets the value of the trancode property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setTrancode(String value) {
this.trancode = value;
}
/**
* Gets the value of the meid property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getMEID() {
return meid;
}
/**
* Sets the value of the meid property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setMEID(String value) {
this.meid = value;
}
/**
* Gets the value of the baiCode property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getBAICode() {
return baiCode;
}
/**
* Sets the value of the baiCode property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setBAICode(String value) {
this.baiCode = value;
}
/**
* Gets the value of the baiDecs property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getBAIDecs() {
return baiDecs;
}
/**
* Sets the value of the baiDecs property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setBAIDecs(String value) {
this.baiDecs = value;
}
/**
* Gets the value of the tranamount property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getTranamount() {
return tranamount;
}
/**
* Sets the value of the tranamount property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setTranamount(String value) {
this.tranamount = value;
}
/**
* Gets the value of the amountonhold property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getAmountonhold() {
return amountonhold;
}
/**
* Sets the value of the amountonhold property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setAmountonhold(String value) {
this.amountonhold = value;
}
/**
* Gets the value of the recordedlimit property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getRecordedlimit() {
return recordedlimit;
}
/**
* Sets the value of the recordedlimit property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setRecordedlimit(String value) {
this.recordedlimit = value;
}
/**
* Gets the value of the currentbalance property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getCurrentbalance() {
return currentbalance;
}
/**
* Sets the value of the currentbalance property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setCurrentbalance(String value) {
this.currentbalance = value;
}
/**
* Gets the value of the availablebalance property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getAvailablebalance() {
return availablebalance;
}
/**
* Sets the value of the availablebalance property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setAvailablebalance(String value) {
this.availablebalance = value;
}
/**
* Gets the value of the description property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getDescription() {
return description;
}
/**
* Sets the value of the description property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setDescription(String value) {
this.description = value;
}
public String getReference() {
return reference;
}
public void setReference(String value) {
this.reference = value;
}
public String getPayer() {
return payer;
}
public void setPayer(String value) {
this.payer = value;
}
}
CashMsgType.java
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name = "CacheMsg", namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "CacheMsgType", namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", propOrder = {
"submitEvent"
})
public class CacheMsgType {
#XmlElement(name = "SubmitEvent", namespace = "nabgroup.com/nab/schema/PaymentsExecution/SubmitPaymentEvent", required = true)
protected List<SubmitEventType> submitEvent;
public List<SubmitEventType> getSubmitEvent() {
if (submitEvent == null) {
submitEvent = new ArrayList<SubmitEventType>();
}
return this.submitEvent;
}
}
It seems sending on to mailbox queue is working but receiving gives error
Exception
2018-05-05 10:44:53.280 WARN 4120 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer : Execution of JMS message listener failed, and no ErrorHandler has been set.
org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method could not be invoked with incoming message
Endpoint handler details:
Method [public void com.nab.services.mq.Receiver.receiveMessage(com.nab.services.dto.CacheMsgType)]
Bean [com.nab.services.mq.Receiver#134bfc8]
; nested exception is org.springframework.messaging.converter.MessageConversionException: Cannot convert from [javax.xml.bind.JAXBElement] to [com.nab.services.dto.CacheMsgType] for org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener$MessagingMessageConverterAdapter$LazyResolutionMessage#3621aa, failedMessage=org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener$MessagingMessageConverterAdapter$LazyResolutionMessage#3621aa
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:118) ~[spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:77) ~[spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:736) ~[spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:696) ~[spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:674) ~[spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1189) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1179) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1076) [spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]
Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [javax.xml.bind.JAXBElement] to [com.nab.services.dto.CacheMsgType] for org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener$MessagingMessageConverterAdapter$LazyResolutionMessage#3621aa
at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:144) ~[spring-messaging-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:116) ~[spring-messaging-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:137) ~[spring-messaging-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:109) ~[spring-messaging-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:114) ~[spring-jms-5.0.5.RELEASE.jar:5.0.5.RELEASE]
... 10 common frames omitted
This might be implementation specific, but once the message is sent, you should be able to read the message id from the message itself.

#ManyToMany spring-mvc, spring-data-jpa, update error - failed to lazily initialize a collection of role

Very well-known exception "failed to lazily initialize a collection of role". I read many blogs, many suggestions but they did not work for my case.
Can anybody help me to understand how to resolve my issue ?
All these work in WAR spring-webmvc (JSP view).
I have entities Person and Address. 1 Person can have many Addresses, at 1 Address can live many persons (family). Look :
package abc.def.data.model;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
/**
*/
#Entity
#Table( name = "PERSON" )
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
/*
* ID of person.
*/
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private long id;
/*
* email and used as login of person.
*/
#Column( name = "email", length = 128, nullable = false, unique = true )
private String email;
/*
* Fullname of person.
*/
#Column( name = "fullname", length = 128, nullable = true )
private String fullName;
/*
* Person`s password. It is stored as encrypted value. Nobody know this value except person. There used
* Spring encryption mechanism. Look at the
*/
#Column( name = "password", length = 128, nullable = false )
private String password;
/*
*
*/
#Column( name = "role", length = 16, nullable = false )
private String role;
#Column( name = "timezone", nullable = false )
private int timezone;
#Column( name = "created", nullable = false )
#Type( type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime" )
private DateTime created;
#Column( name = "updated", nullable = false )
#Type( type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime" )
private DateTime updated;
#Column( name = "isenabled", nullable = false )
#Type( type = "true_false" )
private boolean enabled;
/*
* Addresses of person. One person can has many addresses. In that time many persons can live in one
* address (family).
*/
#ManyToMany( fetch = FetchType.LAZY, cascade = {CascadeType.ALL} )
#JoinTable( name = "PERSON_ADDRESS", joinColumns = {#JoinColumn( name = "personid",
referencedColumnName = "id" )}, inverseJoinColumns = {#JoinColumn( name = "addressid",
referencedColumnName = "id" )} )
private Set<Address> addresses = new HashSet<Address>(0);
/**
* closed Contructor. Need for JPA.
*/
protected Person() {
}
/**
* Public Contructor.
*
* #param fullName
* #param email
* #param role
* #param timezone
* #param created
* #param udated
*/
public Person( String fullName, String email, String password, String role, int timezone,
DateTime created, DateTime udated, boolean enabled ) {
this.fullName = fullName;
this.email = email;
this.password = password;
this.role = role;
this.timezone = timezone;
this.created = created;
updated = udated;
this.enabled = enabled;
}
/**
* Public Contructor without enabled status field. By default user is DISABLED here.
*
* #param fullName
* #param email
* #param role
* #param timezone
* #param created
* #param udated
*/
public Person( String fullName, String email, String password, String role, int timezone,
DateTime created, DateTime udated ) {
this.fullName = fullName;
this.email = email;
this.password = password;
this.role = role;
this.timezone = timezone;
this.created = created;
updated = udated;
this.enabled = false;
}
/*
* (non-Javadoc)
* #see java.lang.Object#toString()
*/
#Override
public String toString() {
return String.format(
"Person [id=%s, fullName=%s, email=%s, password=%s, role=%s, timezone=%s, created=%s,"
+ " updated=%s, enabled=%s, {address}]", id, fullName, email, password, role,
timezone, created, updated, enabled );
}
/**
* Getter.
*
* #return the id
*/
public long getId() {
return id;
}
/**
* Getter.
*
* #return the fullName
*/
public String getFullName() {
return fullName;
}
/**
* Getter.
*
* #return the email
*/
public String getEmail() {
return email;
}
/**
* Getter.
*
* #return the password
*/
public String getPassword() {
return password;
}
/**
* Getter.
*
* #return the role
*/
public String getRole() {
return role;
}
/**
* Getter.
*
* #return the timezone
*/
public int getTimezone() {
return timezone;
}
/**
* Getter.
*
* #return the created
*/
public DateTime getCreated() {
return new DateTime( created, DateTimeZone.forOffsetMillis( this.timezone ) );
}
/**
* Getter.
*
* #return the updated
*/
public DateTime getUpdated() {
return new DateTime( updated, DateTimeZone.forOffsetMillis( this.timezone ) );
}
/**
* Getter.
*
* #return the enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* Getter.
*
* #return the addressCollection
*/
public Set<Address> getAddresses() {
//force clients through our add and remove methods
return Collections.unmodifiableSet( addresses );
}
public void addAddress( Address address ) {
//avoid circular calls : assumes equals and hashcode implemented
if ( !addresses.contains( address ) ) {
addresses.add( address );
//add method to Product : sets 'other side' of association
address.addPerson( this );
}
}
public void removeAddress( Address address ) {
//avoid circular calls : assumes equals and hashcode implemented
if ( !addresses.contains( address ) ) {
addresses.remove( address );
//add method to Product : sets 'other side' of association
address.removePerson( this );
}
}
/**
* Setter.
*
* #param id
* the id to set
*/
public void setId( long id ) {
this.id = id;
}
/**
* Setter.
*
* #param fullName
* the fullName to set
*/
public void setFullName( String fullName ) {
this.fullName = fullName;
}
/**
* Setter.
*
* #param email
* the email to set
*/
public void setEmail( String email ) {
this.email = email;
}
/**
* Setter.
*
* #param password
* the password to set
*/
public void setPassword( String password ) {
this.password = password;
}
/**
* Setter.
*
* #param role
* the role to set
*/
public void setRole( String role ) {
this.role = role;
}
/**
* Setter.
*
* #param timezone
* the timezone to set
*/
public void setTimezone( int timezone ) {
this.timezone = timezone;
}
/**
* Setter.
*
* #param created
* the created to set
*/
public void setCreated( DateTime created ) {
this.created = created;
}
/**
* Setter.
*
* #param updated
* the updated to set
*/
public void setUpdated( DateTime updated ) {
this.updated = updated;
}
/**
* Setter.
*
* #param enabled
* the enabled to set
*/
public void setEnabled( boolean enabled ) {
this.enabled = enabled;
}
/**
* Setter.
*
* #param addressCollection
* the addressCollection to set
*/
public void setAddresses( Set<Address> addressCollection ) {
this.addresses = addressCollection;
}
/*
* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) ( id ^ ( id >>> 32 ) );
return result;
}
/*
* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals( Object obj ) {
if ( this == obj ) return true;
if ( obj == null ) return false;
if ( getClass() != obj.getClass() ) return false;
Person other = (Person) obj;
if ( id != other.id ) return false;
return true;
}
}
Address :
package abc.def.data.model;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
/**
* Addresses of person. <br />
* One person can has many addresses. In that time many persons can live in one address (family).
*
*/
#Entity
#Table( name = "ADDRESS", uniqueConstraints = {#UniqueConstraint( columnNames = {"country", "city", "street",
"housenum"} )}, indexes = {} )
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
/*
* Address ID.
*/
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private long id;
/*
* Name of country.
*/
#Column( length = 128 )
private String country;
/*
* Name of city.
*/
#Column( length = 64 )
private String city;
/*
* Name of street.
*/
#Column( length = 64 )
private String street;
/*
* Number of house.
*/
#Column( name = "housenum" )
private Integer houseNumber;
/*
* Users who live at this Address.
*/
#ManyToMany( fetch = FetchType.LAZY, mappedBy = "addresses" )
public Set<Person> persons = new HashSet<Person>( 0 );
/**
* Getter.
*
* #return the id
*/
public long getId() {
return id;
}
/**
* Getter.
*
* #return the country
*/
public String getCountry() {
return country;
}
/**
* Getter.
*
* #return the city
*/
public String getCity() {
return city;
}
/**
* Getter.
*
* #return the street
*/
public String getStreet() {
return street;
}
/**
* Getter.
*
* #return the houseNumber
*/
public Integer getHouseNumber() {
return houseNumber;
}
/**
* Getter.
*
* #return the personCollection
*/
public Set<Person> getPersons() {
return Collections.unmodifiableSet( persons );
}
/**
* Setter.
*
* #param id
* the id to set
*/
public void setId( long id ) {
this.id = id;
}
/**
* Setter.
*
* #param country
* the country to set
*/
public void setCountry( String country ) {
this.country = country;
}
/**
* Setter.
*
* #param city
* the city to set
*/
public void setCity( String city ) {
this.city = city;
}
/**
* Setter.
*
* #param street
* the street to set
*/
public void setStreet( String street ) {
this.street = street;
}
/**
* Setter.
*
* #param houseNumber
* the houseNumber to set
*/
public void setHouseNumber( Integer houseNumber ) {
this.houseNumber = houseNumber;
}
/**
* Setter.
*
* #param personCollection
* the personCollection to set
*/
public void setPersons( Set<Person> personCollection ) {
this.persons = personCollection;
}
/*
* (non-Javadoc)
* #see java.lang.Object#toString()
*/
#Override
public String toString() {
return String.format( "Address [id=%s, country=%s, city=%s, street=%s, houseNumber=%s, {person}]",
id, country, city, street, houseNumber );
}
/**
*
*/
public void addPerson( Person person ) {
//assumes equals and hashcode implemented: avoid circular calls
if ( !persons.contains( person ) ) {
persons.add( person );
//add method to Product : sets 'other side' of association
person.addAddress( this );
}
}
/**
*
*/
public void removePerson( Person person ) {
//assumes equals and hashcode implemented: avoid circular calls
if ( !persons.contains( person ) ) {
persons.remove( person );
}
//add method to Product : sets 'other side' of association
person.removeAddress( this );
}
/*
* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) ( id ^ ( id >>> 32 ) );
return result;
}
/*
* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals( Object obj ) {
if ( this == obj ) return true;
if ( obj == null ) return false;
if ( getClass() != obj.getClass() ) return false;
Address other = (Address) obj;
if ( id != other.id ) return false;
return true;
}
}
In case New registration and new person and new address - no problem. It passed find.
In PersonService #Service I have :
// create new Person
Person newPerson = new Person( fullName, email, password, role, timezone, created, udated, true );
// add addresses - it is possible have more 1 address in registration
newPerson.setAddresses( (Set<Address>) addrList );
try {
newPerson = personRepository.save( newPerson );
} catch (Exception e) {
actionResult.setError( true );
actionResult.addErrorItem( "error", e.getMessage() );
}
LOG.debug( "Created new person : {}", newPerson.toString() );
actionResult.setObject( newPerson );
return actionResult;
/*
* Check given addresses for existing.
*/
private Collection<Address> checkAddresses( Set<Address> addrList, Person newPerson ) {
Set<Address> newAddresses = new HashSet<Address>();
Address addr = null;
for (Address address : addrList) {
addr =
addressRepository.findByCountryAndCityAndStreetAndHouseNumber( address.getCountry(), address.getCity(), address.getStreet(), address.getHouseNumber() );
if ( addr != null ) {
addr.getPersons().size();
}
addr = addr == null ? address : addr;
newAddresses.add( addr );
LOG.debug( "checked address {}", addr.toString() );
}
return newAddresses;
}
personRepository :
public interface PersonRepository extends JpaRepository<Person, Long> {
}
In case new user enter existing address - it checks (found) in DB. When it found it have to be added to newPerson() . In this case exception arise.
I tried use address.getPerson().size - also exception .
Also I do not want use EAGER. is It possible ?
If you don't have an active transaction or open thread-bound EntityManager, Spring Data JPA will create a new EntityManager for each call on a repository. Then it closes the EntityManager before returning, leading to the exception you're getting when Hibernate tries to lazy-load.
There are two ways to deal with this. One is to use transactions, possibly by applying #Transactional as appropriate. The other is to use OpenEntityManagerInViewFilter, which will create a thread-bound EntityManager at the beginning of each request and hold it open for the entire request. In this case I think a transaction is called for because you're doing an INSERT that depends on previous SELECTs. OpenEntityManagerInViewFilter is very handy for using lazy-loaded collections in views, but it doesn't provide any transaction management.

Resources