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)?
Related
Place that is complaining the error:
#Data
public class AluguelValorForm {
#Autowired
private ValorAluguelMultaService valorAluguelMultaService;
#NotNull #NotEmpty
private String idAluguel;
#NotNull
private Double valor;
public AluguelValor converter(AluguelValorRepository aluguelValorRepository, AluguelForm form ) {
Double valorAluguel = valorAluguelMultaService.valorAluguel(form);
return new AluguelValor(idAluguel,valorAluguel);
}
public AluguelValor update(String idAluguel,Double valor) {
AluguelValor aluguelValor = new AluguelValor();
aluguelValor.setId(idAluguel);
aluguelValor.setValor(valor);
return aluguelValor;
}
Repository:
#Repository
public interface AluguelValorRepository extends MongoRepository<AluguelValor, String> {
Aluguel getReferenceById(String id);
}
Place that I call the method in AluguelValorForm:
#PostMapping
//#CacheEvict(value = "listaDeTopicos",allEntries = true)
public void cadastrar(#RequestBody AluguelForm form) {
Optional<Carro> carro = carroRepository.findByPlaca(form.getPlaca_carro());
Optional<Cliente> cliente = clienteRepository.findByCpf(form.getCpf());
if(carro.isPresent() && cliente.isPresent()) {
Aluguel aluguel2 = form.converter(aluguelRepository);
aluguelRepository.save(aluguel2);
Double valorAluguel = valorAluguelMultaService.valorAluguel(form);
AluguelValor aluguelValor = aluguelValorForm.update(aluguel2.getId(), valorAluguel);
aluguelValorRepository.save(aluguelValor);
}
}
Problem solved. Apparently, it's not possible to #Autowired a class that doesn't have any bean, like my RentValue. That's why I got this error.
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;
}
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)
I am trying to use the automatic versioning of Hibernate but when the update method f of the Session is called I do not see the version field in the where clause of the query nor is the version incremented in the database. I am doing something fundamentally wrong probably, but what? Is calling getCurrentSession of sesssionFactory an issue?
I have the following entity class:
package dslibweb.model;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;
#Entity
#Table(name = "dsXCT_Recalls")
public class DsXCT_Recalls {
#Id
public String recallId;
public int version;
public String status;
//...... more properties.....
#Version
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getRecallId() {
return recallId;
}
public void setRecallId(String recallId) {
this.recallId = recallId;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
My controller:
package recalls.controller;
#Controller
public class RecallsDataController {
#Autowired
RecallsService recallsManager;
#Autowired
AuthenticationService authService;
private static final Logger logger = Logger.getLogger(RecallsDataController.class);
private static final String SAVE_RECALLS = "MODIFY XCT RECALLS";
RecallsGrid recalls;
#RequestMapping(value = "/showRecallsGrid")
#ResponseBody
public RecallsGrid showRecallsGrid( HttpSession session, HttpServletResponse response) {
recalls = recallsManager.getRecallsDataGrid((String) session.getAttribute("socketToken"), new GridFilters(0, 0, "", "", "", "", ""));
if (recalls.getError() == null || recalls.getError().equals("")) { // no error
return recalls;
} else {
try {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, recalls.getError());
} catch (IOException e) {
e.printStackTrace();
}
return recalls;
}
}
#RequestMapping(value = "/saveRecalls" , method= RequestMethod.POST)
#ResponseBody
public String saveRecalls( HttpSession session, #RequestParam(value="ids[]", required = false) String [] ids, #RequestParam(value="statuses[]", required = false) String [] statuses){
boolean result = authService.validateUserAction((String) session.getAttribute("socketToken"), SAVE_RECALLS);
if(result)
return recallsManager.saveRecalls(ids, statuses, recalls);
else
return "You do not have authority to perform this action.";
}
}
Where I retrieve a collection of DsXCT_Recalls and show them to the user. The collection is stored in the controller. The user then changes status in one or more entities and I call the saveRecalls method of the recallManager which creates a list of only the changed entities (comparing with the collection stored in the controller).
The recallsManager (service layer) is:
package recalls.service.defaultimpl;
#Service("recallManager")
public class HibernateRecallsDataService implements RecallsService {
#Autowired
JsonRpcRequest jsonReq;
#Autowired
JsonRpcSocketWriterReader socketWriterReader;
#Autowired
JsonRpcRequestConstructor reqConstructor;
#Autowired
RecallsDao hibernateRecallsDao;
private static final Logger logger = Logger.getLogger(HibernateRecallsDataService.class);
#Transactional
public RecallsGrid getRecallsDataGrid(String socketToken, GridFilters filters) {
List<DsXCT_Recalls> recalls = hibernateRecallsDao.findRangeOfRecordsFiltered(filters);
return new RecallsGrid(recalls);
}
#Transactional()
public String saveRecalls(String[] ids, String[] statuses, RecallsGrid recalls) {
List<DsXCT_Recalls> recallList = recalls.getRecalls();
List<DsXCT_Recalls> updatedRecallList = new ArrayList<DsXCT_Recalls>();
for (int i = 0; i < ids.length; i++) {
for (DsXCT_Recalls recall : recallList) {
if (recall.recallId.equals(ids[i])) { // recall is found in the list
if (!statuses[i].equals(recall.getStatus())) { // status has changed
recall.setStatus(statuses[i]);
updatedRecallList.add(recall);
}
}
}
}
return hibernateRecallsDao.saveAll(updatedRecallList);
}
}
The saveAll method of my DAO calls one update method of hibernate session by entity changed:
package recalls.dao.hibernate;
#Repository
public class HibernateRecallsDao implements RecallsDao {
#Autowired(required = true)
#Resource(name = "mySessionFactory")
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public List<DsXCT_Recalls> findRangeOfRecordsFiltered(GridFilters filters) {
return sessionFactory.getCurrentSession().createQuery("from DsXCT_Recalls r WHERE SID = 0 ORDER BY Org, Bank, BIC, SetlDate").list();
}
public String saveAll(List<DsXCT_Recalls> recallList){
int count = 0;
for(DsXCT_Recalls recall:recallList){
sessionFactory.getCurrentSession().update(recall);
count++;
}
return count + " recalls were modified.";
}
}
So apparently the #Version must be above the attribute declaration and not above the getter method.. I am sure I saw this somewhere though. So much time wasted :(
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