- What Is Code Generation?
- Passive Code Generators
- Active Code Generators
- Attribute-Oriented Programming
- Introducing XDoclet
- Working with Actively Generated Code
- Summary
Attribute-Oriented Programming
Active code generators can work effectively given well-defined metadata and a suitable pattern against which to generate the required code. Attribute-oriented programming leverages the benefits of active code generation by augmenting the code with special metadata tags known as attributes.
What Are Attributes?
Attribute-oriented programming languages enable special declarative tags, or attributes, to be embedded within the body of the code. During compilation, these attributes are extracted by the compiler and passed to an attribute provider, responsible for generating code based on the properties of the attribute and the nature of the code within which it is embedded.
The purpose of attributes is to enable the base language to be extended through the provision of custom-attribute providers. The attribute providers are essentially active code generators that inspect the code surrounding the attribute and produce further code.
Attributes Versus Preprocessor Directives
For those familiar with languages such as C and C++, attribute-oriented programming might sound very similar to preprocessor directives, a language construct not available in Java. Preprocessor directives are special instructions within the code that are handled by a preprocessor prior to compilation. Typically, these directives take the form of macros that are expanded within the body of the code before the source is compiled.
Preprocessor macros are a simple, but powerful, form of code generation and are used extensively within C and C++. Such is the power of the preprocessor that early C++ compilers were essentially preprocessors that expanded macros to generate straight C programming language code that was then compiled.
Though macros are powerful, if used incorrectly, they can result in some very ugly code that is extremely difficult to read and maintain. Macros can considerably alter the appearance of the language, making it very difficult for anything other than the C++ preprocessor to parse. In the past, complex macros have stopped the reverse-engineering features of some high-end modeling tools dead in their tracks. This might be why James Gosling decided to stay well clear of preprocessor directives with Java, presumably preferring instead to keep the language clean and uncluttered.
Attributes differ from preprocessor directives in that the generated code is not expanded within the body of the main code, but rather is written to a separate source file that is later compiled. This approach has the advantage that the original code is not changed behind the scenes, as is the case with macros. Instead, the newly generated file can be both viewed and debugged.
Attributes also serve to annotate the code, whereas macros are embedded into the control flow of the program. This difference makes attributed code much easier to read and understand than code that is plagued with the overzealous use of macros.
J2SE 5.0 Annotations and Attributes
Microsoft has augmented its C++ compiler to support attributes embedded within the C++ language to simplify the development of COM objects for the Microsoft platform. The .NET platform also supports the use of attributes, although these are used more to direct the behavior of a component at runtime rather than at compile time.
The release of J2SE 5.0 brings annotations to Java, a new language construct synonymous with the concept of attributes for declaring metadata within the body of a program. The new annotations construct that now forms part of J2SE 5.0 was defined under the Java Community Process as JSR-175, A Metadata Facility for the Java Programming Language.
J2SE 5.0 annotations realize the attribute concept, enabling existing program elements, such as classes, methods, and fields, to be annotated with additional metadata information. This information embedded within the code can then be used by development tools to generate additional program artifacts.
The compiler is also able to store some annotations as class-file attributes, making them accessible at runtime via a new reflection API. The existence of runtime attributes presents application frameworks with the opportunity to inject bytecode at runtime instead of generating code as part of a precompilation step.
Work is already underway on a number of different technologies that leverage the power of Java's new metadata facility. As an example of how annotations are used within the body of a program, here is a code snippet that uses annotations defined by JSR-181, Web Services Metadata for the Java Platform.
@WebService public class BusinessService { @WebMethod public string myBusinessMethod() { . . . } }
The annotations in the code are identified by the @ symbol, a notation commonly found inside comment blocks for use with Java's Doclet API. One of the objectives of JSR-181 is to allow the developer to convert a plain Java class into a Web Service simply by adding predefined annotation types.
From the example code snippet, the annotation types of @WebService and @WebMethod instruct a JSR-181-aware precompilation tool to generate the Web Services Definition Language (WSDL), schema, and other program artifacts necessary to expose the class as a Web Service.
The Java community has awaited the implementation of JSR-175 as part of J2SE 5.0 with some considerable excitement. During the wait, the open source community stepped in to fill the void by bringing the benefits of attributes to the Java platform using another approach.