title: JAX-WS + Hibernate + JAXB: How to avoid LazyInitializationException during marshalling
body: <p>I have a JAX-WS application, which returns data objects, that were fetched from a Hibernate Database backend (Oracle 10g or Oracle 11g). I use javax.persistence.criteria.CriteriaQuery for that. It works fine, unless the object has dependencies, which should not be returned for some specific queries, e.g.:</p>
  
  <pre><code>@Immutable
  @Entity
  @Table(schema = "some_schema", name = "USER_VW")
  public class User implements Serializable {
  
    ...
  
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PRFL_ID")
    public Profile getProfile() {...}
  
    public void setProfile(Profile profile) {...}
  
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "SM_OTH_TP_ID")
    public SomeOtherType getSomeOtherType() {...}
  
    public void setSomeOtherType(SomeOtherType otherType) {...}
  
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "SM_DPND_ID)
    public SomeDependency getSomeDependency() {...}
  
    public void setSomeDependency(SomeDependency dependency) {...}
  
  ...
  }
  </code></pre>
  
  <p>Here is my criteria query:</p>
  
  <pre><code>CriteriaBuilder cb = entityManager.getCriteriaBuilder();
  CriteriaQuery&lt;User&gt; criteria = cb.createQuery(User.class);
  criteria.distinct(true);
  Root&lt;User&gt; user = criteria.from(User.class);
  Join&lt;User, Profile&gt; profileJoin = user.join("profile", JoinType.INNER);
  user.fetch("someOtherType", JoinType.LEFT);
  criteria.select(user);
  Predicate inPredicate = profileJoin.get("profileType").in(types);
  criteria.where(inPredicate);
  </code></pre>
  
  <p>NOTE: I don't fetch SomeDependency property. I don't want it to be returned.</p>
  
  <p>And here is the definition of the UserServiceResponse class:</p>
  
  <pre><code>@XmlRootElement(name = "UserServiceResponse", namespace = "...")
  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlType(name = "UserServiceResponse", namespace = "...")
  public class UserServiceResponse {
  
  @XmlElementWrapper(name = "users")
  @XmlElement(name = "user")
  private final Collection&lt;User&gt; users;
  
  ...
  </code></pre>
  
  <p>Then JAXB finds that the Hibernate Session has been closed. When it tries to marshall the response I get the following exception:</p>
  
  <pre><code>Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
      at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164) [hibernate-core-4.2.7.SP1-redhat-3.jar:4.2.7.SP1-redhat-3]
      at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285) [hibernate-core-4.2.7.SP1-redhat-3.jar:4.2.7.SP1-redhat-3]
      at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185) [hibernate-core-4.2.7.SP1-redhat-3.jar:4.2.7.SP1-redhat-3]
  
      at com.myproject.model.user.entity.SomeDependency_$$_jvsteec_98.getCode(SomeDependency_$$_jvsteec_98.java)
  ...
      at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494)
      at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323)
      at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:251)
      at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:74) [jboss-jaxb-api_2.2_spec-1.0.4.Final-redhat-2.jar:1.0.4.Final-redhat-2]
      at org.apache.cxf.jaxb.JAXBEncoderDecoder.writeObject(JAXBEncoderDecoder.java:612) [cxf-rt-databinding-jaxb-2.7.7.redhat-1.jar:2.7.7.redhat-1]
      at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:240) [cxf-rt-databinding-jaxb-2.7.7.redhat-1.jar:2.7.7.redhat-1]
      ... 32 more
  </code></pre>
  
  <p>It happens when marshaller tries to get value for the "code" property of SomeDependency class which is a HibernateProxy instance.</p>
  
  <p>The solution that I see for now is to add some kind of "filter" which checks during marshalling if the object is instance of HibernateProxy or not. If it is a HibernateProxy instance the filter handle it, if not, just leaves its default behavior.</p>
  
  <p>How can I do that? Using a XmlJavaTypeAdapter class? Or using com.sun.xml.internal.bind.v2.runtime.reflect.Accessor?</p>
  
  <p>If anyone can tell me any other way to solve my problem I would be appreciated.  </p>
  
  <p>NOTE: I'm reusing the same Hibernate code and POJOs, inside JAX-WS in other web-services and outside JAX-WS in other modules of the application, where lazy loading is an advantage.</p>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>I've tried using XmlJavaTypeAdapter but it didn't work for me. I created a new adapter - HibernateProxyAdapter which extends XmlJavaTypeAdapter. User entity is not the only POJO that I have, in fact, there are a lot of them. To ensure that the adapter is applied to all of them I added it on the package level.</p>
  
  <pre><code>@XmlJavaTypeAdapters(
      @XmlJavaTypeAdapter(value=HibernateProxyAdapter.class, type=HibernateProxy.class)
  )
  package com.myproject.model.entity;
  </code></pre>
  
  <p>Here is the adapter:</p>
  
  <pre><code>public class HibernateProxyAdapter extends XmlJavaTypeAdapter&lt;Object, Object&gt; {
  
      public Object unmarshal(Object v) throws Exception {
          return null; // there is no need to unmarshall HibernateProxy instances
      }
  
      public Object marshal(Object v) throws Exception {
          if (v != null) {
              if ( v instanceof HibernateProxy ) {
                  LazyInitializer lazyInitializer = ((HibernateProxy) v ).getHibernateLazyInitializer();
                  if (lazyInitializer.isUninitialized()) {
                      return null;
                  } else {
                      // do nothing for now
                  }
              } else if ( v instanceof PersistentCollection ) {
                  if(((PersistentCollection) v).wasInitialized()) {
                      // got an initialized collection
                  } else {
                      return null;
                  }
              }
          }
          return v;
      }
  }
  </code></pre>
  
  <p>Now i'm getting another exception:</p>
  
  <pre><code>Caused by: javax.xml.bind.JAXBException: class org.hibernate.collection.internal.PersistentSet nor any of its super class is known to this context.
      at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:588)
      at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:648)
      ... 57 more 
  </code></pre>
  
  <p>As I understand, this happens when it tries to marshal an initialized hibernate collection, e.g.: org.hibernate.collection.internal.PersistentSet. I don't get the reason... PersistentSet implements Set interface. I thought JAXB should know how to handle it. Any ideas?</p>
  
  <p><strong>UPDATE 2:</strong>
  I have also tried the second solution using Accessor class. Here is my accessor:</p>
  
  <pre><code>public class JAXBHibernateAccessor extends Accessor {
  
      private final Accessor accessor;
  
      protected JAXBHibernateAccessor(Accessor accessor) {
          super(accessor.getValueType());
          this.accessor = accessor;
      }
  
      @Override
      public Object get(Object bean) throws AccessorException {
          return Hibernate.isInitialized(bean) ? accessor.get(bean) : null;
      }
  
      @Override
      public void set(Object bean, Object value) throws AccessorException {
          accessor.set(bean, value);
      }
  }
  </code></pre>
  
  <p>AccessorFactory...</p>
  
  <pre><code>public class JAXBHibernateAccessorFactory implements AccessorFactory {
  
      private final AccessorFactory accessorFactory = AccessorFactoryImpl.getInstance();
  
      @Override
      public Accessor createFieldAccessor(Class bean, Field field, boolean readOnly) throws JAXBException {
          return new JAXBHibernateAccessor(accessorFactory.createFieldAccessor(bean, field, readOnly));
      }
  
     @Override
     public Accessor createPropertyAccessor(Class bean, Method getter, Method setter) throws JAXBException {
          return new JAXBHibernateAccessor(accessorFactory.createPropertyAccessor(bean, getter, setter));
     }
  }
  </code></pre>
  
  <p>package-info.java ...</p>
  
  <pre><code>@XmlAccessorFactory(JAXBHibernateAccessorFactory.class)
  package com.myproject.model.entity;
  </code></pre>
  
  <p>Now I need to enable custom AccessorFactory/Accessor support on the JAXB context. I tried adding custom JAXBContextFactory to the web service definition but it didn't work...</p>
  
  <pre><code>@WebService
  @UsesJAXBContext(JAXBHibernateContextFactory.class)
  public interface UserService {
  ...
  }
  </code></pre>
  
  <p>and here is my contextFactory</p>
  
  <pre><code>public class JAXBHibernateContextFactory implements JAXBContextFactory {
  
      @Override
      public JAXBRIContext createJAXBContext(@NotNull SEIModel seiModel, @NotNull List&lt;Class&gt; classes,
                                         @NotNull List&lt;TypeReference&gt; typeReferences) throws JAXBException {
          return ContextFactory.createContext(classes.toArray(new Class[classes.size()]), typeReferences,
              null, null, false, new RuntimeInlineAnnotationReader(), true, false, false);
      }
  }
  </code></pre>
  
  <p>I don't know why but createJAXBContext method is never invoked. Looks like @UsesJAXBContext annotation does nothing...</p>
  
  <p>Does anyone know how to make it work?
  Or how can I set the "com.sun.xml.bind.XmlAccessorFactory" JAXBContext property to true inside JAX-WS?  </p>
  
  <p>BTW, I forgot to mention, I deploy it to JBoss EAP 6.2.</p>