Introduction

SezPoz is a lightweight and easy-to-learn library that lets you perform modular service lookups. It provides some of the same capabilities as (for example) java.util.ServiceLoader, Eclipse extension points, and NetBeans Lookup and XML layers. However, SezPoz has some special advantages:

  1. The service registrations are made just using type-checked Java annotations. There are no configuration files to edit, and your Java IDE can show you registrations since they are simply usages of an annotation. On JDK 6 (or later), no special build or packaging steps are required (just javac); on JDK 5, you just need to run APT (with default arguments), instead of or in addition to javac for any sources which may contain indexable items. Looking up services just requires that you have a ClassLoader which can "see" all of the "modules" (as with ServiceLoader).

  2. You can register individual objects (values of static fields or methods) instead of whole classes.

  3. You can associate static metadata with each implementation, using regular annotation values. The caller can choose to inspect the metadata without loading the actual implementation object (as with Eclipse extension points).

(Why the name? SezPoz "says" the "position" of your services. It is also a "seznam poznámek".)

Sources and Binaries

Sources are in the form of Maven projects. To build:

mvn install

To try the demo application:

mvn -f demo/app/pom.xml exec:exec

Binaries, sources, and Javadoc can all be downloaded from the Maven repository.

For usage from Maven applications, add the java.net repository (details) and use the artifact net.java.sezpoz:sezpoz, for example:

<repositories>
  <repository>
    <id>java.net</id>
    <name>java.net</name>
    <url>http://download.java.net/maven/2/</url>
  </repository>
</repositories>
<dependencies>
  <dependency>
    <groupId>net.java.sezpoz</groupId>
    <artifactId>sezpoz</artifactId>
    <version>(...latest available...)</version>
  </dependency>
</dependencies>

Usage Summary

See Javadoc for details on particular classes, or just look at demo sources.

Support for declaring, creating, and inspecting indices of annotated Java elements.

For example, to permit registration of simple menu items, while making it possible to prepare a menu without loading any of them until they are actually selected:

 @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
 @Retention(RetentionPolicy.SOURCE)
 @Indexable(type=ActionListener.class)
 public @interface MenuItem {
     String menuName();
     String itemName();
     String iconPath() default "";
 }
 
A concrete registration might look like:
 @MenuItem(menuName="File", itemName="Print", iconPath=".../print.png")
 public class PrintAction extends AbstractAction {
     public void actionPerformed(ActionEvent e) {...}
 }
 
Alternatively:
 public class Actions {
     @MenuItem(menuName="File", itemName="Print")
     public static Action print() {...}
 }
 
or even:
 public class Actions {
     @MenuItem(menuName="File", itemName="Print")
     public static final Action PRINT = ...;
 }
 
To create the index on JDK 6, just compile your sources normally with javac. If using JDK 5, simply run apt instead of/in addition to javac. (The processor is in the same JAR as this API and should be autodetected.)

Usage is then simple:

 for (final IndexItem<MenuItem,ActionListener> item :
         Index.load(MenuItem.class, ActionListener.class)) {
     JMenu menu = new JMenu(item.annotation().menuName());
     JMenuItem menuitem = new JMenuItem(item.annotation().itemName());
     String icon = item.annotation().iconPath();
     if (!icon.equals("")) {
          menuitem.setIcon(new ImageIcon(icon));
     }
     menuitem.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
             try {
                 item.instance().actionPerformed(e);
             } catch (InstantiationException x) {
                 x.printStackTrace();
             }
         }
     });
 }
 

Notes

Known limitations:

  1. When using JDK 5 and apt, incremental compilation can result in an index file being generated with only some of the desired entries, if other source files are omitted e.g. by Ant.

    This scenario works better using JDK 6's javac: if you compile just some sources which are marked with an indexable annotation, these entries will be appended to any existing registrations from previous runs of the compiler. (You should run a clean build if you delete annotations from sources.)

  2. The Java language spec currently prohibits recursive annotation definitions, although javac in JDK 5 does not. (JDK 6 and 7's javac do.) See bug #6264216.

Eclipse-specific notes: make sure annotation processing is enabled at least for any projects registering objects using annotations. Make sure the SezPoz library is in the factory path for annotation processors. You also need to check the box Run this container's processor in batch mode from the Advanced button in Java Compiler > Annotation Processing > Factory Path. There does not appear to be any way for Eclipse to discover processors in the regular classpath as JSR 269 suggests, and there does not appear to be any way to make these settings apply automatically to all projects. Eclipse users are recommended to use javac (e.g. via Maven) to build. Eclipse Help Page Eclipse bug #280542