Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

NetBeans 6: Matisse Updates

NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed.

Introduction to Groovy Part 3

In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.

Easier Custom Components with Swing Fuse

Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.

Benchmark Analysis: Guice vs Spring

Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
Replies: 1 - Pages: 1  
  Click to reply to this thread Reply

Annotations: Evolving an Annotation - Part 1

At 11:22 PM on Feb 16, 2005, R.J. Lorimer wrote:

Yesterday I posted a quick introduction to the built-in annotations for Java 5. If you didn't catch it, I recommend reading it first:

Annotations: Utilizing the Standard Annotations

Today I want to talk about the process of writing your own annotations. Annotations are a powerful tool for Java, and they represent a potentially major shift in the way that Java developers will be able to solve programming problems in the future. In addition to having some currently built-in behavior in the compiler, and also having the benefit of being a very concise way to document code, annotations can also currently be processed at runtime. In addition, as this Javalobby Discussion mentions, Java 6 includes JSR-269 - Pluggable Annotation Processing API which is designed to allow developers to control annotation processing at build time. We'll get to annotation processing in due time. To start, however, let's talk about annotation definitions themselves.

At its core, annotation definitions are little different than writing an interface definition. While there are some odd syntax choices, for the most part, it is a straightforward process for the average Java developer. Let's say that we want to create an annotation called ' Note '. The Note annotation will simply be a developer aid to know where there is code that need futher attention in the future. To start, simply create a Note.java file as you would for a class or interface, and then fill in the file like this:

package com.mypackage; // package definition is standard
 
// note the @ symbol
public @interface Note {
 
}

So far, aside from the @interface signature, this is a very simple and familiar format. I have a tendency to read the @interface signature as 'annotation interface'. Amazingly enough, this is a complete enough definition that we can begin using our annotation in our code:

package com.mypackage;
 
@Note
public class MyClass {
 
 @Note
 public MyClass() {
 
 }
}

Note that if your code is in a different package from the annotation, you will have to import it (or refer to the fully qualified name):

package com.myotherpackage;
 
import com.mypackage.Note;
 
@Note
public class MyOtherClass {
 
 @com.mypackage.Note // alternative fully qualified annotation reference.
 public MyOtherClass() {
 
 }
}

So, our annotation works, but obviously it's not entirely too useful. Defining what values/properties an annotation can contain is relatively familiar as well. The 'values' of an annotation are defined by creating interface-like methods. The name of the method corresponds directly to the name of the property. Each of these 'methods' must have a return type, and the return type must be one of these:

  • Primitives (bytes, ints, chars, shorts, longs, booleans, doubles, floats)
  • Strings
  • Class Objects
  • Enumerations
  • Annotations
  • Arrays containing any of the above

Finally - and this is the wierd one - default values can be supplied so that users of the annotation don't have to supply them in all cases - and that is done by trailing the method with the keyword default and then putting the default value for that property after ending with a semi-colon. This sounds complicated, but you'll see below how this works out.

Let's add an enumeration called Priority to our annotation (defining how important it is to deal with the Note), and a String value so that we can supply the note itself.

To start, let's define our Priority enum.

package com.mycompany;
 
public enum Priority { LOW, MEDIUM, HIGH }

Now let's put the priority and value into our annotation.

public @interface Note {
    String value();
    Priority priority() default Priority.MEDIUM;
}

Essentially that gives us two parameters to our annotation - a value, and a priority. The priority is given a default value which basically means it's not required to be entered when the annotation is used. Along the same lines, since we haven't supplied a default value for our value, outside developers will be required to supply a value for... value. If that wasn't desired (meaning we still wanted to allow a blank @Note annotation, we could use the default value of the empty string - "" - null is NOT allowed). Not having a default value means our original example will now be broken and won't compile - let's fix it!

package com.mypackage;
 
@Note("This Class isn't finished")
public class MyClass {
 
 @Note("This Constructor isn't finished")
 public MyClass() {
 
 }
}

Ok, now it compiles, but we aren't taking advantage of our new prioirty field. To take advantage of our priority (if the default isn't good enough), we can use named assignments to set each property:

package com.mypackage;
 
@Note(value="This Class isn't finished", priority=Priority.HIGH)
public class MyClass {
 
 @Note(value="This Constructor isn't finished", priority=Priority.LOW)
 public MyClass() {
 
 }
}

Note the use of the property-name=property-value syntax, and commas to separate the individual assignments. That's about it when it comes to values. The only other value that might cause confusion is arrays - and that was covered briefly in yesterday's tip . To reiterate quickly - arrays should be defined using { ..., ..., ... } syntax, but if only a single argument is required, the array syntax can be omitted (similar to Java 5 varargs).

Stay tuned as I continue down the path of defining this annotation. Tomorrow we'll cover annotation properties such as the retention policy, the appropriate targets, whether or not it contributes to documentation, and whether or not it is inherited.

1 . At 10:39 PM on Feb 17, 2005, Andy Tripp DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Annotations: Evolving an Annotation - Part 1

I've spent the last week using annotations, and I haven't
been able to find a way to do what I want to do.

I want to associate a text label with every field
in a class:

public class Person {
@Label("Name") String name;
@Label("Age") int age;
@Label("Date of Birth") Date dob;
}

And then I want to be able to look up the label
at runtime using reflection.

The problem is that I can't get a Field object for
a given field, so that I can call getAnnotation() on it.
I want to have a generic function that takes any
Object and looks up its Label:
public static String getAnnotation(Object o) {
???
}

I can call o.getClass().getDeclaringClass(), so if
"o" is the "age" field, I'll get back the "Person"
class. I can then loop through the "Person" class's
fields. But how to I know when I've hit the "age"
field? I can't do this:
Field[] fields = declaringClass.getDeclaredFields();
for (Field field: fields) {
Object fieldObject = field.get(o);
if (fieldObject.equals(o)) {
// this is our field!
}
}

that would work if the fields were all Objects, but
not if some of them are primitives.

I just don't see any way to do what I want to do.
That's a shame, too. It might make building GUIs
a lot easier.

Andy
Andy Tripp, CTO and Founder Jazillian - Legacy to 'natural' Java.

thread.rss_message