Decorating code (Research Paper)


Published on

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Decorating code (Research Paper)

  1. 1. Decorating Code: A Survey of Meta-programming<br />Jenna Pederson<br /> SAVEDATE @ "MMMM d, yyyy" * MERGEFORMAT June 17, 2006<br />Abstract<br />With the release of J2SETM Development Kit 5.0 (JDKTM 5.0), developers have access to a new feature known as annotations. JSR 175 introduced this feature into JDKTM 5.0 as a means of creating custom annotations to add metadata to fields, methods, and classes. Tools can process this metadata during development, deployment, or at runtime. The tools can create source files, configuration files, or other artifacts during development. They can specify deployment configuration, and at runtime, annotations can be accessed using reflection. In addition to JDKTM 5.0 annotations, there are other meta-programming facilities available. These include pre-JDKTM 5.0 open-source implementations such as xDoclet and Jakarta Commons Attributes, as well as Microsoft .NET attributes, and Ruby.<br />This feature could enable a very powerful use of the Java programming language. As with any new language feature, annotations have the potential to impact maintenance, testability, and reusability, as well as influence other software engineering design principles.<br />In order to address the shortcomings of a metadata facility, this project will implement an annotation-based solution to the popular Web Services framework, Axis. As a novice user of Axis, this will allow for a comparison of what the developer must experience when implementing a Web Service from start to finish. If the introduction of JSR 175 aims to make the developer’s life easier, this path will surely expose its strengths and weaknesses. This annotation-based solution to Web Service deployment will use JSR 181 annotations. The key difference is that in this implementation, Axis will process the annotations at runtime, rather than a Web Service deployment descriptor (WSDD) file at deployment time. Instead of requiring the developer to write or generate a WSDD file, the developer will now have the option of decorating the Java code with metadata in order to expose the methods as Web Services.<br />Table of Contents<br /> TOC f h z Introduction PAGEREF _Toc138269940 h 1<br />Background PAGEREF _Toc138269941 h 1<br />XML PAGEREF _Toc138269942 h 1<br />Open-Source Implementations PAGEREF _Toc138269943 h 2<br />.NET Attributes PAGEREF _Toc138269944 h 3<br />Ruby PAGEREF _Toc138269945 h 4<br />Java Annotations PAGEREF _Toc138269946 h 5<br />JSR 175 PAGEREF _Toc138269947 h 7<br />Dissecting an Annotation Type Declaration PAGEREF _Toc138269948 h 7<br />Decorating Elements PAGEREF _Toc138269949 h 9<br />JSR 181 PAGEREF _Toc138269950 h 10<br />Axis Web Services PAGEREF _Toc138269951 h 11<br />Metadata and Web Services PAGEREF _Toc138269952 h 11<br />Design PAGEREF _Toc138269953 h 11<br />The JSR 181 Processor PAGEREF _Toc138269954 h 11<br />In Use PAGEREF _Toc138269955 h 12<br />Analysis PAGEREF _Toc138269956 h 13<br />The Future of Meta-programming PAGEREF _Toc138269957 h 14<br />References PAGEREF _Toc138269958 h 15<br />List of Figures<br /> TOC f F h z c "Figure" Figure 1 – Hibernate Mapping PAGEREF _Toc138269959 h 2<br />Figure 2 – Hibernate Object Using xDoclet PAGEREF _Toc138269960 h 3<br />Figure 3 - .NET WebService Attribute PAGEREF _Toc138269961 h 3<br />Figure 4 – Ruby Stock Class PAGEREF _Toc138269962 h 4<br />Figure 5 – Ruby Stock Class Using Meta-programming PAGEREF _Toc138269963 h 4<br />Figure 6 – Using Ruby Stock Class PAGEREF _Toc138269964 h 5<br />Figure 7 – Hibernate Object Using Annotations PAGEREF _Toc138269965 h 6<br />Figure 8 - @Transactional Annotation Type Declaration PAGEREF _Toc138269966 h 8<br />Figure 9 – Illegal Block Annotation PAGEREF _Toc138269967 h 9<br />Figure 10 – Illegal Annotation PAGEREF _Toc138269968 h 10<br />Figure 11 – Exposing a WebService Using JSR 181 PAGEREF _Toc138269969 h 10<br />Figure 12 – StockExch Web Service PAGEREF _Toc138269970 h 12<br />Figure 13 – server-config.wsdd PAGEREF _Toc138269971 h 12<br />Figure 14 – axisConfig.xml PAGEREF _Toc138269972 h 13<br />Figure 15 – web.xml PAGEREF _Toc138269973 h 13<br />Introduction TC "Introduction" f C l "1" <br />Wikipedia defines meta-programming as the writing of programs that write themselves [14]. The research that follows explores the capabilities of this programming technique. The goal is to document the strengths and weaknesses of meta-programming, with a focus on the use of J2SETM Development Kit 5.0 (JDKTM 5.0) annotations. This research will cover the background of meta-programming and address how annotation-based metadata influences software engineering design principles.<br />In order to demonstrate these strengths and weaknesses successfully, this research will also provide an implementation of an annotation-based solution to the popular Web Services framework, Axis. It will compare the developer experience of configuring a Web Service using the conventional configuration files to this proposed solution.<br />Background TC "Background" f C l "1" <br />Meta-programming can involve generating boilerplate code, generating other programs at design or compile time, or even modifying programs at runtime. Developers can react quickly and more accurately to the constantly changing requirements. It gives developers the ability to reduce the duplication of code and provides for better maintainability. Meta-programming is declarative, specifying what is necessary to get the job done. Metadata describes the attributes about a program or element. Meta-programs process this metadata to generate or modify code or other programs. Developers are able to create a domain-specific language. A language that closely resembles the language of the problem at hand tends to promote a better understanding of the application.<br />The history of programming has always involved increasing the level of abstraction. In the beginning, it was about writing machine code that computers ran directly. Then, assemblers translated a higher level of code into machine code. The next generation brought about higher-level languages, structured programming, and later object-oriented programming. Each of these has added a level of abstraction between the developer and the machine code executed by the computer [4]. These abstractions make developers lives easier.<br />A compiler is the most common abstraction and is a form of meta-programming [5]. In addition to compilers, there are several different facilities available for meta-programming. The annotation framework introduced Java Specification Request (JSR) 175 in JDKTM 5.0 is one of several available for the Java programming language. Meta-programming facilities for other languages will be briefly touched on later.<br />The history behind Java annotations is also revolutionary. Java started out as a strictly imperative programming language where programs specified how to get the job done. More recently, it has become necessary to specify the relationships and dependencies between components and services deployed to containers. Combining both the imperative nature of Java with declarative features enables developers to become more effective. Java contains a significant amount of boilerplate code, more often than not, amounting to duplicate code, maintenance issues, and unnecessarily complex code.<br />XML TC "XML" f C l "2" <br />Extensible Markup Language (XML) files were the first declarative approach to solving this problem. It is yet another level of abstraction, which holds several disadvantages. The first disadvantage is the “XML Hell” that developers go through while learning and writing XML. It is traditionally stored in flat text files and can be very verbose. Often it is redundant as XML elements are repeated. XML is not checked by the compiler and issues are only found at runtime. It moves the maintenance issues from the Java code to the XML code. Figure 1 below is an example that we will follow throughout the next few sections:<br />Figure 1 – Hibernate Mapping In XML TC "Figure 1 – Hibernate Mapping" f F l "1" <br /><hibernate-mapping> <class name="decoratingcode.examples.Stock" table="stock"> <id name="id" column="symbol" type="java.lang.String" unsaved-value="undefined"> <generator class="assigned"/> </id> <property name="price" type="java.math.BigDecimal" update="true" insert="true" column="price" length="22" not-null="true"/> </class></hibernate-mapping><br />This is the XML, which turns a Java class into a Hibernate object. It details the attributes of each property need to persist the object to a database. This XML configuration is in addition to the actual Java class containing the properties and their getters and setters.<br />Open-Source Implementations TC "Open-Source Implementations" f C l "2" <br />package decoratingcode.examples;import java.math.BigDecimal;/** * @hibernate.class default-access="field" table="stock" */public class Stock { private String id; // symbol private BigDecimal price; private long timestamp; /** * generator-class="assigned" unsaved-value="undefined" column="symbol" */ public String getId() { return id; } public void setId(String id) { = id; }xDoclet is an open-source framework which embeds tags in Javadoc comments. These tags are metadata, which specify where to deploy services and what code or configuration files to generate. A doclet processes these tags pre-compilation to generate artifacts for the application to use at runtime. Below is an example of the Java class from above decorated with xDoclet tags:<br /> /** * not-null="true" column="price" length="22" */ public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public long getTimestamp() { return timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } }Figure 2 – Hibernate Object Using xDoclet TC "Figure 2 – Hibernate Object Using xDoclet" f F l "1" <br />xDoclet provides a Hibernate doclet task which processes these tags and generates the XML shown in the previous example. One key feature missing from xDoclet is the ability to gain access to this metadata at runtime.<br />Generated code or template-based programming, as with xDoclet, tends to be more accurate, or at least as accurate as the template is. One downside to this is that generated code or configuration files can be a maintenance headache. You cannot go edit the generated code to fix it or customize it because the next build will just regenerate it, deleting the edits. This requires the template to be maintained as well.<br />Other design-time implementations are available for the Java platform. Jakarta Commons Attributes (C-A) and Attrib4J are two other frameworks, which also use custom Javadoc tags to allow developers to add metadata to their code. These frameworks have helped Java developers inch their way closer to the attributes that Microsoft .NET introduced into the .NET platform.<br />.NET Attributes TC ".NET Attributes" f C l "2" <br /><%@ WebService Language="C#" Class="DecoratingCode.Examples.StockExchService" %>namespace DecoratingCode.Examples {public class StockExchService: System.Web.Services.WebService{[WebMethod] public Double getStockPrice(string symbol) {return someStockPrice; }}}Microsoft .NET provides its own metadata capabilities known as attributes. The introduction of this attribute-oriented programming brought about the next generation of meta-programming. Attributes are declarative tags, which reside inside the code, adding a powerful dimension to the .NET framework. The example below defines a Web Service in C# using attributes:<br />Figure 3 - .NET WebService Attribute TC "Figure 3 - .NET WebService Attribute" f F l "1" <br />The first attribute, WebService, exposes the class as a Web Service. The second attribute, WebMethod, exposes the getStockPrice() method as a part of a Web Service.<br />These attributes add additional meaning to program elements. They are stored in a .NET assembly and become available at design time, compile time, or runtime. The .NET framework provides over 200 attributes in the Framework Class Library (FCL) out of the box, giving developers easy access to manipulate behavior. Developers of the FCL originally created many of these predefined attributes in an effort to make their own lives easier [8].<br />There are two very important aspects of this metadata framework. The first is that this framework gives developers the ability to create and customize these attributes. The second important aspect is that the .NET attributes are not language specific. This allows developers to create customize, and use attributes across the .NET framework without the need to modify language-specific compilers.<br />Microsoft supported meta-programming prior to .NET in Microsoft Transaction Services (MTS) and COM+ environments [8]. The older environments only provided a few predefined attributes, but the .NET implementation allows developers to tap into these services and features using attributes. Early COM programming allowed developers to explore late binding. The information describing components was spread across several files, making it painful to truly appreciate. Attributes attempt to solve this problem by keeping the metadata near the place of implementation.<br />Ruby TC "Ruby" f C l "2" <br />1 class Stock2def symbol=(value)3@symbol=value4end5def symbol6return @symbol7end8def price=(value)9@price=value10end11def price12return @price13end14 endThe Ruby language has been public since 1993 and has gained serious momentum over the last few years. It is an interpreted language, which is object-oriented. In fact, everything in Ruby is an object, including nil [15]. Two of its many features include a simple, concise syntax and dynamic typing. Its reflective feature provides developers with meta-programming abilities. Ruby objects can change behavior on the fly, even generate classes and behavior at runtime using reflection [9]. The following are two examples of Ruby classes:<br />Figure 4 – Ruby Stock Class TC "Figure 4 – Ruby Stock Class" f F l "1" <br />1 class StockWithMetaprogramming2attr_accessor :symbol, :price3 endFigure 5 – Ruby Stock Class Using Meta-programming TC "Figure 5 – Ruby Stock Class Using Meta-programming" f F l "1" <br />Granted this is a trivial example, but compare the fourteen-line class to the three-line class. Stock explicitly defines the getters and setters for the symbol and price instance variables. StockWithMetaprogramming declaratively adds symbol and price, as well as their getters and setters, using the attr_accessor method. Ruby allows methods to be invoked as part of the class declaration. These classes only contain two instance variables. Imagine the size of a class with the need for ten instance variables.<br />irb(main):013:0> stock => #<Stock:0x2c0f698>irb(main):014:0> stock.symbol = "DRIV"=> "DRIV"irb(main):015:0> stock.price = 40.81=> 40.81irb(main):016:0> stock.symbol=> "DRIV"irb(main):017:0> stock.price=> 40.81Both classes above allow the developer to access the instance variables in the same manner:<br />Figure 6 – Using Ruby Stock Class TC "Figure 6 – Using Ruby Stock Class" f F l "1" <br />The most prominent example of this capability is Ruby on Rails [15]. The dynamic typing and reflective nature of Ruby allow the Rails framework to generate core application code at runtime. The concise language features and meta-programming abilities ease the development of Rails applications.<br />Java Annotations TC "Java Annotations" f C l "2" <br />Until JDKTM 5.0, Java has never had this sort of functionality built-in. Developers had to write their own frameworks for meta-programming. These efforts have not been without great benefit, as the lessons learned from using XML, programming with xDoclet and other open-source implementations, as well as the abilities already present with .NET attributes, have contributed greatly to the Java annotation standard. The future of annotations is wide open at this point, with several frameworks converting to use annotations instead of XML or a form of Javadoc tags.<br />With many developers creating frameworks to ease their own burdens and maybe even possibly that of others, we begin to lose sight of the programming standards and lose consistency within our code. When several frameworks accomplish the same thing, just in a slightly different way, developers who support applications have to stay on their toes in order to know how each works. Applications become even more tightly coupled to these external framework dependencies, which may or may not play well with others. Maintenance and upgrading of that which depends on these frameworks becomes nightmarish. The upgrade of one library often implies the upgrade another library, which may or may not be available. Budget constraints often force companies put this off indefinitely. More often than not, it is in favor of building new features.<br />The introduction of a metadata facility into the Java language was the next logical step. The annotations now live as first-class citizens within the Java code. They are part of the Application Programming Interfaces (APIs), are checked at compile-time, and are supported by Integrated Development Environments (IDEs) and other development and modeling tools. Compare the class below with the one in Figure 2:<br />Figure 7 – Hibernate Object Using Annotations TC "Figure 7 – Hibernate Object Using Annotations" f F l "1" <br />package decoratingcode.examples;import java.math.BigDecimal;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;import javax.persistence.Transient;@Entity@Table(name="stock")public class Stock { @Id @Column(name="symbol", nullable=false) @GeneratedValue(strategy=GenerationType.IDENTITY) private String id; @Column(name="price", nullable=false, length=22) private BigDecimal price; @Transient private long timestamp; // getter and setter method declarations}<br />This is the same Stock class, but it is decorated with Java annotations directly in the source code. Note the import statement for each annotation used, creating more dependencies.<br />Developers can decorate different program elements with annotations. By keeping the metadata closer to the implementation, developers are able to understand better the context of the metadata. XML provides this level of context, but with multiple layers. Maintenance can become easier, but configuration can be more difficult as a change to an annotated class requires it to be recompiled and redeployed. Frameworks such as EJB3, address this issue by providing the ability to override annotations with XML. A benefit to coupling the metadata with the code is that when a program element needs to change, the metadata is right there waiting to be updated. Depending on the modification, the code may not even compile. An incorrect change to an XML configuration file will be compiled and deployed before the issue is found at runtime. When the code and metadata are separated, it is often not implied within the code that there are external dependencies that must also be changed. Coupling code and metadata allows the metadata to be readily visible and not forgotten about. Applying metadata directly in the source code means that developers can more uniquely define program elements, creating a domain-specific language.<br />While declaratively configuring these relationships and dependencies within the Java code will increase developer productivity, architects argue coupling the configuration code with the application code has far reaching effects [12]. Besides blurring the line of separation between code and configuration, these dependencies tie applications to external frameworks. These dependencies, as mentioned above, can be maintenance headaches. What makes this even more of an issue is that these annotations are first-class citizens of the code. When upgrades or migrations of the external dependencies do occur, all Java code using the legacy annotations will need to be modified, recompiled, and tested.<br />JSR 175 TC "JSR 175" f C l "1" <br />JSR 175 introduced annotations into the Java programming language. The Java Community Process (JCP) first proposed this meta-programming facility in early 2002. By August of 2004, the proposed final draft was submitted and it was released into the mainstream as an official feature of JDKTM 5.0.<br />JSR 175 aims to improve developer’s lives by providing the ability to meta-program in Java [3]. In addition to seven built-in annotations, it provides a framework for developers to write their own annotations.<br />For annotations to have any meaning, they must be processed by some predefined mechanism. There are three basic forms of annotation consumers [10]:<br />General tools read the annotations of external programs, but do not actually load them into the virtual machine.<br />Specific tools read known annotations at design-time or compile-time, loading the annotation interfaces into the virtual machine. They allow you to generate the boilerplate code that many APIs require. Based on the annotations in the source code, they produce additional source code or XML documents.<br />Introspectors use the Java reflection APIs, inspecting classes at runtime for metadata. Both classes and interfaces are loaded into the virtual machine. Introspectors are commonly used when an application only has access to class files.<br />JSR 175 provided updates to the reflection APIs. Included are methods to retrieve annotations from different element types. These additions allow developers to write custom annotation processing tools. In addition, Sun Microsystems also updated the javadoc APIs to be able to read the annotations as well as the existing javadoc tags.<br />JSR 175 also defined the syntax and semantics of annotations. Their decisions were based on the JCP and an expert group of people with a vested interest in the metadata feature of Java. This includes experts from companies like IBM, BEA Systems, Oracle, and Sun Microsystems, Inc. Using the lessons learned through the use of other metadata facilities, they were able to define the Java annotation feature.<br />Many APIs and programs already use attribute as a keyword, so annotation was chosen to enable backward compatibility. Instead of using the [] used to indicate in .NET the presence of metadata, the JCP chose to use the @ symbol, reminiscent of javadoc and the existing open-source metadata frameworks [11]. The @ symbol is also a mnemonic for Annotation Type [11].<br />Dissecting an Annotation Type Declaration TC "Dissecting an Annotation Type Declaration" f C l "2" <br />JSR 175 provides a framework for defining annotation types for custom use. This mechanism enables developers to program Java more declaratively. By creating custom annotations, the developers will be able to use Java in a more domain-specific role where metadata lives closer to the problem at hand.<br />An annotation type declaration defines how an annotation can be used. It defines what kind of program elements it can annotate. It specifies how and when the annotation is accessible and it declares members and their default values. It does this in its own .java file that must reside in the class path in order to be accessible.<br />Let us dissect the annotation type declaration below:<br />1@Target({ElementType.METHOD, ElementType.TYPE})2@Retention(RetentionPolicy.RUNTIME)3@Inherited4@Documented5public @interface Transactional {6Propagation propagation() default Propagation.REQUIRED;7Isolation isolation() default Isolation.DEFAULT;8boolean readOnly() default false;9Class[] rollbackFor() default {};10String[] rollbackForClassName() default {};11Class[] noRollbackFor() default {};12String[] noRollbackForClassName() default {};13}Figure 8 - @Transactional Annotation Type Declaration TC "Figure 8 - @Transactional Annotation Type Declaration" f F l "1" <br />The annotation type declaration above is a trimmed down version of the Spring Framework’s @Transactional annotation. While it resembles a Java interface, note the @ symbol in front of the interface keyword in line 5. This indicates this is an annotation type declaration, which implicitly inherits from java.lang.annotation.Annotation. Any interface that explicitly inherits from this interface is not an annotation type declaration. This interface is similar to java.lang.Object in that it’s methods are never part of the annotation itself. Annotation type declarations are prohibited from extending any other element.<br />Starting at line 1, the built-in meta-annotation, @Target, annotates this annotation to indicate where the annotation can be applied. In this example, it can decorate a method or a class. On line 2, the @Retention annotation declares how this annotation is to be treated by the compiler and the virtual machine. This is a runtime annotation, meaning that the annotation will be retained in class file attributes at runtime.<br />Lines 6 – 12 declare the annotations members. Note that instead of using a field declaration style similar to Java classes, a method declaration style is used. This resembles the method declarations present in Java interfaces. Each of the members may define a default value. The return types can include an array, as seen in lines 9 – 12. However, these method-like declarations cannot be parameterized, nor can they throw exceptions.<br />Above we saw four of the seven annotations that JSR 175 pre-defines and are that included in the JDKTM 5.0 platform. Here is a brief overview of their meaning [11,12]:<br />@Deprecated: Indicates an element is deprecated and is accessible at runtime.<br />@Override: Indicates a method is intended to override a superclass method. If it does not override any method, there are compile-time errors.<br />@SupressWarnings: Tells the compiler to ignore any warnings generated by the annotated element.<br />The following are meta-annotations, meant to annotate other annotations [11,12]:<br />@Documented: Indicates the annotation should be included in the javadoc.<br />@Inherited: Indicates that subclasses inherit the annotation.<br />@Target: Defines the locations that this annotation can be placed.<br />@Retention: Defines how this annotation is retained.<br />The number of predefined Java annotations dwarfs in comparison to the over 200 predefined Microsoft .NET attributes.<br />One of the benefits of the @Retention meta-annotation is that a developer can specify where this annotation is retained. For instance, if an annotation is purely meant for documentation purposes, it might be defined as: @Retention(RetentionPolicy.SOURCE). RetentionPolicy.CLASS and RetentionPolicy.RUNTIME are the other two valid values. If every annotation were defined as RetetionPolicy.RUNTIME, they all would be retained when the class was loaded into the virtual machine. This unfortunately, could impact performance. By providing this meta-annotation, developers have control over how accessible their annotations are.<br />Decorating Elements TC "Decorating Elements" f C l "2" <br />Annotations can be applied to the following program elements:<br />Class<br />Interface<br />Field<br />Method<br />Parameter<br />Constructor<br />Enum<br />Local variable<br />Package declarations<br />Packages can be annotated with only one annotation. Annotating a package is different compared to annotating any other program elements, but it is similar to the mechanism used for javadocing a package. The annotation is placed in a file named and resides in the package’s source directory. This file replaces the javadoc’s package.html file and holds the package’s javadoc info as well.<br />One obvious programming construct is not included in this list. Because of the complexity of an arbitrary block of code, they cannot be annotated. For instance, you cannot do the following:<br />@BlockAnnotation{if (someCondition){// do something} else {// do something else}}Figure 9 – Illegal Block Annotation TC "Figure 9 – Illegal Block Annotation" f F l "1" <br />As one would expect, annotated program elements must import the annotation declaration, just as a Java class is imported to gain access to its methods. This inherently creates a dependency on any annotations that are applied to program elements within the class.<br />To illustrate this, consider the restriction that a member-value pair must be present for all annotation members without defaults defined. Problems can arise when a member is added to an existing annotation, but no default value is defined. This will result in a runtime exception when the annotation is read.<br />It is not with out disadvantages, though. Metadata cannot, however, be applied to existing class files. For example, with a commercial product, the source code may be unavailable and metadata cannot be “injected.”<br />Annotations are also restricted from directly affecting the semantics of a program. For instance, metadata cannot be used to modify the code that it resides in. The following @Field annotation cannot generate getters and setters for the field that is annotated:<br />public class BadExample {@FieldString aField;}Figure 10 – Illegal Annotation TC "Figure 10 – Illegal Annotation" f F l "1" <br />The semantics of this class become vague when the reader cannot find the definition of the getAField() or setAField() methods. In other words, Java annotations cannot dynamically add methods, fields, or classes at runtime, as Ruby can. This, in my opinion is a serious downfall to how Java annotations function. To some extent this violates declarative programming in that you are unable to specify the what about an object and how it will behave once it is configured.<br />The framework provided here allows others to declare and use their own annotations. Several other JSRs are proposing the addition of common annotations. JSR 269 proposes a common framework for applications to process annotations. JSR 250 proposes a set of common annotations that applications can use. JSR 181 proposes a set of annotations to be used for defining Web Services classes and methods.<br />JSR 181 TC "JSR 181" f C l "1" <br />JSR 181 defines a set of annotations for use in exposing Web Services. As with other JSRs for metadata implementations, this aims to make developers lives easier. By reducing the amount of configuration code that usually resides in XML files, it provides annotations for configuring Web Services. As well as increasing developer productivity, JSR 181 also aims to develop a standard for creating Web Services in Java. In addition to the predefined set of annotations, it defines the specifications to which this set of annotations must adhere. The following is the set of predefined annotations [13]:<br />@WebService: Exposes a Java class or interface as a Web Service.<br />@WebMethod: Exposes a method as a Web Service operation.<br />@WebParam: Maps a parameter of an operation to an XML element<br />@WebResult: Maps a return value of an operation to an XML element<br />@Oneway: Indicates a Web Service operation has input but no output.<br />@HandlerChain: Maps a Web Service to an externally defined handler chain.<br />@SOAPBinding: Binds a Web Service to a SOAP message protocol.<br />@SOAPMessageHandlers: Defines SOAP handlers that run in response to a Web Service call.<br />@WebServicepublic class MyWebService { @WebMethod public void aWebServiceMethod() { // do something }}Figure 11 below is a simple example of how a developer exposes a Web Service using the @WebService and @WebMethod annotations:<br />Figure 11 – Exposing a WebService Using JSR 181 TC "Figure 11 – Exposing a WebService Using JSR 181" f F l "1" <br />In the remaining sections, we will follow these four annotations: @WebService, @WebMethod, @WebParam, @WebResult in the analysis of a real-life implementation.<br />Axis Web Services TC "Axis Web Services" f C l "1" <br />Apache Axis is a Simple Object Access Protocol (SOAP)-based implementation of Web Services in Java [1]. In Axis, a developer exposes a Web Service by configuring a WSDD file. On deployment, Axis reads this WSDD file into a WSDDDeployment object, registering the names of its services and methods as being accessible as Web Services. It is not until the service is actually requested by a client that Axis loads the classes into its class cache. Based on this WSDDDeployment object, Axis is aware of which classes and services are available. At that point, Axis invokes the actual Web Service using reflection.<br />Metadata and Web Services TC "Metadata and Web Services" f C l "2" <br />As previously mentioned, the Microsoft .NET framework has the ability to decorate a class with a WebService attribute and expose its methods with a WebMethod attribute. A developer can then deploy this Web Service without the effort of writing a WSDD-type file telling the hosting server which classes and methods are Web Services. The framework automatically registers the services based on the class and method attributes.<br />What if Axis had the same ability to configure the availability of Web Services as .NET currently does? The annotations provided by JSR 181 are the first step to providing this ability in Axis. The next step is to provide a mechanism to process the annotated classes. One of the criticisms of Axis 2.0 is that even though its release date was in April 2006, it does not yet provide this ability. Next, we will review a proof of concept of Axis with support for JSR 181 annotations.<br />Design TC "Design" f C l "2" <br />The key feature of this solution is that Axis will process these annotations at runtime, rather than at compile-time. Instead of requiring a WSDD file, the developer will have the option of decorating the Java class, exposing the Web Service and its methods. If annotations aim to ease the pain of developers by removing the boilerplate code and modifying behavior at runtime, than this will surely expose its strengths and weaknesses.<br />The JSR 181 Processor TC "The JSR 181 Processor" f C l "2" <br />JSR 181 defines how the processor will treat the set of annotations it defines. It defines what the default value of each annotation field is. Based on the annotation, the annotated element, the metadata, and any other annotations present, the processor must determine if it is a valid Web Service configuration and enforce the specifications that JSR 181 defines. The processor is required to produce a functioning Web Service, but what JSR 181 does not require is that the processor uses a specific processing model. For instance, this basic implementation processes the annotations at runtime. Another processor might process the annotations at build-time, generating deployable source code.<br />In Use TC "In Use" f C l "2" <br />package decoratingcode.examples.stockexch.server;import java.math.BigDecimal;import java.util.HashMap;import java.util.Map;import javax.jws.WebMethod;import javax.jws.WebParam;import javax.jws.WebResult;import javax.jws.WebService;@WebServicepublic class StockExch { private static Map<String, Stock> stocks = new HashMap<String, Stock>(); static { loadStocks(); } @WebMethod public BigDecimal getStockPrice( @WebParam(name="symbol") String symbol ) { Stock stock = stocks.get( symbol ); return stock.getPrice(); } @WebMethod @WebResult(name="Stock") public Stock getStock( @WebParam(name="symbol") String symbol ) { return stocks.get( symbol ); } private static void loadStocks() { // add Stocks to stocks map }}The features provided by a JSR 181 processor will speed up productivity. Below is a more complete annotated Web Service.<br />Figure 12 – StockExch Web Service<br /> TC "Figure 12 – StockExch Web Service" f F l "1" <br />Obviously, a developer must learn the concept of using annotations before he can be successful and productive programming in this fashion. Since this feature is now part of the official release of the JDK, programmers will have more access to annotations, they will become second nature, and most importantly, the compiler will check the annotations.<br />When comparing the Web Service configuration in Figure 12 above, it is easy to see why the WSDD configuration file below may become messy. Below is a snippet from the WSDD file, as there can be several Axis components configured here. Imagine defining more than two methods, several object mappings, along with schema definitions.<br /><service name="StockExch" provider="java:RPC"> <parameter name="className" value="decoratingcode.examples.stockexch.server.StockExch"/> <parameter name="allowedMethods" value="getStockPrice,getStock" /> <beanMapping qname="ns:Stock" xmlns:ns="decoratingcode.examples.stockexch.server" languageSpecificType="java:decoratingcode.examples.stockexch.server.Stock"/></service>Figure 13 – server-config.wsdd TC "Figure 13 – server-config.wsdd" f F l "1" <br />Often, it seems that XML configuration files are the result of a cut and paste job. Occasionally cut and paste will do. For more complex component configuration, it may pose problems since the compiler does not evaluate the XML, IDEs do not check it, and it is probably not spell checked by the developer. If XML is difficult to read and if no schema is defined or readily available, it is difficult to write efficiently. As a developer that often has the need to configure XML files, this nearly always lives up to its reputation of “XML Hell.” The annotations provided by JSR 181 reduce the learning curve for writing a Web Service immensely.<br />Analysis TC "Analysis" f C l "2" <br /><beans> <bean id="annotationProvider" class="org.apache.axis.configuration.AnnotationProvider"> <property name="annotatedClasses"> <list> <value>decoratingcode.examples.stockexch.server.StockExch</value> </list> </property> </bean></beans>Unfortunately, this particular implementation does require there to be an XML configuration detailing the names of annotated classes. One obvious issue that I ran into while trying to implement this annotation-based solution was determining from where to read the annotated classes. In the original implementation, the WSDD file defines exactly which classes need to be exposed, and Axis loads them based on this definition. Without some global way of defining which the classes an application has annotated as Web Services, I had no concise way of knowing which classes to load or from where to load the classes. I addressed this problem by using the Spring Framework’s WebApplicationContext to define which classes contained annotations. <br />Figure 14 – axisConfig.xml TC "Figure 14 – axisConfig.xml" f F l "1" <br />Figure 14 includes the bean annotationProvider that is needed by Spring for Axis to be able process the annotated classes. Each Web Service class or interface must be included in the <list> tag to have its annotations processed by Axis.<br />The configuration of a listener and the location of this axisConfig.xml file must also be added to the web.xml file as shown in Figure 15:<br /><context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/axisConfig.xml</param-value></context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener </listener-class></listener>Figure 15 – web.xml TC "Figure 15 – web.xml" f F l "1" <br />This problem uncovers a downfall of using runtime annotation processing. There is no way to apply an annotation at the global level. Considering the definition of metadata, to annotate an object, the target object must exist. In this case, there is no object available. The need to use XML to define which classes in an application contain annotations defeats the purpose of using Java annotations to reduce the need for configuration files. There is a similar issue with Hibernate’s use of annotations for persistence. An AnnotationConfiguration must have the annotated classes configured within a static initializer for the processor to know which annotated classes to process.<br />JSR 181 provides only a small set of possible annotations for configuring a Web Service. One upside to this is that it prevents applications from using the annotations in framework specific manners. For instance, it would not be good design to couple the annotation definitions to the Axis framework. To switch Web Service implementations would involve touching every Web Service class exposed using an annotation. This becomes risky when these define the contract with the client. Because of this, there is potential to affect any of the callers of the Web Services, as well.<br />The Future of Meta-programming TC "The Future of Meta-programming" f C l "1" <br />As stated on the Jakarta C-A website, “When Java 5.0 becomes as commonly used as 1.3+1.4 is today, nobody will want to use any other [Java] metadata framework, just like nobody wants to use any other string class than the java.lang one. Therefore, by that time, C-A will have been rendered superfluous, and development will stop” [2]. While it may be time before applications can convert to JDKTM 5.0 and begin using the annotation feature, there is a definite trend toward meta-programming. The ability to do meta-programming in Java using annotations takes a step closer to successful and useful declarative programming. It may take a few years for Java annotations (and their users) to mature and is by no means the silver bullet to meta-programming. However, once more applications convert to JDKTM 5.0, it is likely that the open source frameworks like xDoclet and C-A will no longer be supported. That does not mean that there will not be frameworks that provide annotation definitions, like JSR 181, or process annotations, like the annotation-based implementation of Axis described above. As developers and architects, we must be sure that we are using annotations in an effective way. Especially, in a way that does not promote coupling of frameworks.<br />With other technologies such as Microsoft .NET attributes, Ruby, and pre-JDKTM 5.0 metadata implementations available, there is surely a metadata facility available to suit an application’s needs and these technologies will continue to help shape Java annotations.<br />References TC "References" f C l "1" <br />[1] Apache Software Foundation (2005). Web Services – Axis [On-line]. Available:<br />[2] Apache Software Foundation (2005). Commons Attributes – Frequently Asked Questions [On-line]. Available:<br />[3] Heiss, Janice J. (2003). New Language Features for Ease of Development in the Java 2 Platform, Standard Edition 1.5: A Conversation with Joshua Bloch [On-line]. Available:<br />[4] Herrington, Jack (2003). Code-Generation Techniques for Java [On-line]. Available:<br />[5] Herrington, Jack (2003). Code Generation in Action [On-line]. Available:<br />[6] Hunter, Jason (2005). Making the Most of Java’s Metadata [On-line]. Available:<br />[7] Hunter, Jason (2005). Making the Most of Java’s Metadata, Part 2: Custom Annotations [On-line]. Available:<br />[8] Pattison, Ted (2005). Basic Instincts: Designing with Custom Attributes [On-line]. Available:<br />[9] Rustad, Aaron (2005). Ruby on Rails and J2EE: Is There Room For Both? [On-line]. Available:<br />[10] Sun Microsystems, Inc. (2004). JSR175: A Program Annotation Facility for the Javatm Programming Language: Final Release [On-line]. Available:<br />[11] Sun Microsystems, Inc. (2003). JSR-000175A Program Annotation Facility for the Javatm Programming Language: Public Review [On-line]. Available:<br />[12] Yuan, Michael Juntao (2006). Annotations, Friend or Foe? [On-line]. Available:<br />[13] Sun Microsystems, Inc. (2005). JSR-000181 Web Services Metadata for the Javatm Platform: Final Release [On-line]. Available:<br />[14] Wikipedia (2006). Metaprogramming [On-line]. Available:<br />[15] Wikipedia (2006). Ruby Programming Language [On-line]. Available:<br />