问题
I'm trying to implement a Hibernate session/transaction interceptor to avoid LazyInitializationException
on json results in Struts2, but I get this exception anyway:
245968 [http-8080-7] ERROR util.HibernateEndTransInterceptor - org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: java.lang.reflect.InvocationTargetException
org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: java.lang.reflect.InvocationTargetException
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:238)
at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:171)
at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:161)
at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:127)
at org.apache.struts2.json.JSONWriter.write(JSONWriter.java:95)
at org.apache.struts2.json.JSONUtil.serialize(JSONUtil.java:116)
at org.apache.struts2.json.JSONResult.createJSONString(JSONResult.java:196)
at org.apache.struts2.json.JSONResult.execute(JSONResult.java:170)
at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:374)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:278)
at util.HibernateEndTransInterceptor.intercept(HibernateEndTransInterceptor.java:55)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:236)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:236)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:190)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:90)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:243)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:192)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at util.HibernateBeginTransInterceptor.intercept(HibernateBeginTransInterceptor.java:32)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at util.LoginInterceptor.intercept(LoginInterceptor.java:36)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:511)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:831)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:652)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1203)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: java.lang.reflect.InvocationTargetException
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:238)
at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:171)
at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:161)
at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:127)
at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:363)
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:223)
... 73 more
Caused by: org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: java.lang.reflect.InvocationTargetException
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:238)
at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:171)
at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:161)
at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:127)
at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:363)
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:223)
... 78 more
Caused by: org.apache.struts2.json.JSONException: java.lang.reflect.InvocationTargetException
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:238)
at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:171)
at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:161)
at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:127)
at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:363)
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:223)
... 83 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:218)
... 88 more
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:272)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at com.lm.model.common.Language_$$_javassist_0.getName(Language_$$_javassist_0.java)
... 93 more
My Interceptor looks like this:
package util;
import java.util.Map;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import util.hibernate.HibernateUtil;
import com.lm.action.ActionsConstants;
import com.lm.action.user.Constants;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class HibernateEndTransInterceptor implements Interceptor, Constants, ActionsConstants {
private static final long serialVersionUID = -8734958511612355789L;
private static SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
private transient Logger log = Logger.getLogger(HibernateEndTransInterceptor.class);
private Session s=null;
private Transaction t=null;
@Override
public void destroy() {
}
@Override
public void init() {
}
@Override
public String intercept(final ActionInvocation invocation) throws Exception {
/*invocation.addPreResultListener(new PreResultListener() {
@Override
public void beforeResult(ActionInvocation arg0, String arg1) {
Map<String, ResultConfig> resultsMap = invocation.getProxy().getConfig().getResults();
//ResultConfig finalResultConfig = resultsMap.get(resultCode);
}
});*/
Map<String,Object> strutsSession = invocation.getInvocationContext().getSession();
String res=null;
try {
s=sessionFactory.openSession();
t = s.beginTransaction();
strutsSession.put("hibernateSession", s);
strutsSession.put("hibernateTransaction", t);
res=invocation.invoke();
t.commit();
} catch (Throwable t2) {
log.error(t2,t2);
try {
t.rollback();
} catch (Throwable t3) {
log.error(t3,t3);
}
} finally {
try {
s.close();
} catch (Throwable t) {
log.error(t,t);
}
strutsSession.remove("hibernateSession");
strutsSession.remove("hibernateTransaction");
}
return res;
}
}
This is not working, I'm getting LazyInitializationException
even before trans.commit()
and session.close();
回答1:
Do not reimplement the weel. If you need to implement the open session in view concept then use Hibernate Full Plugin. If you want to fix the LazyInitializationException
put FetchType.EAGER
on the collections.
回答2:
Ok, finally I've solved adding injection of generic DAO (with session and transaction) to a genericAction. This works for JSONResults & jsp's with lazy hibernate beans.
Thanks for contributions to "bmorris591" and "Roman C" (I don't want, even need, all this plugin).
I leave my examples, I hope I don't forget anything...
Interceptor configuration (struts.xml fragment):
<package name="lmp" extends="struts-default,json-default">
<interceptors>
<interceptor name="login" class="util.LoginInterceptor"/>
<interceptor name="hibernateSessionTransInjector" class="util.HibernateSessionTransInjectorInterceptor"/>
<interceptor-stack name="loggingStack">
<interceptor-ref name="login" />
<interceptor-ref name="defaultStack" />
<interceptor-ref name="hibernateSessionTransInjector"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="loggingStack"/>
<global-results>
<result name="login" type="redirectAction">login</result>
</global-results>
</package>
<package name="myAction" extends="lmp">
<action name="myAction" class="com.lmp.MyAction">
<result name="json" type="json">
<param name="ignoreHierarchy">false</param>
</result>
<result name="*">/jsp/myAction.jsp</result>
</action>
</package>
Interceptor implementation:
package util;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import util.hibernate.HibernateUtil;
import com.lm.action.ActionsConstants;
import com.lm.action.user.Constants;
import com.lm.dao.DAO;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class HibernateSessionTransInjectorInterceptor implements Interceptor, Constants, ActionsConstants {
private static final long serialVersionUID = -8734958511612355789L;
private static SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
private transient Logger log = Logger.getLogger(HibernateSessionTransInjectorInterceptor.class);
@Override
public void destroy() {
}
@Override
public void init() {
}
@Override
public String intercept(final ActionInvocation invocation) throws Exception {
String res=null;
DAO dao=null;
try {
Session s=sessionFactory.openSession();
dao = new DAO(s);
dao.beginTransaction();
**invocation.getStack().setValue("dao", dao, true);**
res=invocation.invoke();
boolean rollback=(Boolean)invocation.getStack().findValue("rollbackTransaction", Boolean.class);
if (rollback)
dao.rollBackTransaction();
if (!dao.getT().wasRolledBack())
dao.commitTransaction();
} catch (Throwable t2) {
log.error(t2,t2);
if (dao!=null)
try {
dao.rollBackTransaction();
} catch (Throwable t3) {
log.error(t3,t3);
}
} finally {
if (dao!=null)
try {
dao.finallyClose();
} catch (Throwable t) {
log.error(t,t);
}
}
return res;
}
}
UserDAO example:
public class UserDAO extends DAO {
[...]
public UserDAO(Session s) {
super(s);
}
[...]
}
GenericDAO example:
public class DAO {
protected static final transient Logger log = Logger.getLogger(DAO.class);
public static SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
public Session s = null;
public Transaction t = null;
public DAO(Session s) {
this.s=s;
}
public void beginTransaction(Transaction t) {
this.t=t;
}
private int exceptionErr=0;
public void beginTransaction() {
try {
t=s.beginTransaction();
} catch (Throwable t) {
log.error(t,t);
}
}
public void rollBackTransaction() {
if (t!=null && t.isActive())
t.rollback();
}
public void commitTransaction() {
if (t!=null && t.isActive())
t.commit();
}
public void finallyClose() {
if (t!=null && t.isActive())
t.rollback();
if (s!=null && s.isOpen())
s.close();
}
public Session getS() {
return s;
}
public void setS(Session s) {
this.s = s;
}
public Transaction getT() {
return t;
}
public void setT(Transaction t) {
this.t = t;
}
}
GenericAction:
public class GenericAction extends ActionSupport {
private DAO dao=null; //Interceptor injects here
public GenericAction() {
}
...
@JSON(deserialize=false, serialize=false)
public DAO getDao() {
return dao;
}
@JSON(deserialize=false, serialize=false)
public void setDao(DAO dao) {
this.dao = dao;
}
}
MyAction:
public class MyAction extends GenericAction {
public MyAction() {
}
@Override
public String execute() throws Exception {
super.execute();
UserDAO userDAO=new UserDAO(getDao().getS());
OtherDAO otherDAO=new OtherDAO(getDao().getS());
userDAO.loadUsers(...);
return SUCCESS;
}
}
回答3:
If this is a Struts2 interceptor this is absolutely not the way to implement it.
An application has a single instance of the interceptor for all requests so one request is setting the variable in the intercept
method then another is coming in and resetting them while the first is still processing. The first request then comes back on calls session.close()
on the second request's session.
Your interceptor should look more like this:
@Override
public String intercept(final ActionInvocation invocation) throws Exception {
final Map<String, Object> strutsSession = invocation.getInvocationContext().getSession();
String res = null;
Session s = null;
Transaction t = null;
try {
s = sessionFactory.openSession();
t = s.beginTransaction();
strutsSession.put("hibernateSession", s);
strutsSession.put("hibernateTransaction", t);
res = invocation.invoke();
t.commit();
} catch (Throwable t2) {
log.error(t2, t2);
t.rollback();
} finally {
s.close();
strutsSession.remove("hibernateSession");
strutsSession.remove("hibernateTransaction");
}
return res;
}
Notice all variables are local unless you want them to be shared across requests.
Also, it's best practice to extend AbstractInterceptor
so that you do not have all the empty methods that you have.
来源:https://stackoverflow.com/questions/15269786/struts-2-json-result-hibernate-lazyinitialization-how-to-deserialize-within-a