Hibernate Lazy Loading with @LazyToOne (LazyToOneOption.NO_PROXY)
I have an application running Hibernate 4.2.21 on JBoss AS 7.2
We currently have several @OneToOne links that, due to the known limitations of lazy loading, will always receive from the back.
To enable Lazy loading for reverse relationships, I am trying to enable build time bytecode instrumentation.
Here's what I've done so far ...
1) Activate the appliance with maven-antrun-plugin
(I tried the hibernate-enhance-maven-plugin and couldn't get it to work, but that's for another question), now I get the following maven output in the build log:
[INFO] --- maven-antrun-plugin:1.7:run (Instrument domain classes) @ MyApp-entities ---
[INFO] Executing tasks
instrument:
[instrument] starting instrumentation
[INFO] Executed tasks
2) Next, I annotated all @OneToOne relationships like this:
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "client", optional=false)
@LazyToOne(LazyToOneOption.NO_PROXY)
public ClientPrefs getClientPrefs() {
return clientPrefs;
}
public void setClientPrefs(ClientPrefs clientPrefs) {
this.clientPrefs = clientPrefs;
}
3) Then I add implement FieldHandled
@Entity to the classes along with the private field and getter and setter:
private FieldHandler fieldHandler;
success ... I am now getting the following output in the deployment log:
15:54:09,720 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 56) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.Session
15:54:09,730 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 57) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.Session
15:54:09,969 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 56) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.Client
15:54:09,970 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 57) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.Client
15:54:09,999 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 56) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.Country
15:54:10,003 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 57) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.Country
15:54:10,054 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 56) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.Pool
15:54:10,054 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 57) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.Pool
15:54:10,569 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 56) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.User
15:54:10,624 INFO [org.hibernate.tuple.entity.EntityMetamodel] (ServerService Thread Pool -- 57) HHH000157: Lazy property fetching available for: uk.co.myapp.entities.User
Now the relationships don't load anymore ... but they are not lazy either, they just return zero.
I tried to remove the interface FieldHandled
and FieldHandler
of the Entity, because I was not sure it was necessary, then I no longer get the message 'HHH000157: Lazy property fetching available for:'
when you run, and he returns to the active loading by default.
Am I missing something? There is no explicit information in the hibernation docs on how to actually configure this.
EDIT: Added Ant task config as per the comments:
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>process-classes</phase>
<id>Instrument domain classes</id>
<configuration>
<target name="instrument">
<taskdef name="instrument"
classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
<classpath>
<path refid="maven.dependency.classpath" />
<path refid="maven.plugin.classpath" />
</classpath>
</taskdef>
<instrument verbose="true">
<fileset dir="${project.build.outputDirectory}">
<include name="MyApp-entities/co/uk/myapp/entities/*.class" />
</fileset>
</instrument>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.21.Final</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.1-GA</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
source to share
As usual it was a configuration issue, it seems that the ant launch plugin should be pointing to the exact directory containing the entities, not one of the parent directories
This worked for me ...
<instrument verbose="true">
<fileset dir="${project.build.directory}/classes/uk/co/myapp/entities">
<include name="*.class" />
</fileset>
</instrument>
source to share
@LazyToOne(LazyToOneOption.NO_PROXY)
required <property name="hibernate.ejb.use_class_enhancer" value="true"/>
in your persistance.xml
Lazy, return the real object loaded when the link was requested ( Bytecode enhancement is required for this option, fallback to PROXY if class is not extended. ). This option should be avoided if you cannot afford to use proxies
source to share
You have to fake a one-to-many relationship. This will work because lazy loading a collection is much easier than lazy loading a single nullable property, but this solution is usually very inconvenient if you are using complex JPQL / HQL queries.
Another way is to use build-time bytecode instrumentation. For more details, please read the Hibernate documentation: 19.1.7. Using lazy fetching of properties. Remember, in this case, you must add the @LazyToOne (LazyToOneOption.NO_PROXY) annotation in a one-to-one relationship to make it lazy. Setting fetch to LAZY is not enough.
The last solution is to use runtime bytecode instrumentation, but it will only work for those using Hibernate as their JPA provider in a fully functional JEE environment (in this case setting "hibernate.ejb.use_class_enhancer" to "true "should help: Entity Manager Configuration) or use Hibernate with Spring configured to do runtime weaving (this can be difficult to do on some older application servers). In this case, the @LazyToOne (LazyToOneOption.NO_PROXY) annotation is also required.
source to share