-
1. Re: avoid lazy-initialization exceptions
thomas.diesler Oct 22, 2007 4:52 AM (in response to mazz)Hi John,
please show us your SLSB and one of your entities. The JAXB default is to bind all public members. Please have a look at the JAXB spec for finer control. e.g. @XMLAccessType -
2. Re: avoid lazy-initialization exceptions
mazz Oct 25, 2007 9:09 AM (in response to mazz)The SLSB and entity is very simple. I've included the relevant SLSB interface definition and entity code below. The specific issue here is our login() method returns a Subject - and the Subject, although it has a Role relationship, we do not eagerly load it. The caller to login() never needs to know the role relationship data, and because of that, we increase performance by never asking the persistence layer to load that data before returning the Subject. While this is a very specific example, this design paradigm is all through our code. In fact, I have to believe this is a general problem everyone will have (since this is a big reason behind using LAZY vs. EAGER loading).
Not sure how to annotate the entity, because would that mean we can either ALWAYS or NEVER the data? But we know will we need it sometimes, but not always (i.e. sometimes a caller will call a different method that returns a Subject and that Subject WILL have the role information loaded and we thus WILL want that data go through the JAXB engine and returned to the web client).
I think we need some way to customize the way JAXB processes the returned entity or we need some annotation on a per-SLSB method. We are looking at @XMLJavaTypeAdapter as a possible way to do something, but we aren't sure yet until we try it out.@WebService @SOAPBinding(style = SOAPBinding.Style.DOCUMENT) public interface SubjectManagerRemote { @WebMethod Subject login(String user, String password);
@Entity @Table(name = "ON_SUBJECT") public class Subject implements Externalizable { ... @ManyToMany @JoinTable(name="ON_SUBJECT_ROLE_MAP", joinColumns={@JoinColumn(name="SUBJECT_ID")}, inverseJoinColumns={@JoinColumn(name="ROLE_ID")}) private java.util.Set<Role> roles; ... public java.util.Set<Role> getRoles() { return this.roles; }
-
3. Re: avoid lazy-initialization exceptions
ghinkle Oct 30, 2007 3:32 PM (in response to mazz)So I went and tried a few different ways to solve this. I implemented a XmlAdapter thinking I could inject some code into the marshalling process to null out the relationships before jaxb tries to do its thing.
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(org.jboss.on.domain.util.EJBXMLTypeAdaptor.class)
Doing this on the entity class and having the adapter just returned the cleaned-up object results in:javax.xml.bind.JAXBException: org.jboss.on.domain.auth.Subject nor any of its super class is known to this context
It doesn't look like many people understand XmlAdapters given what I've been able to find on Google. Any ideas how to just get access to the object, but still have JAXB do the marshalling?
I also tried putting the adapter on the relationship collection field that is lazy (and set the accessor type to FIELD), but it never ran my adapter in that case. Putting the adapter on the accessors didn't seem to get picked up. -
4. Re: avoid lazy-initialization exceptions
ghinkle Oct 30, 2007 10:53 PM (in response to mazz)I've now introduced an extended ServiceEndpointInvoker for the ejb3 calls. It's not perfect, but it allows me to get rid of all the PersistentCollections before soap and jaxb get their hands on my result objects. I'd still be interested if there's a better way though.
-
5. Re: avoid lazy-initialization exceptions
florian79 Jan 15, 2008 5:13 AM (in response to mazz)I have the same problems using JAX-WS and EJB3.
I am very interested in a solution for this problem.
ghinkle introduced an extended ServiceEndpointInvoker - is there any document how to do that or can you gif me a small intro please. -
6. Re: avoid lazy-initialization exceptions
florian79 Jan 23, 2008 12:49 PM (in response to mazz)really no solution?
-
7. Re: avoid lazy-initialization exceptions
cbax007 Feb 4, 2008 4:12 PM (in response to mazz)Has anyone come up with a better solution to this problem? Is there any way that in the XML marshaling code, the logic could check if the instance was a PersistentBag. If it was, and it had not yet been initialized, then serialize it as either null or an empty collection. Is there a way to make this happen?
-
8. Re: avoid lazy-initialization exceptions
euvitudo Feb 14, 2008 1:35 PM (in response to mazz)Even if you create another layer of DTOs, you'll still have to handle this case. I actually created such a layer and transformers to convert the Entities to DTOs (and vice-versa). The code has a relatively ugly solution, but it works.
The solution was to create a handler that catches all RuntimeExceptions when the transformation code iterates through to the collections. The handler looks for LazyInitializationException; if found, it logs the exception (but does not re-throw), if not found, it rethrows the (non-LIE) RuntimeException.
Yeah, ugly, but it works. The layer essentially removes external dependence on Hibernate. I suppose an alternative is to submit a bug report (or feature request?) to Hibernate. Alas, my hack gives me a (false?) sense of security until a Hibernate change causes the hack to break! YMMV and all. :) -
9. Re: avoid lazy-initialization exceptions
ghinkle Mar 5, 2008 5:58 PM (in response to mazz)Just sending along a link to our solution to this problem. Like I said, we don't like it, but it works.
This is the invoker:
http://viewvc.rhq-project.org/cgi-bin/viewvc.cgi/rhq/trunk/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvoker.java?revision=7&view=markup
And this is how we deploy it:
http://viewvc.rhq-project.org/cgi-bin/viewvc.cgi/rhq/trunk/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/EJB3SafeEndpointInvokerDeploymentAspect.java?revision=7&view=markup -
10. Re: avoid lazy-initialization exceptions
florian79 Jul 18, 2008 10:56 AM (in response to mazz)another "ugly" solution is the following:
instad of@XmlIDREF
use:@XmlJavaTypeAdapter(Entity2StringXMLAdapter.class)
and here is the implementation for the Adapter:public class Entity2StringXMLAdapter extends XmlAdapter<String,BasicEntity> { @Override public String marshal(final BasicEntity entityGot) throws Exception { String strValue = ""; try { strValue = entityGot.getName() + "(" + entityGot.getId() + ")"; } catch (LazyInitializationException e) { Long id = this.getEntityID(entityGot); if(id == null) id = new Long(-1); strValue = "lazy (" + id + ")"; } return strValue; } @Override public BasicEntity unmarshal(final String arg0) throws Exception { return null; } private Long getEntityID(final BasicEntity entityGot) { //dirty, but it works: //long duration = System.currentTimeMillis(); Long entityId = null; Class clazz = entityGot.getClass(); for(Field fieldHandler : clazz.getDeclaredFields()) { if(fieldHandler.getType().isAssignableFrom(javassist.util.proxy.MethodHandler.class) && fieldHandler.getName().equals("handler")) { try { fieldHandler.setAccessible(true); javassist.util.proxy.MethodHandler methodHandler = (javassist.util.proxy.MethodHandler) fieldHandler.get(entityGot); Field fieldID = AbstractLazyInitializer.class.getDeclaredField("id"); fieldID.setAccessible(true); entityId = (Long)fieldID.get(methodHandler); } catch (SecurityException e1) { e1.printStackTrace(); } catch (IllegalArgumentException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { e1.printStackTrace(); } catch (NoSuchFieldException e1) { System.out.println("======= THIS EXCEPTION DEPENDS ON A NEWER HIBERNATE VERSION!!!!!! ========"); e1.printStackTrace(); } break; } } return entityId; } }
BasicEntity is just Interface that is implemented by all my entities with the following methods:public Long getId(); public void setId(final Long idGot); public String getName(); public void setName(final String strNameGot);
-
11. Re: avoid lazy-initialization exceptions
lespoches Sep 25, 2009 11:26 AM (in response to mazz)I think the solution is to use @XmlAccessorFactory on Entity Bean and override default accessor !
But by default, Jboss do not exploit this annotation when creating JAXBContext and i can't find how to enable this Binding customization.
If anyone have an idea, help would be greatly appreciated
Jo -
12. Re: avoid lazy-initialization exceptions
asoldano Sep 29, 2009 1:37 PM (in response to mazz)You can provide your own JAXBContextFactory, take a look at org.jboss.ws.core.jaxws.CustomizableJAXBContextFactory for instance. This way you can setup the property you need in the context at creation.
Then make sure your context factory is loaded by the JBossWS ServiceLoader (basically you might want to either set your factory through a System property or add a org.jboss.ws.core.jaxws.JAXBContextFactory file in META-INF/services somewhere in the classpath). -
13. Re: avoid lazy-initialization exceptions
asoldano Sep 29, 2009 1:39 PM (in response to mazz)INteresting link to better follow this topic: http://blogs.sun.com/searls/entry/jaxb_custom_accessor_for_marshalling
-
14. Re: avoid lazy-initialization exceptions
lespoches Sep 30, 2009 3:53 AM (in response to mazz)"alessio.soldano@jboss.com" wrote:
You can provide your own JAXBContextFactory, take a look at org.jboss.ws.core.jaxws.CustomizableJAXBContextFactory for instance. This way you can setup the property you need in the context at creation.
Then make sure your context factory is loaded by the JBossWS ServiceLoader (basically you might want to either set your factory through a System property or add a org.jboss.ws.core.jaxws.JAXBContextFactory file in META-INF/services somewhere in the classpath).
Is there any sample on how to do that ?
Thanks a lot
Jonathan