Integrating JPA2.0 and Spring - java

last few hours I try to test with spring jpa 2.0 3.0
Finally I could recover objects persisted
but when I try to persist a new object I receive the following error message:
org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:306)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:102)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.orm.jpa.JpaAccessor.translateIfNecessary(JpaAccessor.java:152)
at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:188)
at org.springframework.orm.jpa.JpaTemplate.flush(JpaTemplate.java:288)
at myPackage.testDAO.create(testDAO.java:33)
at myPackage.Main.main(Main.java:27)
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:789)
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.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy21.flush(Unknown Source)
at org.springframework.orm.jpa.JpaTemplate$8.doInJpa(JpaTemplate.java:290)
at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:183)
... 3 more
my entity bean:
#Entity
public class Application implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="ID_APPLICATION")
private long idApplication;
#Temporal( TemporalType.DATE)
#Column(name="DATE_LIVRAISON")
private Date dateLivraison;
#Lob()
private String description;
#Column(name="NOM_APPLICATION")
private String nomApplication;
private String url;
//bi-directional many-to-one association to Test
#OneToMany(mappedBy="application")
private List<Test> tests;
public Application() {
}
public long getIdApplication() {
return this.idApplication;
}
public void setIdApplication(long idApplication) {
this.idApplication = idApplication;
}
public Date getDateLivraison() {
return this.dateLivraison;
}
public void setDateLivraison(Date dateLivraison) {
this.dateLivraison = dateLivraison;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getNomApplication() {
return this.nomApplication;
}
public void setNomApplication(String nomApplication) {
this.nomApplication = nomApplication;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public List<Test> getTests() {
return this.tests;
}
public void setTests(List<Test> tests) {
this.tests = tests;
}
}
my repository:
#Repository
public class testDAO extends JpaDaoSupport implements ItestDAO {
#PersistenceContext
private EntityManager em;
public List<Application> findALL() {
// TODO Auto-generated method stub
return null;
}
public Application findById(long id) {
// TODO Auto-generated method stub
return getJpaTemplate().find(Application.class, id);
}
public void create(Application application) {
getJpaTemplate().persist(application);
}
}
findById method works normally (which reassures me that jpa configuration is correct), but when I run the create method I receive the above error message.
ApplicationContext context=new ClassPathXmlApplicationContext("application-context.xml");
testDAO dao=(testDAO)context.getBean("dao");
Application application=new Application();
application.setIdApplication(2);
application.setUrl("url");
application.setDescription("description");
application.setNomApplication("dsdsds");
dao.create(application);
any help are appreciated
Thank you for your help

In short, methods of EntityManager such as persist, remove, merge must be called inside a transaction, hence the error message which is actually self explaining:
javax.persistence.TransactionRequiredException: no transaction is in progress
Spring provides support for transaction management (see links below), including when writing tests... if you use one of the Spring testing class providing transactional support.
See also
10. Transaction Management
10.5 Declarative transaction management
10.5.6 Using #Transactional

Related

Spring Boot Repository.save() methods do not work - No commit

I scan two QR code and try to get them from My QR Code Android Mobile App and save it with repository.save() in my Local db.
My app send List to Backend but don't insert to db. When I run localhost/8090, i don't get back anything.
In Browser show only this:
-Find Devices
-Device Code
-Device ID
Developer.java
#Entity
public class Developer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id = 0;
private String deviceCode;
private String deviceId;
public Developer() {
super();
}
public Developer(String deviceCode, String deviceID)
{
super();
this.deviceCode = deviceCode;
this.deviceId = deviceId;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String deviceCode() {
return deviceCode;
}
public void set DeviceCode(String deviceCode) {
this.deviceCode;
}
public String deviceId() {
return deviceId;
}
public void set DeviceId(String deviceId) {
this.deviceId;
}
}
DeveloperRepository.java
import org.springframework.data.repository.CrudRepository;
public interface DeveloperRepository extends CrudRepository<Developer, Long> {
}
DeveloperController.java
#Controller
public class DevelopersController {
#Autowired
DeveloperRepository repository;
#RequestMapping(value = "/", method = RequestMethod.POST)
#ResponseBody
private String addDevices(Developer deviceCodeAndId) {
System.out.println("xyz!");
if (!repository.exists(deviceCodeAndId.getId())) {
repository.save(deviceCodeAndId);
return "successfully added " + deviceCodeAndId.getId();
}
return deviceCodeAndId.getId();
}
#RequestMapping(value = "/showall",method = RequestMethod.GET)
public String index(Model model) {
model.addAttribute("index",repository.findAll());
return "index";
}
}
deviceCodeAndID is Class from Android App which scanned with app!
index.html
Have you enabled transaction management. Even you use Spring boot data repository. You need to enable transaction management, else by default everything will be read mode. And for read mode there is no need to transaction. But when you do any operation that will change data in DB, you need to perform transaction management.
Use #EnableTransactionManagement on in application class, and #Transactional in DAO or service class
#SpringBootApplication
public class Application {
#Autowired
DeveloperRepository developerRepository;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
Here is my Application Class

Spring EntityManager.persist issue

I am using a Spring framework (Boot+web+jpa) for a REST service and needs to persist an Entity called Sensor. Since I was using Hibernate, I wanted to keep usingEntityManager. From the Spring Data Access document and some of the questions answered in Stackoverflow, I could see that I should configure LocalEntityManagerFactoryBean or LocalContainerEntityManagerFactoryBean.
Now I was able to read persist.xml and persist the entity through dependency injection #PersistenceUnit(unitName="...") EntityManagerFactory in case for LocalContainerEntityManagerFactoryBean. However, Spring keeps throwing an error everytime when I try to persist new Sensor() instance with LocalEntityManagerFactoryBean as shown below.
// LocalEntityManagerFactoryBean
#Bean
public LocalEntityManagerFactoryBean entityManagerFactory() {
LocalEntityManagerFactoryBean em = new LocalEntityManagerFactoryBean();
em.setPersistenceUnitName("myunit");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
Persisting (transaction.begin and end are in the caller method):
private Sensor getSensor(SimpleData sd) {
List<Sensor> sensors = entityManager.createQuery("select s from Sensor s where s.deviceId = :devid", Sensor.class)
.setParameter("devid", sd.getDeviceId())
.getResultList();
Sensor sensor = null;
if(sensors.isEmpty()) {
sensor = new Sensor();
sensor.setDeviceId(sd.getDeviceId());
sensor.setName(sd.getName());
entityManager.persist(sensor); // Throws an exception
deviceIdMapper.put(sensor.getDeviceId(), sensor.getId());
logger.trace("Cannot find the sensor in db, adding: "+sensor.getDeviceId());
} else {
sensor = sensors.get(0);
deviceIdMapper.put(sensor.getDeviceId(), sensor.getId());
logger.trace("Found a sensor from the db: "+sd.getDeviceId());
}
deviceIdMapper.putIfAbsent(sensor.getDeviceId(), sensor.getId());
logger.trace(sensor);
return sensor;
}
Exception:
javax.persistence.PersistenceException: org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [protected int com.database.Sensor.id] by reflection for persistent property [com.database.Sensor#id] : com.database.Sensor#6de9600a
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:807)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:785)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350)
at com.sun.proxy.$Proxy108.persist(Unknown Source)
at com.DataListener.getSensor(DataListener.java:69)
at com.DataListener.lambda$0(DataListener.java:87)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at com.DataListener.processData(DataListener.java:86)
at com.DataListener.onMessage(DataListener.java:49)
at org.apache.activemq.ActiveMQMessageConsumer.dispatch(ActiveMQMessageConsumer.java:1321)
at org.apache.activemq.ActiveMQSessionExecutor.dispatch(ActiveMQSessionExecutor.java:131)
at org.apache.activemq.ActiveMQSessionExecutor.iterate(ActiveMQSessionExecutor.java:202)
at org.apache.activemq.thread.PooledTaskRunner.runTask(PooledTaskRunner.java:129)
at org.apache.activemq.thread.PooledTaskRunner$1.run(PooledTaskRunner.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [protected int com.database.Sensor.id] by reflection for persistent property [com.database.Sensor#id] : com.database.Sensor#6de9600a
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:75)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:224)
at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4931)
at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:4631)
at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:226)
at org.hibernate.event.internal.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:540)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:102)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:62)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:800)
... 20 more
Caused by: java.lang.IllegalArgumentException: Can not set int field com.database.Sensor.id to com.database.Sensor
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at java.base/jdk.internal.reflect.UnsafeIntegerFieldAccessorImpl.getInt(UnsafeIntegerFieldAccessorImpl.java:56)
at java.base/java.lang.reflect.Field.getInt(Field.java:594)
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:62)
... 28 more
Sensor class:
#Entity
public class Sensor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected int id;
protected String deviceId;
protected String name;
#OneToMany(mappedBy = "owner", cascade=CascadeType.ALL)
private List<SimpleData> simpleDevices = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<SimpleData> getSimpleDevices() {
return simpleDevices;
}
public void setSimpleDevices(List<SimpleData> simpleDevices) {
this.simpleDevices = simpleDevices;
}
}
There are two questions:
Why the error?
Spring throws an error if I do not provide DataSource for LocalContainerEntityManagerFactoryBean? LocalEntityManagerFactoryBean uses DataSource configs from persistence.xml Why LocalContainerEntityManagerFactoryBean doesn't do the same?:
Edit 1
I think I have found a solution. If I remove spring-boot-devtools from the dependency, it fixes the problem. In fact when I use spring-boot-devtools I could not read Sensor due to some sort of ClassLoader problem. Maybe some sort of a bug?:
java.lang.ClassCastException: class com.database.Sensor cannot be cast to class com.database.Sensor (com.database.Sensor is in unnamed module of loader 'app'; com.database.Sensor is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader #6228d409)
Edit 2
Here is SimpleData class
#Entity
public class SimpleData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private double value;
#JsonIgnore
private Date time;
#Transient
private String deviceId;
#JsonIgnore
#Transient
private String name;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="sensor_id")
private Sensor owner;
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public Sensor getOwner() {
return owner;
}
public void setOwner(Sensor owner) {
this.owner = owner;
}
}
Edit 3
Okay, I made a small test program that reproduces the problem: https://github.com/hjparker/spring-boot-devtools-issue.
Once the server is up, you can make a GET request to localhost:8080, which will throw an error. Commenting out spring-boot-devtools in build.gradle will solve the problem. I found this is something to do with the restart classloader in spring-dev-tools (https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html), which reloads developing code every time spring is restarted. But I think some part of the file is not reloaded automatically causing the classcastexception, e.g. An entity loaded with CL1 != An entity loaded with CL2. Can someone explain if I am doing something wrong?
It seems some of the deserializers for Entity or Bean classes managed by hibernate/Spring ORM are not reloaded by the spring-boot-devtools restart classloader properly. I had to explicitly include the classes that perform deserialization to the restart classloader by setting the following properties in META-INF/spring-devtools.properties:
restart.include.hibernate=hibernate.*
restart.include.spring-orm=spring-orm.*
Sources:
https://github.com/AxonFramework/AxonFramework/issues/344
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html#using-boot-devtools-customizing-classload
Need to update access modifier private instead of protected, seems that Java persistence tries to get id which is not in package neither is called on some subclass.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String deviceId;
private String name;
Access modifier documentation

Hibernate createCriteria query with annotation based composite primary key

In my project, I am having trouble writing a createCriteria query with a composite primary key. My Entity class & DAO method are given below -
#Entity
#Table(name="METRICS")
public class Metrics implements Serializable {
private static final long serialVersionUID = -2580493160757497919L;
#EmbeddedId
protected MetricsID metricsID;
#Column(name="PROJ_PERF")
private String proj_perf;
#Column(name="ANALYSIS")
private String analysis;
public String getProj_perf() {
return proj_perf;
}
public void setProj_perf(String proj_perf) {
this.proj_perf = proj_perf;
}
public String getAnalysis() {
return analysis;
}
public void setAnalysis(String analysis) {
this.analysis = analysis;
}
public MetricsID getMetricsID() {
return metricsID;
}
public void setMetricsID(MetricsID metricsID) {
this.metricsID = metricsID;
}
}
#Embeddable
public class MetricsID implements Serializable {
private static final long serialVersionUID = 4691163770334366543L;
#Column(name="PROJECT_ID")
private String project_id;
#Column(name="METRICS_NO")
private int metrics_no;
public String getProject_id() {
return project_id;
}
public void setProject_id(String project_id) {
this.project_id = project_id;
}
public int getMetrics_n0() {
return metrics_no;
}
public void setMetrics_no(int i) {
this.metrics_no = i;
}
}
#Override
#Transactional
public List<Metrics> viewMetrics(String project_id) throws Exception {
List<Metrics> metrics = (List<Metrics>)sessionFactory.getCurrentSession().
createCriteria(Metrics.class).createAlias("metricsID.project_id", "project_id_alias").
add(Restrictions.eqProperty("project_id_alias.project_id", project_id)).list();
return metrics;
}
The error I am getting is - org.hibernate.QueryException: not an association: metricsID.project_id
I searched for several similar examples, and used alias on the suggestion of one of the search results, but it's my first time using an alias. What am I doing wrong?
Why do you need to use an alias? Have you tried to access directly?
Following this example, this code should work
#Override
#Transactional
public List<Metrics> viewMetrics(String project_id) throws Exception {
List<Metrics> metrics =
(List<Metrics>) sessionFactory.getCurrentSession()
.createCriteria(Metrics.class)
.add(Restrictions.eq("metricsID.project_id", project_id))
.list();
return metrics;
}

Hibernate - Spring MVC - llegal attempt to associate a collection with two open sessions

There are are many questions of same type, but none works for me.
I have Spring MVC hibernate application.
Here are my two model classes
Config.java
public class Config implements java.io.Serializable {
private Integer configId;
private String configName;
private Set<ConfigFields> ConfigFieldses = new HashSet<ConfigFields>(0);
//getters and setters
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="configuration")
public Set<ConfigFields> getConfigFieldses() {
return this.ConfigFieldses;
}
public void setConfigFieldses(Set<ConfigFields> ConfigFieldses) {
this.ConfigFieldses = ConfigFieldses;
}
}
ConfigFields.java
public class ConfigFields implements java.io.Serializable {
private Integer configFieldId;
private Confign config;
private String configFieldName;
//getteres and setters
#XmlTransient
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="ConfigId")
public Config getConfig() {
return this.config;
}
public void setConfig(Config configu) {
this.config = config;
}
}
Here is GenericHibernateDao.java
#Repository
#Transactional
public class GenericHibernateDao<T extends Serializable>
implements GenericDao<T>{
#Resource
protected SessionFactory sessionFactory;
#Override
public void insert(T transientInstance) {
sessionFactory.getCurrentSession().persist(transientInstance);
}
#Override
public void update(T instance) {
sessionFactory.getCurrentSession().saveOrUpdate(instance);
}
#Override
public void delete(T persistentInstance) {
sessionFactory.getCurrentSession().delete(persistentInstance);
}
#SuppressWarnings("unchecked")
#Override
public T merge(Serializable detachedInstance) {
return (T) sessionFactory.getCurrentSession().merge(detachedInstance);
}
#SuppressWarnings("unchecked")
#Override
public T findById(Class<?> clazz, Serializable id) {
T t= (T) sessionFactory.openSession().get(clazz, id);
return t;
}
#SuppressWarnings("unchecked")
public List<T> findByNamedQuery(Class<T> clazz, String queryName, Map<String, Object> queryParams) {
Query namedQuery = sessionFactory.getCurrentSession().getNamedQuery(queryName);
for (String s : queryParams.keySet()) {
namedQuery.setParameter(s, queryParams.get(s));
}
return namedQuery.list();
}
}
In my controller I have this method
#RequestMapping(value = "/deleteConfig/{configId}", method = RequestMethod.POST)
#ResponseBody
#Transactional
public String deleteConfiguration(#PathVariable Integer configId, HttpServletResponse response) throws IOException {
try {
Config config=configService.findById(configId);
logger.info("Deleting configuration...");
configService.delete(config);
} catch(Exception e) {
logger.debug(e.getMessage());
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
return "success";
}
My test case
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("classpath:webapptest")
#ContextConfiguration(locations = {"classpath:test-applicationcontext.xml"})
public class ConfigurationsControllerTest {
private MockMvc springMvc;
#Autowired
WebApplicationContext wContext;
#Before
public void init() throws Exception {
springMvc = MockMvcBuilders.webAppContextSetup(wContext).build();
}
#Test
public void deleteConfiguration() throws Exception {
ResultActions resultActions=springMvc.perform(MockMvcRequestBuilders.post("/deleteConfig/117").accept(MediaType.APPLICATION_JSON));
resultActions.andDo(MockMvcResultHandlers.print());
resultActions.andExpect(MockMvcResultMatchers.status().isOk());
}
}
When I run the testcase in console, logger showing
Illegal attempt to associate a collection with two open sessions
And JUnit test case stacktrace is
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is bitronix.tm.internal.BitronixRollbackException: transaction was marked as rollback only and has been rolled back
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:932)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:66)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:168)
In Config class, I have Set which is set to CASCADE ALL. SO I am able to insert set of configfields while inserting config too. But now I want to delete by passing config object. So it should delete 1 row from config table and few rows from configfields table based on configId.
What is wrong here? And how to solve without affecting application(I mean insert)

LazyInitializationException encountered when using load instead of get with Hibernate

I am using JPA, Hibernate and Spring MVC. In the controller class all the methods works greatly. When I test them in the web browser the public String getModuleFormation(long id) method, that returns an object, and it gives me the following error:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
as a root cause, but yesterday I tried it, and it worked without problem in the localhost:45045/GestionModules/detail/xx URL.
What could cause this problem?
My detail.jsp:
<c:if test="${!empty detailModule}">
${detailModule.idModule}
${detailModule.libModule}
</c:if>
POJO Class + JPA :
#Entity
#Table(name="ModuleFormation")
public class ModuleFormation {
private long idModule;
private String libModule;
public ModuleFormation() {
// TODO Auto-generated constructor stub
}
public ModuleFormation(String libModule) {
this.libModule = libModule;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "seqModule")
#SequenceGenerator(name="seqModule", sequenceName = "seqModuleFormation")
#Column(name="idModule")
public long getIdModule() {
return this.idModule;
}
public void setIdModule(long idModule) {
this.idModule = idModule;
}
#Column(name="libModule", nullable=false, length = 100)
public String getLibModule() {
return this.libModule;
}
public void setLibModule(String libModule) {
this.libModule = libModule;
}
}
DAO Class :
#Repository
public class ModuleFormationDAOImpl implements ModuleFormationDAO {
#Autowired
private SessionFactory sessionFactory;
public void ajouterModuleFormation(ModuleFormation module) {
sessionFactory.getCurrentSession().save(module);
}
public void supprimerModuleFormation(long idModule) {
ModuleFormation module = (ModuleFormation) sessionFactory.getCurrentSession().load(ModuleFormation.class, idModule);
if(module != null)
sessionFactory.getCurrentSession().delete(module);
}
public List<ModuleFormation> listModuleFormation() {
return sessionFactory.getCurrentSession().createQuery("from ModuleFormation")
.list();
}
public ModuleFormation getModuleFormation(long idModule) {
return (ModuleFormation) sessionFactory.getCurrentSession().load(ModuleFormation.class, idModule);
}
public void majModuleFormation(ModuleFormation module) {
sessionFactory.getCurrentSession().merge(module);
}
}
Service Class :
#Service
public class ModuleFormationServiceImpl implements ModuleFormationService {
#Autowired
private ModuleFormationDAO moduleDao;
#Transactional
public void ajouterModuleFormation(ModuleFormation module) {
moduleDao.ajouterModuleFormation(module);
}
#Transactional
public void supprimerModuleFormation(long idModule) {
moduleDao.supprimerModuleFormation(idModule);
}
#Transactional
public List<ModuleFormation> listModuleFormation() {
return moduleDao.listModuleFormation();
}
#Transactional
public ModuleFormation getModuleFormation(long idModule) {
return moduleDao.getModuleFormation(idModule);
}
#Transactional
public void majModuleFormation(ModuleFormation module) {
moduleDao.majModuleFormation(module);
}
}
Controller Class :
#Controller
public class ModuleFormationController {
#Autowired
private ModuleFormationService moduleService;
#RequestMapping("/module")
public String listModulesFormations(Map<String, Object> map) {
map.put("module", new ModuleFormation());
map.put("moduleList", moduleService.listModuleFormation());
return "module";
}
#RequestMapping(value = "/ajouter", method = RequestMethod.POST )
public String ajouterModuleFormation(#ModelAttribute("module")
ModuleFormation module,BindingResult result) {
moduleService.ajouterModuleFormation(module);
return "redirect:/module";
}
#RequestMapping(value = "/supprimer/{idModule}")
public String supprimerModuleFormation(#PathVariable("idModule")
long idModule) {
moduleService.supprimerModuleFormation(idModule);
return "redirect:/module";
}
#RequestMapping(value= "/detail/{idModule}")
public String getModuleFormation(#PathVariable("idModule")
long idModule,Map<String, Object> map) {
map.put("detailModule", moduleService.getModuleFormation(idModule));
return "/detail";
}
#RequestMapping(value= "/detail/modifier", method = RequestMethod.POST )
public String majModuleFormation(#ModelAttribute("detailModule")
ModuleFormation module, BindingResult result) {
moduleService.majModuleFormation(module);
return "detail/{idModule}";
}
}
The Javadoc on the Hibernate Session#load(Class, Serializable) method says:
Return the persistent instance of the given entity class with the given identifier,
assuming that the instance exists. This method might return a proxied instance that
is initialized on-demand, when a non-identifier method is accessed.
When you access a property on the object in your JSP the session which loaded the object has been closed.
Use Session#get(Class, Serializable) to ensure that you don't load a proxy.
Instead of sessionFactory.getCurrentSession().load(ModuleFormation.class, idModule), have you tried sessionFactory.getCurrentSession().get(ModuleFormation.class, idModule)?

Categories