???When you     start a JPA client     application, tutorials such as this     one tell you to use this mysterious incantation on the command     line:

java -javaagent:toplink-essentials-agent.jar client.Client

What is the reason behind that? Go to the GlassFish     forum and search for javaagent. You'll get lots of confused queries.     (Ok, most of them are mine.) The gist of the friendly advice that I got     seemed to be that the toplink-essentials-agent.jar file was required for     lazy loading.


Lazy loading means that you can fetch an object from a database without     also fetching all of its dependent objects. Here is the canonical     example:


In a multiple-choice testing application, a Question has a     number of choices:

public class Question implements Serializable {
    private int id;
    private Collection<Choice> choices;
    . . .
    public Collection<Choice> getChoices() {
        return choices;

Now let's say we load a Question object from the database.     Should all choices be loaded as well? And what about the objects that are     related to Choice objects? That can be dangerous--suppose a     Choice remembers all the questions that contain it? Clearly,     something has to give, or we pull out a potentially huge transitive     closure with every query.


That's where lazy loading comes in. You can mark relationships so that     they are fetched lazily. By default, collections are always fetched     lazily. For example, consider this code:

Question q = em.find(Question.class, id);

It prints

{IndirectList: not instantiated}
elvis.entity.Choice[id=1,text=run anywhere]

Clearly, our collection isn't a humble array list. Indeed, calling     q.getChoices().getClass() reveals that it is a     oracle.toplink.essentials.indirection.IndirectList.


Ok, so I tried omitting -javaagent. What would happen to my lazy     collection? Would it be eagerly fetched? Would my keyboard melt into a     puddle of plastic if I accessed it? To my surprise, nothing special     happened. The output was exactly the same. What, if anything, did the     agent do?


???I     finally figured it out, thanks to reading this     article very carefully. You need -javaagent for one specific     purpose, to lazily load one-to-one and many-to-one relationships.     (If you knew this and you read this far, I am sorry to have wasted your     time. This blog entry is for Elvis, not Einstein.)


We had a one-to-many relationship, so the agent didn't care. Let's add     a lazily fetched one-to-one relationship:

public class Question implements Serializable {
    . . .
    private Choice answer;

    public Choice getAnswer() {
        return answer;
    . . .
    public String toString() {
        return getClass().getName() + "[id=" + id 
                + ",answer=" + answer"]";

Here we need to specify the fetch type since one-to-one relationship     are eagerly fetched by default.


Now we'll be able to tell the difference between running with     -javaagent and without.

Question q = em.find(Question.class, id);
With -javaagentWithout -javaagent
elvis.entity.Question[id=3,answer=null] elvis.entity.Choice[id=1,text=run anywhere]elvis.entity.Question[id=3,answer=elvis.entity.Choice[id=1,text=run anywhere] elvis.entity.Choice[id=1,text=run anywhere]

Both outputs are interesting.


???With     -javaagent, the answer instance field is null, but the     getAnswer method doesn't simply return the instance field (even     though our code says it does). The agent intercepted the loading of the     Question class and edited the bytecodes of the getAnswer     method so that it fetches the result. (This process of on-the-fly bytecode     modification is called "weaving" by the cognoscenti.)


Without -javaagent, lazy fetching has been disabled.


Why was the agent necessary? With the Collection<Choice>     field, the persistence provider can simply set an object of a class that     implements the Coll ection interface and that does the lazy     loading. There is no need to modify the bytecodes of the class. But one     can't do that with a single object. The Choice field must be set     to a Choice object (or to null), and the getter must be     modified. Mystery solved.


Unfortunately, I haven't yet found a way to actually see the modified     bytecodes, but if you set a breakpoint in the debugger and inspect the     Question object in the debugger, you can see a field that was     added to the class:




???Here     is the executive summary in terms that Elvis     can understand:

  • -javaagent:toplink-essentials-agent.jar is only useful when       you have one-to-one or many-to-one lazily fetched relationships.
  • If you omit it, your program will still work, but one-to-one and       many-to-one relationships will be fetched eagerly.