<html>
<head>
<title>Using JAM to ease the transition to JSR175</title>

<link href="jam.css" rel="stylesheet" type="text/css" />


</style>
</head>

 
<body>

<h2>Using JAM to ease the transition to JSR175</h2>

<p>This document describes how <a href='/stuff/jamdocs'>JAM</a> can help you transition your metadata processing from javadoc tags to <a href='http://www.jcp.org/en/jsr/detail?id=175'>JSR175</a>.




<h3>Before you can require 1.5</h3>

<p>First, define a set of java beans that reflect what you expect your
175 annotation types to ultimately look like.  Ideally, they should also
directly reflect the javadoc tags you are currently using.  (If they can't,
you will have to do a little more work than this example describes - more
on that later).  Here is a simple example of such a bean:</p>

<pre>
  package foo.bar;

  /**
   * This is a 'fake' 175 annotation type that will work under 1.4.
   * It's just a generic java bean except that it should conform to
   * the 175 annotation conventions.  This means, among other things,
   * that the getters are not prefixed with 'get'.
   */
  public class MyAnnotation {
    public MyAnnotation() {} // a public no-arg constructor is required
    public int id() { return mId;}
    public void setId(int id) { mId = id; }
    private int mId = 13;
  }
</pre>

<p>In your client/tool code, when creating a JService, you need to specify 
a mapping between javadoc tag names and the qualified classnames of these
annotation beans.  For example:</p>

<pre>
  String[][] mappings = { "myannotation", "foo.bar.MyAnnotation" };
  JServiceFactory factory = JServiceFactory.getInstance();
  JServiceParams params = factory.createServiceParams();
  p.setJavadoc175Mappings(mappings);
  // (also do other stuff like include your .java files in the params)
  JService service = factory.createService(params);
</pre>

<p>For every javadoc tag encountered named 'myannotation,' and instance
of foo.bar.MyAnnotation will be created and populated by mapping the
tag attributes to the setters via reflection.  For example, if you
were using the JService created above to inspect the following source
file:

<pre>

  package foo.bar;

  /**
   * @myannotation id=42
   */  
  public class SomeClass {
  }
</pre>

<p>you could access the myannotation metadata as follows:</p>

<pre>

  JClass someClass = service.getClassLoader().load("foo.bar.SomeClass");
  JAnnotation jAnn = someClass.getAnnotation(MyAnnotation.class);
  MyAnnotation myAnnotation = (MyAnnotation)jAnn.getAnnotationObject();
  System.out.println(myAnnotation.getId());  // prints out 42

</pre>

<p>In this way, our access to the javadoc'ed metadata is strongly-typed,
structured, and isolated from the vagaries of javadoc parsing.  Better still,
the stage is now set for an easy transition to JSR175-style annotations, 
even though none of the code here requires JDK 1.5.</p>


<h3>After you can require 1.5</h3>

<p>Once you are sure that you can require JRE 1.5, and
that you no longer need to support javadoc tags, the transition away from
this mechanism is extremely simple.  Building on the previous example, 
the first step is to change MyAnnotation.java so that MyAnnotation is a
genuine 175 annotation:</p>

<pre>
  package foo.bar;

  /**
   * This is a genuine 175 annotation type.
   */
  public @interface MyAnnotation {
    int id() default 13;
  }
</pre>

<p>It is important to be sure that the package and class name remains the
same so that your client code does not need to change.  With this done,
it no longer is necessary to provide the javadoc-to-class mappings
as we did above when creating the JService.  Now, all we have to do is:</p>

<pre>
  JServiceFactory factory = JServiceFactory.getInstance();
  JServiceParams params = factory.createServiceParams();
  // (also do other stuff like include your .java files in the params)
  JService service = factory.createService(params);
</pre>

<p>That's it.  The beautiful part is that our client code does not
have to change at all:</p>

<pre>
  JClass someClass = service.getClassLoader().load("foo.bar.SomeClass");
  JAnnotation jAnn = someClass.getAnnotation(MyAnnotation.class);
  MyAnnotation myAnnotation = (MyAnnotation)jAnn.getAnnotationObject();
  System.out.println(myAnnotation.getId());  // still prints out 42
</pre>

<p>The MyAnnotation instance we get here is no longer the annnotation
bean we defined earlier - it's a real java.lang.annotation.Annotation.
But the beauty of it is that because we planned things out well, it
doesn't make any difference to the client code.</p>

<p>Again, though, it's important to note that once we get to this point,
nothing will work without JRE 1.5, and javadoc-style metadata will no
longer be recognized.</p>

</body>
</html>