title: Enable no-proxy behaviour for all FetchType.LAZY non-collections by default in Hibernate
body: <p>When using standard JPA annotations, you can specify <code>FetchType.LAZY</code> on non-collection fields (i.e. <code>@ManyToOne</code> and <code>@OneToOne</code>). It seems Hibernate internally uses "proxy" fetching in this case. But proxy fetching has its problems with inheritance and I think it is better to use no-proxy fetching in combination with bytecode instrumentation. Unfortunately, Hibernate still requires you either to specify "no-proxy" in the <code>hbm</code>-file or to use the Hibernate-specific <code>@LazyToOne</code> annotation.</p>
  
  <p>My question is: does Hibernate support a configuration option to use a no-proxy fetch strategy for all non-collection fields, that are <code>FetchType.LAZY</code>?</p>
  
  <p>Here is what I need this for: I would like to use only JPA annotations in most cases on the one hand. On the other hand, I'd like to avoid issues with inheritance and lazy fields. And I don't like the idea of wrapping everything in interfaces, because I use DDD in my current project, so I think that no boilerplate garbage should exist in my domain model, only pure business logic.</p>
  
  <p>I have an idea of a poor workaround: by using bytecode modification, I add <code>@LazyToOne</code> annotation everywhere <code>@ManyToOne</code> appears. But I would prefer a built-in Hibernate feature, if exists.</p>
  
  <hr>
  
  <p>Here is (well known) issue with proxy fetching, to make things a bit clearer:</p>
  
  <pre><code>@Entity @DiscriminatorColumn("t") @DiscriminatorValue("")
  public abstract class A {
      @Id private Integer id;
  }
  
  @Entity @DiscriminatorValue("B")
  public abstract class B extends A {
  }
  
  @Entity @DiscriminatorValue("C")
  public abstract class C extends A {
  }
  
  @Entity public class D {
      @Id private Integer id;
      @ManyToOne(fetch = FetchType.LAZY) private A a;
      public A getA() {
          return a;
      }
  }
  </code></pre>
  
  <p>prepare:</p>
  
  <pre><code>D d = new D();
  C c = new C();
  d.setA(c);
  em.persist(d);
  </code></pre>
  
  <p>and fail assertion (in another EM, another transaction):</p>
  
  <pre><code>D d = em.createQuery("select d from D d", D.class).getSingleResult();
  List&lt;C&gt; cs = em.createQuery("select c from C c", C.class).getResultList();
  assert d.getA() instanceof C;
  assert d.getA() == cs.get(0);
  </code></pre>
  
  <p>Here's what I would do to fix the assertions above:</p>
  
  <pre><code>@Entity public class D {
      @Id private Integer id;
      @ManyToOne(fetch = FetchType.LAZY) @LazyToOne(LazyToOneOption.NO_PROXY)
      private A a;
      public A getA() {
          return a;
      }
  }
  </code></pre>
  
  <p>And I don't want the same thing to be enabled by default, without <code>@LazyToOne</code> annotation.</p>