I am trying to get a small sample web app up and running but I have run into a problem injecting the Entity Manager Factory.
My persistence.xml is as follows;
<persistence version="2.0" xmlns=" http://java.sun.com/xml/ns/persistene"
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence ttp://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="main" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/Maindb</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
</properties>
</persistence-unit>
The web application has two functions; return a customer and a list of items.
The CustomerResource object injects the entity manager factory as follows:
#PersistenceUnit(unitName="main")
private EntityManagerFactory emf;
and queries the persistence layer by the following code;
EntityManager em = emf.createEntityManager();
Customer customer = (Customer) em.find(Customer.class, customerID);
This works with no problems (that I am aware of), I get the expected data returned.
The ItemResource object does the same thing against the same persistence unit.
#PersistenceUnit(unitName="main")
private EntityManagerFactory emf;
But the injection fails and emf is always null.
EntityManager em = emf.createEntityManager(); <- emf is null here
I am unsure of what I have done wrong here, my guess is that I am using the entity manager factory incorrectly.
Any help would be much appreciated! Thanks
Update
I was taking out the troublesome code to put in a war file for everyone to look at which helped me isolate the problem.
The issue seems to be with the url patterns I am using.
web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Item</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Item</servlet-name>
<url-pattern>/Item/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Customer</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Customer</servlet-name>
<url-pattern>/Customer</url-pattern>
</servlet-mapping>
</web-app>
sun-jaxws.xml:
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint name="Item" implementation="com.test.item.ItemResource" url-pattern="/Item/*" />
<endpoint name="Customer" implementation="com.test.customer.CustomerResource" url-pattern="/Customer" />
</endpoints>
The item resource right now has two web methods;
Get Item Details
Type: Get
Path: /
Web param: item id
Get Item List
Type: Get
Path: /list
Web param: Item Colour
With the wild cards in the url patterns the entity manager is always null. If I remove the wild cards then I can successfully request an item, put I cannot request a list of items because it is not mapped.
The customer resource requests are always successful because it does not contain any wild cards in the mappings.
Thanks
I am not sure this will answer the question (why is the EMF null in the second case?) but since you're using an application-managed entity manager, do you close the EntityManager properly? Something like this:
public class LoginServlet extends HttpServlet {
#PersistenceUnit(unitName="EmployeeService")
EntityManagerFactory emf;
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
String userId = request.getParameter("user");
// check valid user
EntityManager em = emf.createEntityManager();
try {
User user = em.find(User.class, userId);
if (user == null) {
// return error page
// ...
}
} finally {
em.close();
}
}
But, honestly, I really wonder why you aren't using a container-managed entity manager. It is much simpler to let the container manage its life cycle in my opinion. To get an EntityManager injected:
#PersistenceContext(unitName = "main")
private EntityManager em;
Related
When using JPA 2.1 in our current application, we encounter a 500 internal server error when sending web service request. The issue resolves and JPA works properly only after a reboot of the application's managed server. I'm using eclipselink as my JPA provider since this is what is provided on the server. My current deployment unzips the ear file and deployed an exploded file that contains META-INF (application.xml, MANIFEST.MF, weblogic-application.xml) and the war file which contains the classes and persistence.xml file. I'm currently deploying using the wldeploy ant script with redeploy as the action.
JPA only works after the initial deployment or a bounce of the managed server if I was to redeploy.
Could this be an issue with my deployment or the structure or the EAR and WAR files or could it be an implementation issue with JPA?
I've included the #RequestScoped annotation on the web service class.
I've included the beans.xml file in my web folder with the following line:
bean-discovery-mode="annotated">
My web folder contains the following:
web/WEB-INF/classes/persistence.xml
web/beans.xml
web/web.xml
web/weblogic.xml
Persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
<persistence-unit name="DB" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/PublicAPI</jta-data-source>
</persistence-unit>
</persistence>
Beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="annotated">
</beans>
weblogic.xml
<?xml version='1.0' encoding='UTF-8'?>
<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-
app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
http://xmlns.oracle.com/weblogic/weblogic-web-app/1.9/weblogic-web-app.xsd">
<context-root>/PublicAPI/</context-root>
WebService
#ApplicationPath("")
#Path("inventory/")
#Api(value = "Engineering Public API")
#RequestScoped
public class SsmcResource {
#Inject
private SsmcListProcedure ssmcListProcedure;
#POST
#Path("GetSSMCList")
#Produces(MediaType.APPLICATION_JSON)
public SsmcResponse getSSMCList(SsmcRequest ssmcRequest)
{
SsmcResponse response = null;
response = new SsmcResponse();
SsmcList ssmc = ssmcRequest.getSsmc();
CallerStatus callerStatus = ssmcRequest.getCallerStatus();
InitializeCallerStatus(callerStatus);
response.setSsmc(ssmcListProcedure.getSSMCList(ssmc.getSeries(), ssmc.getStyle(), ssmc.getMaterial(), ssmc.getColor()));
return response;
}
}
JPA Class:
#Dependent
#Default
public class SsmcListProcedure implements SsmcDAO {
#PersistenceContext(unitName = "DB")
private EntityManager em;
#Override
public List<SsmcList> getSSMCList(String seriesInd, String styleInd, String materialInd, String colorInd)
{
Query q = em.createNamedStoredProcedureQuery("SsmcList");
q.setParameter("p_series_ind", seriesInd);
q.setParameter("p_style_ind", styleInd);
q.setParameter("p_material_ind", materialInd);
q.setParameter("p_color_ind", colorInd);
return (List<SsmcList>) q.getResultList();
}
}
After redeploying, I receive the following errors in the logs when sending a POST request:
WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 3
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl
This looks like bug that already has a patch.
(JAX-RS + CDI).
check at support oracle.
I have a database with multiples schemas so I have a persistence.xml file with multiples <persistence-unit /> (named 01, 02, ...).
Problematic :
I want to create an EntityManager dynamically function of some user criteria.
I have tested 2 cases.
First case : basically, I tested this code (inside stateless EJB) :
String criteria = "01";
EntityManagerFactory emf = Persistence.createEntityManagerFactory(criteria);
EntityManager em = emf.createEntityManager();
Joueur joueur = new Joueur(); // Joueur is an Entity
joueur.setPseudo("olivier");
em.persist(joueur);
but I received exception :
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERREUR: la transaction est annulée, les commandes sont ignorées jusqu'à la fin du bloc
de la transaction
I thought, (with help of some Stackoverflow posts), that my EntityManager wasn't "linked" to my transaction context due to the fact it wasn't injected by container.
Second case : thus, I used injection :
#PersistenceContext(unitName="00")
private EntityManager em00;
#PersistenceContext(unitName="01")
private EntityManager em01;
Code in my function :
String criteria = "01";
EntityManager em = getEm(criteria);
...
and getEm() method :
private EntityManager getEm(String criteria){
if (criteria == "00")
return em00;
else if (criteria == "01")
return em01;
return null;
}
No problem, it's work but I have to inject as many EntityManagers that I have persistence-unit.
What will be the cost if I have 50 schemas...?
Is there a way to really manage entities managers dynamically ? (1 EntityManger only)
If I have to create 1 EntityManager per schema even if I don't use it, how can I improve my code to consume the least amount of resources possible ?
Thank you for advices and feedbacks
EDIT :
My configurations files :
Persistence.xml :
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="00" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/sim/00</jta-data-source>
<mapping-file>orm_00_beta.xml</mapping-file>
<class>com.sim.entities.Joueur</class>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables" />
</properties>
</persistence-unit>
<persistence-unit name="01" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/sim/01</jta-data-source>
<mapping-file>orm_01_beta2.xml</mapping-file>
<class>com.sim.entities.Joueur</class>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables" />
</properties>
</persistence-unit>
</persistence>
orm_00_beta.xml :
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
version="2.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>beta</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
orm_01_beta2.xml :
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
version="2.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>beta2</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
You need to set the "eclipselink.target-server" to the application server you are using when using application managed persistence units (some servers set this automatically then using container managed persistence units). Then the EntityManager will bind with the JTA transaction that is active when it is created. If you create the EntityManager before the start of the JTA transaction then you can use joinTransaction().
If you still have issues, include the server you are using, and the full exception stack trace.
If you have a lot of schemas, you could consider using EclipseLink multi-tenant support, which allows each tenant to have their own schema.
http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm#BABEGBIJ
Usually you don't have 50 schemas. I would not worry about the cost of injections, as usually EJB container has a pool of already opened connections which are ready to be injected. So the overhead is really small.
AFAIK, JPA does not allow dynamic entity managers.
If you care about resources, I would suggest to avoid using EclipseLink (I had really bad experience with EclipseLink + EJBs)
To optimize things a bit I would try to use factory pattern here. Create a Bean which will serve you EntityManagers. Instead of injecting several PersistenceContext you will have one injection with a method like:
EntityManager getEntityManager(String schemaId) {...}
Another option is to move all injections to an AbstractBean. All other beans inherit from the AbstractBean.
I'm writing a little web-interface for a database I created. The database access is done through Hibernate, but it also uses Spring for injecting instances of DAO's (which in turn have a SessionFactory injected). I test the web-interface on an embedded Jetty server. Everything works fine when used independently: I can get stuff out of the database from the database project, I can run a webpage using Wicket on the Jetty server, I even managed to get Spring working for the WicketTester, which was a bit of a pain in the ass. But now when I try to get something out of the database (by clicking some button on the webpage), I get an error saying:
java.lang.NullPointerException
at nl.ru.cmbi.pdbeter.core.controller.DAO.GenericDAO.getCurrentSession(GenericDAO.java:37)
Somehow the sessionFactory that should have been injected in the DAO wasn't injected. I defined the DAO bean in applicationContext.xml of the Wicket module, but I assumed that as soon as it would see the #Autowired of the SessionFactory it would look in the spring.xml file of thát project, but apparently it doesn't. I'll put some code below to show the individual parts at work.
The WicketApplication:
#Service
public class WicketApplication extends WebApplication {
#SpringBean
private IPDBEntryDAO pdbEntryDAO;
public IPDBEntryDAO getPdbEntryDAO() {
return pdbEntryDAO;
}
public void setPdbEntryDAO(IPDBEntryDAO pdbEntryDAO) {
this.pdbEntryDAO = pdbEntryDAO;
}
/**
* #see org.apache.wicket.Application#getHomePage()
*/
#Override
public Class<HomePage> getHomePage() {
return HomePage.class;
}
/**
* #see org.apache.wicket.Application#init()
*/
#Override
public void init() {
super.init();
new ClassPathXmlApplicationContext("applicationContext.xml").getAutowireCapableBeanFactory().autowireBean(this);
}
public void setupInjector() {
getComponentInstantiationListeners().add(new SpringComponentInjector(this));
}
}
The class which starts the embedded Jetty server (copied from the Wicket quickstart):
public class Start {
public static void main(String[] args) throws Exception {
int timeout = (int) Duration.ONE_HOUR.getMilliseconds();
Server server = new Server();
SocketConnector connector = new SocketConnector();
// Set some timeout options to make debugging easier.
connector.setMaxIdleTime(timeout);
connector.setSoLingerTime(-1);
connector.setPort(8080);
server.addConnector(connector);
// check if a keystore for a SSL certificate is available, and
// if so, start a SSL connector on port 8443. By default, the
// quickstart comes with a Apache Wicket Quickstart Certificate
// that expires about half way september 2021. Do not use this
// certificate anywhere important as the passwords are available
// in the source.
Resource keystore = Resource.newClassPathResource("/keystore");
if (keystore != null && keystore.exists()) {
connector.setConfidentialPort(8443);
SslContextFactory factory = new SslContextFactory();
factory.setKeyStoreResource(keystore);
factory.setKeyStorePassword("wicket");
factory.setTrustStoreResource(keystore);
factory.setKeyManagerPassword("wicket");
SslSocketConnector sslConnector = new SslSocketConnector(factory);
sslConnector.setMaxIdleTime(timeout);
sslConnector.setPort(8443);
sslConnector.setAcceptors(4);
server.addConnector(sslConnector);
System.out.println("SSL access to the quickstart has been enabled on port 8443");
System.out.println("You can access the application using SSL on https://localhost:8443");
System.out.println();
}
WebAppContext bb = new WebAppContext();
bb.setServer(server);
bb.setContextPath("/");
bb.setWar("src/main/webapp");
// START JMX SERVER
// MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
// MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer);
// server.getContainer().addEventListener(mBeanContainer);
// mBeanContainer.start();
server.setHandler(bb);
try {
System.out.println(">>> STARTING EMBEDDED JETTY SERVER, PRESS ANY KEY TO STOP");
server.start();
System.in.read();
System.out.println(">>> STOPPING EMBEDDED JETTY SERVER");
server.stop();
server.join();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
The web.xml file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>web-interface</display-name>
<!--
There are three means to configure Wickets configuration mode and they
are tested in the order given.
1) A system property: -Dwicket.configuration
2) servlet specific <init-param>
3) context specific <context-param>
The value might be either "development" (reloading when templates change) or
"deployment". If no configuration is found, "development" is the default. -->
<filter>
<filter-name>wicket.web-interface</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>nl.ru.cmbi.pdbeter.WicketApplication</param-value>
</init-param>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
<init-param>
<param-name>applicationBean</param-name>
<param-value>wicketApplication</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>wicket.web-interface</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- The SpringWebApplicationFactory will need access to a Spring Application context, configured like this... -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
The applicationContext.xml file:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!--
<context:component-scan base-package="nl.ru.cmbi.pdbeter" />
-->
<!-- setup wicket application -->
<bean id="wicketApplication" class="nl.ru.cmbi.pdbeter.WicketApplication">
<property name="pdbEntryDAO" ref="pdbEntryDAO"/>
</bean>
<bean id="pdbEntryDAO" class="nl.ru.cmbi.pdbeter.core.controller.DAO.PDBEntryDAO" />
</beans>
Part of the DAO class from the database module:
public class GenericDAO<I> implements IGenericDAO<I> {
private Class<I> persistentClass;
#Autowired
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public GenericDAO() {
persistentClass = (Class<I>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
protected Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
The spring.xml file used by the database module:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<context:component-scan base-package="nl.ru.cmbi.pdbeter" />
<!-- Transaction Manager -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
<!-- Session Factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="hibernate.cfg.xml" />
<property name="packagesToScan" value="nl.ru.cmbi.pdbeter.core.model.domain" />
</bean>
</beans>
Sorry for posting so much code, but I think I might let important stuff out if I don't.
Does anyone know how to make sure everything gets injected, both for the Wicket module as for the database module?
I'm just starting with Spring MVC trying to create a new project, and came accross an issue for which no manual or tutorial seems to help...
I have set up a simple application with no logic, just trying to get Spring configured properly. The controller just returns the name of a view to be displayed, but the view resolver is not rendering the jsp, and returning a 404 error....
Any help is greatly appreciated.
My web.xml is:
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>openstats</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>openstats</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<display-name>OpenStats API Server</display-name>
</web-app>
An my openstats-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<context:component-scan base-package="org.openstats.api.controller"/>
<!-- Enable to request mappings PER METHOD -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<!-- Enable annotated POJO #Controller -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<!-- Define the view resolver to use jsp files within the jsp folder -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>
<property name="prefix"><value>/jsp/</value></property>
<property name="suffix"><value>.jsp</value></property>
</bean>
</beans>
The controller itself has no logic whatsoever, it's simply:
#Controller
public class ProductController {
#RequestMapping(value = "/products.do", method = RequestMethod.GET)
public ModelAndView listProducts(HttpServletRequest request) {
ModelAndView model = new ModelAndView("index");
return model;
}
}
The controller is reached, the issue is when attempting to render...
I set up log4j in debug, and this is part of what I get:
02:08:19,702 DEBUG
DispatcherServlet:1094 - Testing handler adapter
[org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#397b6074]
02:08:19,803 DEBUG
HandlerMethodInvoker:134 - Invoking
request handler method: public org.springframework.web.servlet.ModelAndView
org.openstats.api.controller.ProductController.listProducts(javax.servlet.http.HttpServletRequest)
02:08:19,833 DEBUG
DefaultListableBeanFactory:1367 -
Invoking afterPropertiesSet() on bean
with name 'index' 02:08:19,876 DEBUG
InternalResourceViewResolver:81 -
Cached view [index] 02:08:19,877 DEBUG
DispatcherServlet:1181 - Rendering
view
[org.springframework.web.servlet.view.JstlView:
name 'index'; URL [/jsp/index.jsp]] in
DispatcherServlet with name
'openstats' 02:08:19,877 DEBUG
JstlView:240 - Rendering view with
name 'index' with model {} and static
attributes {} 02:08:19,923 DEBUG
JstlView:234 - Forwarding to resource
[/jsp/index.jsp] in
InternalResourceView 'index'
02:08:19,926 DEBUG
DispatcherServlet:955 -
DispatcherServlet with name
'openstats' determining Last-Modified
value for [/api-server/jsp/index.jsp]
02:08:19,927 DEBUG
DispatcherServlet:1054 - Testing
handler map
[org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#440c4cee]
in DispatcherServlet with name
'openstats' 02:08:19,928 DEBUG
DefaultAnnotationHandlerMapping:179 -
No handler mapping found for
[/jsp/index.jsp] 02:08:19,929 DEBUG
DispatcherServlet:962 - No handler
found in getLastModified 02:08:19,937
DEBUG DispatcherServlet:781 -
DispatcherServlet with name
'openstats' processing request for
[/api-server/jsp/index.jsp]
02:08:19,938 DEBUG
DispatcherServlet:843 - Bound request
context to thread: GET
/api-server/products.do HTTP/1.1
My jsp folder is right within "webapp" and the index.jsp file exists.
Thanks in advance.
I do have the same problem with Spring 3.x.
Any progress so far?
EDIT:
I figured it out myself :-) I used the following servletmapping:
<servlet-mapping>
<servlet-name>spring-frontcontroller</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Editing the url-pattern to e.g. *.do fixes the problem of not rendering the JSP.
But this leaves the question how this is possible with your url-pattern.
Does your web.xml define index.jsp in the welcome-file-list, if so it may be getting overridden. Try changing the jsp name to products.jsp.
e.g.
#Controller
public class ProductController {
#RequestMapping(value = "/products.do", method = RequestMethod.GET)
public String handleRequest() {
return "products";
}
}
doesn't your .jsp and your .do conflict? since a file cannot end with both .jsp and .do .. therefore it will never resolve... so you should get rid of .jsp or change your url pattern to /*
Changing
import org.springframework.web.servlet.ModelAndView;
by
import org.springframework.web.portlet.ModelAndView;
Works in my case.
I am trying to create an application using spring mvc and hibenate. I have been seeing the exception failed to lazily initialize a collection of role for nearly two days now :( The application runs fine if I eager load the collections. But I don't want it that way.
I tried implementing OpenSessionInViewFilter in web.xml but still the error persisted. I tried to extend OpenSessionInViewFilter and use my own filter, even now the problem remains unsolved. Here is the filter I implemented
public class HibernateFilter extends OpenSessionInViewFilter {
#Override
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
Session session = super.getSession(sessionFactory);
session.setFlushMode(FlushMode.AUTO);
return session;
}
#Override
protected void closeSession(Session session, SessionFactory sessionFactory) {
try {
if (session != null && session.isOpen() && session.isConnected()) {
try {
session.flush();
} catch (HibernateException e) {
throw new CleanupFailureDataAccessException("Failed to flush session before close: " + e.getMessage(), e);
} catch (Exception e) {
}
}
} finally {
super.closeSession(session, sessionFactory);
}
}
}
I ran the application in debug mode. I find the session to be not null, and the closeSession gets invoked only after it passes through the controller code. But still if I try to fetch a collection in the controller when the session is open it fails :( Here is my web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/blog-servlet.xml</param-value>
</context-param>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
core.HibernateFilter
</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>mySessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>blog</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>blog</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
What is going wrong?
As #sfussenegger mentioned...I am using sessions to identify the current user. This is my controller code:
#RequestMapping("/show.htm")
public String show(ModelMap model, HttpSession session) {
User u = (User) session.getAttribute("currentUser");
model.addAttribute("user", u);
if (u.getBlogs() != null) {
List<Blog> blogs = new ArrayList<Blog>(u.getBlogs());
model.addAttribute("myBlogs", blogs);
}
return "show";
}
and my jsp iterates over the MYblogs I collected in the model
My controller code:
Integer uid = (Integer) session.getAttribute("currentUser");
User user = getUserDao().findById(uid);
model.addAttribute("user", user);
if (user.getBlogs() != null) {
List<Blog> blogs = new ArrayList<Blog>(user.getBlogs()); //fails here
model.addAttribute("myBlogs", blogs);
}
return "show";
}
exception raised:
StandardWrapperValve[try-blog]: PWC1406: Servlet.service() for servlet try-blog threw exception
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ValueObjects.User.blogs, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
at org.hibernate.collection.PersistentSet.toArray(PersistentSet.java:194)
at java.util.ArrayList.<init>(ArrayList.java:131)
at Controllers.UserController.show(UserController.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:421)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:136)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:326)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:313)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:427)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:333)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:313)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:287)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:218)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:94)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:98)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:222)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:166)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:288)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:647)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:579)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:831)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:263)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:214)
at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265)
at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)
Dick is correct, controller class might be doing something funny.
Another point is make sure you have all the required jar in your classpath such as cglib or javaassist.
It might be easier to use springs openSessionInViewInterceptor instead of OpenSessionInViewFilter (since you are already using spring).
simply add the following on your blog-servlet.xml config (you can of course split this to multiple files)
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors"><list>
<ref bean="openSessionInViewInterceptor" />
</list></property>
</bean>
<bean id="openSessionInViewInterceptor" class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor">
<property name="entityManagerFactory"><ref local="entityManagerFactory"/></property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="ha-admin" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="ORACLE" p:showSql="true" />
</property>
<property name="jpaPropertyMap">
<props>
<!-- Enable Hibernate statistics generation
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">/ehcache.xml</prop>
<prop key="hibernate.generate_statistics">true</prop>
-->
</props>
</property>
</bean>
You need to add datasource on the configuration file and remove hibernateFilter from your web.xml.
Most likely you are using detached objects, i.e. object that have been loaded in a different session than the one created by your OpenSessionInViewFilter. This might happen when you store objects in the session and access them from a subsequent request. Is this possible?
Edit:
I'd discourage keeping the User object in the session. Instead, only keep the id and fetch the User object from DB each time it's needed. Hence, instead of your current approach, you should use something like this
User getUserFromSession(HttpSession session) {
Integer userId = (Integer) session.getAttribute("currentUser");
return userId != null ? getObjectById(User.class, userId) : null;
}
Note that fetching an object by id is insanely fast, especially if you've configured Hibernate's second level cache to store User object - so forget about any performance considerations. The main advantage though is that you don't have to deal with detached objects anymore. Detached objects are evil and nobody likes them! ;)
And as #skaffman mentioned, go back to the default OpenSessionInViewFilter as your implementation obviously won't solve your problem.
Hmmm, probably you are not going to change your ORM at this stage - but it is a nice reminder of why "Session-less" ORM's are interesting.
e.g. Ebean ORM ... no sessions, lazy loading just works (no filter required) - means you never hit this issue.
Just an idea: for me it helped to change the order of my filters. I had a url rewrite filter and the order with the session filter was important.
Just a thought...
If your code is failing in the controller, then the Filter is a red herring. Your Hibernate session should still be open at this point, filter or no filter.
Could you post your DAO code and the associated config?
You said that your application runs fine when you eagerly load the collection object.
Since you are using user object from the httpsession from another request, you might have to reattach the user object using refresh or update.
does the following code work?
User u = (User) session.getAttribute("currentUser");
User newUser = service.getUser(u.getUserId);
System.out.println(newUser.getBlogs());
And see if this helps. could you also list the jar files in your classpath.
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value> <!-- or false -->
</init-param>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>