Tag Interface

Category: JavaIdioms


A Tag Interface is a Java term. It is an empty interface which a class implements to claim membership in a set. For example, if a class implements the Serializable interface, it is claiming to be serializable -- to be a member of the set of serializable classes. The interface itself declares no methods; it's just a tag.

There is an issue with TagInterfaces. They are most meaningful to the Java VM itself. The Java VM knows to play some special "tricks" with a cloneable or serializable class. A TagInterface is just some kind of boolean flag for a programmer. It's true or false (instanceof operator). It also provides type compatibility with the interface, but since the interface doesn't declare any methods, there is nothing useful which can be implemented to support the interface.


TagInterfaces are often useful when used in combination with Reflection. As described above, they are a way of associating boolean "flags" with classes or interfaces. These flags can be checked by reflective code written to perform generic operations on any object, such as methods of base classes that FallBackOnReflection. This is how the Serializable interface is used, for example.

Here's another example, from a network protocol framework. A protocol stack is divided into protocol layers, each of which provides interfaces for data transmission and reception, and can also provide one or more control interfaces. The application using the stack, can query for control interfaces by passing the Class object representing the required type of control interface to a query method of the protocol layer at the top of the stack.

A base class is provided to make it easier to implement protocol layers. The base class falls back on reflection to find control interfaces. It enumerates interfaces implemented by the concrete layer class to find those that extend a TagInterface used to identify control interfaces and are the compatible with the control interface required by the application.

Therefore, all protocol control interfaces must be defined to extend the TagInterface. This both helps the implementation of the reflective base class, and stops applications querying for concrete interfaces or classes that are not control interfaces.

-- NatPryce

This is how the JavaBeans framework determines which methods represent an event source. Reflection is used to find methods named addXXXListener( XXXListener l ) and removeXXXListener( XXXListener l ), where XXXListener is an interface that extends the empty TagInterface java.util.EventListener.


A TagInterface is used as a boolean predicate when it is not possible to define that predicate as a method because the objects are not related by inheritance, or because you cannot add methods to a common base class.

The drawback with a TagInterface is that it defines predicate upon instances of a class and all classes derived from that class. A tag interface does not allow that predicate to be evaluated dynamically, or to be overridden in derived classes. This can cause problems later when you want to add such features.


I HaveThisPattern. --

What do you use it for?


With the advent of AttributedProgramming? a.k.a. AnnotationsInJava?, TagInterfaces might be a thing of past.

An example:

    @Serializable()
    public class MyClass {
    }

-- VhIndukumar

Could you please continue your example by showing how you then check to see if MyClass is Serializable? For instance, using TagInterfaces? you would do 'if (myClass instanceof Serializable)'.

--

Like this:

    new MyClass().getClass().isAnnotationPresent(Serializable.class) // assuming that Serializable was an annotation

Full example here: http://github.com/nerab/TaggingInterfaceVsAnnotation

--- NicolasRabenau?


I HaveThisPattern and I use it to hide from middlemen implementation details such as whether they are dealing with real or fake objects.

For example, let's say we have a component (the middleman) that requests input from some supplier, massages it somehow, and then gives the output to some consumer. It may be the case that the supplier and the consumer both know some details about some part of the data that the middleman does not care about at all. Assume further that these details are relatively heavy-weight --- for example, they may be blobs of binary data of some sort. The middleman shuffles the input around and maybe processes some wrapper information, but it never touches these binary data blobs at all.

Okay. Now let's say we want to write a test for the middleman. Our plan is to synthesize some input, run it through the middleman, and then assert that the right massaged data comes out. Now, it may be difficult or time-consuming to synthesize actual data blobs, and they may be bulky to compare, etc., so what we really want to do is provide fake data blobs that just have maybe simple ID numbers but no actual data. We could subclass the binary data class, but that would be messy, so we want to extract a common interface instead. The problem is that the real blobs and the fake blobs actually have no common interface. So what do we do? Extract the interface anyway!

Where does this leave us? Well, we have a fake consumer that expects fake blobs and a real consumer that expects real blobs, but since the blobs do not have a common interface, each consumer will have to downcast the blobs to its expected implementation class. So now we have a downcast not only in our test code, but also in our production code. Bummer. On the other hand, we have isolated the concrete blob implementation from the middleman. This would actually not be possible without requiring downcasts in the consumers. More importantly, however, we now have an easy way of substituting the blobs for test doubles.

--- DanielBrockman


EditText of this page (last edited April 10, 2012) or FindPage with title or text search