Valery Silaev's Blog

if it ain't broken we'll break it

There is a well-defined naming convention in Java to start annotation names with an uppercase letter – same as for class/interface names. Though this naming convention is widely accepted, I think it’s a bit dogmatic. If you take a look at the list of Java-specific annotations in Scala you may see that both lowercase (like @cloneable or @throws) and uppercase (like @SerialVersionUID or @BeanProperty) forms are used. Personally, I tend to agree with decisions made by architects of the Scala’s standard library: some annotations are meta-data, for example javax.persistence.@Entity / javax.persistence.@Column or javax.xml.bind.annotation.@XmlElement / javax.xml.bind.annotation.@XmlAttribute; other ones look like a directive to processing tool or like a syntax extension. In addition, directive-like annotations typically have no extra parameters, so they are very similar to @-prefixed keywords. Hence, I think it would be more natural to write @override rather than @Override in Java — it’s a directive to compiler to check whether or not the method overrides/implements a method defined in a superclass/interface. Moreover, in some languages “override” is indeed a keyword, so it’s even more tempting to use all-lower-case variant.

The above should explain why lower-case annotation names where chosen for two annotations in Tascalate Javaflow: @continuable and @ccs. Both are directives to bytecode instrumentation tools, both have no extra parameters, and both looks like library-defined keywords:

public @continuable void execute() {
  ...
  final @ccs Runnable contRunnable = new MyContinuableRunnable(someArg);
  ...
}

What if you don’t agree with arguments above and would prefer to follow standard Java naming conventions for annotations? Not a problem at all with Tascalate Javaflow! There is a third annotation defined in the library – org.apache.commons.javaflow.api.ContinuableAnnotation – that allows you to define your own annotations instead of @continuable and @ccs. In fact, ContinuableAnnotation is a meta annotation and it may/should be applied only to other annotations. Here is how to define @ContinuableMethod annotation that you may use instead of @continuable in your code to strictly adhere to Java naming conventions:

package mycompany.myapp.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.apache.commons.javaflow.api.ContinuableAnnotation;

@Documented                       // optional
@Retention(RetentionPolicy.CLASS) // mandatory, may be RetentionPolicy.RUNTIME as well
@Target({ElementType.METHOD})     // mandatory, only methods are examined
@ContinuableAnnotation            // mandatory
public @interface ContinuableMethod {
}

The rules are:

  1. Your custom @ContinuableMethod annotation must be annotated with @ContinuableAnnotation (obviously)
  2. It must be an annotation applicable to methods – any other targets have no effect and will only confuse a user of your annotation class. However, sometimes you need to have other targets and it’s ok to define more – typical example is CDI interceptor binding annotations.
  3. It must have retention policy defined either as RetentionPolicy.CLASS or as RetentionPolicy.RUNTIME, SOURCE-level annotations are not saved into class bytes

Similar, you can re-define @ccs as @ContinuableTarget:

package mycompany.myapp.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.apache.commons.javaflow.api.ContinuableAnnotation;

// optional
@Documented
// mandatory, may be RetentionPolicy.RUNTIME as well
@Retention(RetentionPolicy.CLASS)
// mandatory, use exact syntax
@Target({ElementType.LOCAL_VARIABLE, ElementType.PARAMETER, ElementType.TYPE_USE})
// mandatory
@ContinuableAnnotation
public @interface ContinuableTarget {
}

The rules are similar to the method-level annotation except for @Target – please use exact syntax as above. In addition to regular variable/parameter targets you must declare ElementType.TYPE_USE (Java 8 feature) – otherwise annotation is not saved in a class bytecode.

No other customization is necessary: you may use your own annotations right away thanks to meta-annotation. By the way, there is another important use-case when ContinuableAnnotation may be useful in your code — stereotype annotations. Imaging, that your application has a method-level annotation @WorflowTask with it’s own duties. Moreover, all @WorkflowTask methods must be @continuable. To mark some business methods as workflow tasks you should use both annotations:

package mycompany.myapp.services;
import mycompany.myapp.annotations.WorkflowTask;
import org.apache.commons.javaflow.api.ContinuableAnnotation;

public class MyService {
  ...
  @WorkflowTask(timeout="3d",name="SomeTask")
  @continuable
  public int myBusinessMethod() { ... }
  ...
}

However, if you mark your @WorkflowTask annotation as @ContinuableAnnotation then you may use just one annotation in your code:

package mycompany.myapp.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.apache.commons.javaflow.api.ContinuableAnnotation;

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD})
@ContinuableAnnotation
public @interface WorkflowTask{
  public String name();
  public String timeout();
  ...
}

//=====

package mycompany.myapp.services;
import mycompany.myapp.annotations.WorkflowTask;

public class MyService {
  ...
  @WorkflowTask(timeout="3d",name="SomeTask")
  public int myBusinessMethod() { ... }
  ...
}

Now @WorkflowTask annotation is a stereotype that:

  • clearly defines specific business method role
  • captures this role at a conceptual level
  • encapsulates implementation details

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: