If you want to generate Java code (classes and interfaces) and AspectJ ITDs in response to the execution of one or more Roo commands, then you should create an advanced Roo add-on.
Spring Roo treats both simple and advanced add-ons the same way. The distinction between simple and advanced add-ons exists so that you can choose an appropriate add-on template based on your custom add-on requirement. The add-on template created by the addon
create
simple
command is useful if you want to create a custom add-on meant for adding project dependencies to the pom.xml
file and for adding configuration artifacts to the project. In this recipe we'll look at the addon
create
advanced
command, which is useful if you want to create a custom add-on to generate Java code and AspectJ ITD.
Create a new directory C:
oo-cookbookch07-advanced-add-on
in your system and start the Roo shell from the ch07-advanced-add-on
directory.
The following steps will demonstrate how to create an advanced add-on:
addon
create
advanced
command, as shown here, to create a com.roo.addon.myadvanced
add-on project:..roo> addon create advanced --topLevelPackage com.roo.addon.myadvanced ... Created SRC_MAIN_JAVA...MyadvancedCommands.java Created SRC_MAIN_JAVA...MyadvancedOperations.java Created SRC_MAIN_JAVA...MyadvancedOperationsImpl.java Created SRC_MAIN_JAVA...MyadvancedMetadata.java Created SRC_MAIN_JAVA...MyadvancedMetadataProvider.java Created SRC_MAIN_JAVA...RooMyadvanced.java Created SRC_MAIN_RESOURCES...configuration.xml
The output only shows some of the important files generated by the Roo command that we'll discuss them in this recipe.
perform
eclipse
command to create Eclipse-IDE specific configuration files:roo> perform eclipse
Now, import the com.roo.addon.myadvanced
Eclipse project into Eclipse IDE.
The addon
create
advanced
command creates a Roo add-on template which you can use as the starting point to create a custom Roo add-on which generates Java classes, interfaces and AspectJ ITDs. The following classes and interfaces are generated by the addon
create
advanced
command. The <last-part-of-top-level-package>
refers to the text after the last index of '.' in the value of the topLevelPackage
argument. In case of our example, the topLevelPackage
argument value is com.roo.addon.myadvanced
, which makes value of <last-part-of-top-level-package>
as 'myadvanced'.
<last-part-of-top-level-package>Commands.java
class: defines methods that are contributed to the Roo shell by the add-on.<last-part-of-top-level-package>Operations.java
interface: defines methods that contain the processing logic for commands defined in the *Commands.java
class.<last-part-of-top-level-package>OperationsImpl.java
class: implements the *Operations.java
interface.<last-part-of-top-level-package>Metadata.java
class: represents the metadata associated with this add-on. In this class you write the code for creating Java classes, interfaces, and AspectJ ITDs.<last-part-of-top-level-package>MetadataProvider.java
class: creates the metadata associated with this add-on.Roo<last-part-of-top-level-package>.java
class: represents the Roo annotation (similar to other Roo annotations like @RooEntity
, @RooJavaBean
, @RooSolrSearchable
, and so on) which triggers this add-on to generate Java classes, interfaces, and AspectJ ITDs.You may have noticed that a configuration.xml
file is also generated in the SRC_MAIN_RESOURCEScom
ooaddonmyadvanced
directory. The configuration.xml
file defines dependencies that are added by the add-on to the pom.xml
file of the Roo project.
The following code shows the methods of the MyAdvancedCommands
class that defines Roo commands exposed by the myadvanced add-on:
@Component @Service public class MyadvancedCommands implements CommandMarker { @Reference private MyadvancedOperations operations; @CliAvailabilityIndicator({ "myadvanced setup", "myadvanced add", "myadvanced all" }) public boolean isCommandAvailable() { return operations.isCommandAvailable(); } @CliCommand(value = "myadvanced add", help = "Some helpful description") public void add(@CliOption(key = "type", mandatory = true, help = "The java type to apply this annotation to") JavaType target) { operations.annotateType(target); } @CliCommand(value = "myadvanced all", help = "Some helpful description") public void all() { operations.annotateAll(); } @CliCommand(value = "myadvanced setup", help = "Setup Myadvanced addon") public void setup() { operations.setup(); } }
As the code shows, the myadvanced add-on registers the following commands with the Roo shell:
myadvanced
setup
: performs the initial setup that is required for using the add-on. When this command is executed, the myadvanced add-on updates project dependencies in the pom.xml
file.myadvanced
add
: annotates the Java class (specified via the type
argument of the myadvanced
add
command) with the @RooMyadvanced
annotation. In the preceding code, you'll notice that the Java class passed to the add
method is of type JavaType
. The JavaType
represents a Roo-specific class that simplifies accessing simple and package names of a Java type. Annotating a Java type with the @RooMyAdvanced
annotation kicks off code generation by the myadvanced add-on.myadvanced
all
: finds all the Java types in the project that are annotated with the @RooJavaBean
annotation (soon we'll see how the myadvanced add-on does this), and annotates them with the @RooMyAdvanced
annotation. Annotating a Java type with the @RooMyAdvanced
annotation kicks off code generation by the myadvanced add-on.The MyAdvancedCommands
class also defines a @CliAvailabilityIndicator
annotated method, which decides the availability of the myadvanced
setup
, myadvanced
add
, and myadvanced
all
commands.
Let's now look at the MyadvancedOperationsImpl
class, which provides implementations for the commands exposed by the myadvanced add-on.
The following code shows the MyadvancedOperationsImpl
class. The code doesn't show the implementation of the annotateType
and annotateAll
methods, which will be discussed in detail later in this section.
import ...roo.classpath.PhysicalTypeMetadataProvider; import ...roo.classpath.TypeLocationService; import ...roo.metadata.MetadataService; import ...roo.model.JavaType; import ...roo.project.ProjectOperations; import ...roo.project.Dependency; import ...roo.project.DependencyScope; import ...roo.project.DependencyType; import ...roo.project.Repository; import ...roo.support.util.XmlUtils; import org.w3c.dom.Element; @Component @Service public class MyadvancedOperationsImpl implements MyadvancedOperations { @Reference private MetadataService metadataService; @Reference private PhysicalTypeMetadataProvider physicalTypeMetadataProvider; @Reference private ProjectOperations projectOperations; @Reference private TypeLocationService typeLocationService; ... public boolean isCommandAvailable() { return projectOperations.isProjectAvailable(); } public void annotateType(JavaType javaType) { ... } public void annotateAll() { ... } public void setup() { projectOperations.addRepository( new Repository("Myadvanced Roo add-on repository", "Myadvanced Roo add-on repository", "https://com-roo-addon- myadvanced.googlecode.com/svn/repo")); List<Dependency> dependencies = new ArrayList<Dependency>(); dependencies.add( new Dependency("com.roo.addon.myadvanced", "com.roo.addon.myadvanced", "0.1.0.BUILD-SNAPSHOT", DependencyType.JAR, DependencyScope.PROVIDED)); for (Element dependencyElement : XmlUtils. findElements("/configuration/batch/" + "dependencies/dependency", XmlUtils.getConfiguration(getClass()))) { dependencies.add(new Dependency(dependencyElement)); } projectOperations.addDependencies(dependencies); } }
The MyadvancedOperationsImpl
class references the following services offered by Roo:
MetadataService
: service provided by Roo for retrieving metadata information for the Roo project, Java types, fields, methods, and so on. Refer to the Developing a simple add-on recipe for more details.PhysicalTypeMetadataProvider
: a metadata provider that provides metadata for a class, interface, enum, or annotation type. As we'll see later in this section, this metadata provider is used by the MyadvancedOperationsImpl
class to obtain the metadata information about the Java type that needs to be annotated with the @RooMyadvanced
annotation.ProjectOperations
: this is used by the myadvanced add-on in the isCommandAvailable
and setup
methods to check if a Roo project exists and to modify the pom.xml
file of the Roo project, as shown in the given code. The isCommandAvailable
method in the given code makes use of the isProjectAvailable
method of ProjectOperations
to determine if a Roo project has been created. The isCommandAvailable
method is invoked by the @CliAvailabilityIndicator
annotated method of the MyadvancedCommands
class. The setup
method in this code makes use of the addRepository
method of ProjectOperations
to add repository information of the add-on to the Roo project's pom.xml
file. By default, the repository refers to the repo
directory of the Google Code project of the add-on (refer to the pom.xml
file of the myadvanced add-on). The setup
method adds Roo project's dependency on the myadvanced add-on and the dependencies defined in the configuration.xml
(inside SRC_MAIN_RESOURCES/com/roo/addon/myadvanced
) file by using the addDependencies
method. The setup
method makes use of the getConfiguration
method of XmlUtils
class to load the configuration.xml
file.TypeLocationService
: a Roo service that helps with locating Java types in the Roo project. For instance, you can find Java types annotated with a particular annotation using TypeLocationService
.annotateType
method of the MyadvancedOperationsImpl
class is invoked when the myadvanced
add
command is executed. The following code shows the implementation of the annotateType
method:import ...roo.classpath.PhysicalTypeDetails; import ...roo.classpath.PhysicalTypeMetadata; import ...roo.classpath.PhysicalTypeMetadataProvider; import ...roo.classpath.TypeLocationService; import ...roo.classpath.details.MemberFindingUtils; import ...roo.classpath.details.MutableClassOrInterfaceTypeDetails; import ...roo.classpath.details.annotations.AnnotationMetadataBuilder; ... @Reference private MetadataService metadataService; @Reference private PhysicalTypeMetadataProvider physicalTypeMetadataProvider; ... public void annotateType(JavaType javaType) { String id = physicalTypeMetadataProvider.findIdentifier(javaType); PhysicalTypeMetadata physicalTypeMetadata = (PhysicalTypeMetadata) metadataService.get(id); PhysicalTypeDetails physicalTypeDetails = physicalTypeMetadata.getMemberHoldingTypeDetails(); MutableClassOrInterfaceTypeDetails mutableTypeDetails = (MutableClassOrInterfaceTypeDetails) physicalTypeDetails; if (MemberFindingUtils.getAnnotationOfType( mutableTypeDetails.getAnnotations(), new JavaType(RooMyadvanced.class.getName())) == null) { JavaType rooRooMyadvanced = new JavaType(RooMyadvanced.class.getName()); AnnotationMetadataBuilder annotationBuilder = new AnnotationMetadataBuilder(rooRooMyadvanced); mutableTypeDetails.addTypeAnnotation( annotationBuilder.build() ); } }
The annotateType
method accepts a JavaType
argument. The JavaType
argument represents the Java type that you specified as the value of the type
argument of the myadvanced add
command. The annotateType
method performs the following actions to annotate the JavaType
argument with the @RooMyadvanced
annotation:
JavaType
on which the annotation needs to be applied. This is achieved by using the findIdentifier
method of the PhysicalTypeMetadataProvider
class of Roo.Let's say that the myadvanced add
command is executed as shown here:
... roo> myadvanced add --type sample.roo.flightapp.domain.Flight
In the myadvanced
add
command, the value of the type
argument is sample.roo.flightapp.domain.Flight
. This Java type is passed to the annotateType
method of the MyadvancedOperationsImpl
class by Roo. The metadata identification string returned by the findIdentifier
method of PhysicalTypeMetadataProvider
is as follows:
MID:org.springframework.roo.classpath.PhysicalTypeIdentifier#SRC_MAIN_JAVA?sample.roo.flightapp.domain.Flight
PhysicalTypeMetadata
object, which represents the metadata information about the Java type.getMemberHoldingTypeDetails
method of PhysicalTypeMetadata
to retrieve PhysicalTypeDetails
. The PhysicalTypeDetails
provides details of the Java type represented by PhysicalTypeMetadata
.PhysicalTypeDetails
into MutableClassOrInterfaceTypeDetails
. The MutableClassOrInterfaceTypeDetails
is used to modify the Java type represented by it, which is the JavaType
argument passed to the annotateType
method of MyadvancedOperationsImpl
class. Amongst other things, you can use the MutableClassOrInterfaceTypeDetails
object to add or remove fields, methods, and annotations from the Java type.MemberFindingUtils
utility class to check if the Java type is already annotated with the @RooMyadvanced
annotation. AnnotationMetadataBuilder
to create the @RooMyAdvanced
annotation, and adds it to the Java type using the MutableClassOrInterfaceTypeDetails
object.annotateAll
method of the MyadvancedOperationsImpl
class, which adds the @RooMyadvanced
annotation to all the Java types annotated with the @RooJavaBean
annotation:import ...roo.classpath.TypeLocationService; import ...roo.model.JavaType; ... public void annotateAll() { for (JavaType type: typeLocationService.findTypesWithAnnotation( new JavaType("org.springframework.roo.addon. " + "javabean.RooJavaBean"))) { annotateType(type); } }
As shown in the preceding code, the annotateAll
method makes use of TypeLocationService
to find Java types that are annotated with the @RooJavaBean
annotation, and then invokes the annotateType
method to annotate Java types with the @RooMyadvanced
annotation.
Let's now look at how the myadvanced add-on triggers code generation using the MyadvancedMetadataProvider
class.
The MyadvancedMetadataProvider
class represents an OSGi component which creates a MyadvancedMetadata
instance when a Java type is annotated with the @RooMyadvanced
annotation. The MyadvancedMetadata
in turn creates an AspectJ ITD and adds a method and a field to it. In this section, we'll look at how Roo-generated MyadvancedMetadataProvider
is implemented.
The following code shows some of the methods of the MyadvancedMetadataProvider
class:
import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.osgi.service.component.ComponentContext; import ...roo.classpath.PhysicalTypeIdentifier; import ...roo.classpath.PhysicalTypeMetadata; import ...roo.classpath.itd.AbstractItdMetadataProvider; import ...roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem; import org.springframework.roo.model.JavaType; import org.springframework.roo.project.Path; @Component @Service public final class MyadvancedMetadataProvider extends AbstractItdMetadataProvider { protected void activate(ComponentContext context) { metadataDependencyRegistry. registerDependency(PhysicalTypeIdentifier. getMetadataIdentiferType(), getProvidesType()); addMetadataTrigger( new JavaType(RooMyadvanced.class.getName())); } protected void deactivate(ComponentContext context) { metadataDependencyRegistry. deregisterDependency(PhysicalTypeIdentifier. getMetadataIdentiferType(), getProvidesType()); removeMetadataTrigger( new JavaType(RooMyadvanced.class.getName())); } ... }
The preceding code shows that MyadvancedMetadataProvider
extends Roo's AbstractItdMetadataProvider
abstract class. The AbstractItdMetadataProvider
class defines the common functionality required by add-ons that generate AspectJ ITDs. The activate
method is invoked by the Apache Felix OSGi container when the myadvanced add-on is installed.
In Chapter 4, Web Application Development with Spring Web MVC you saw that if you redefine a method of the *_Roo_Controller.aj
file in the *Controller.java
class, then Roo automatically removes that method from the *_Roo_Controller.aj
file. We also saw that when you modify a @RooEntity
or @RooWebScaffold
annotation, it results in modification of corresponding AspectJ ITDs. Roo maintains dependency between Java types (which could be a class, interface, or a @Roo*
annotation) of the Roo project using metadata identification strings, making it possible for Roo to manage code contained in AspectJ ITD when changes are made to a Java type.
Let's now look closely at the following code snippet in the activate
method of MyadvancedMetadataProvider
class:
metadataDependencyRegistry. registerDependency(PhysicalTypeIdentifier. getMetadataIdentiferType(), getProvidesType());
The metadataDependencyRegistry
is a protected
attribute defined in Roo's AbstractItdMetadataProvider
class and is of type MetadataDependencyRegistry
. The MetadataDependencyRegistry
instance keeps track of dependencies between metadata identification strings. The registerDependency
method is used to specify dependency between metadata identification strings. PhysicalTypeIdentifier
represents a Roo class that creates a metadata identification string for a Java type in Roo project.
In the previous code, the PhysicalTypeIdentifier.getMetadataIdentiferType()
code returns MID:org.springframework.roo.classpath.PhysicalTypeIdentifier
, and MyadvancedMetadata.getMetadataIdentiferType()
returns MID:com.roo.addon.myadvanced.MyadvancedMetadata
. As both the metadata identification strings don't contain the Java type to which they apply, they are class-level metadata identification strings. You can create dependencies between class level-or instance-level metadata identification strings.
The MID:org.springframework.roo.classpath.PhysicalTypeIdentifier
represents the upstream dependency and MID:com.roo.addon.myadvanced.MyadvancedMetadata
represents the downstream dependency. When changes are made to an upstream dependency, Roo takes care of notifying all the downstream dependencies, which results in recreating the downstream metadata. The MetadataProvider
s are responsible for handling the notification. So, in the case of the myadvanced add-on, when a Java type (represented by MID:org.springframework.roo.classpath.PhysicalTypeIdentifier
) in the Roo project is changed, it notifies the MyadvancedMetadataProvider
instance.
The metadata dependencies specified in the activate
method should be unregistered in the deactivate
method of the metadata provider. The metadata dependencies are unregistered using the deregisterDependency
method of the MetadataDependencyRegistry
instance, as shown here for MyadvancedMetadataProvider
:
protected void deactivate(ComponentContext context) { metadataDependencyRegistry. deregisterDependency(PhysicalTypeIdentifier. getMetadataIdentiferType(), getProvidesType()); ... }
Metadata dependency registration ensures that downstream dependencies of a metadata are notified when changes occur in the upstream dependencies. To specify what triggers creation of metadata, metadata provider makes use of the addMetadataTrigger
method of the AbstractItdMetadataProvider
class, as shown here for MyadvancedMetadataProvider
:
protected void activate(ComponentContext context) { metadataDependencyRegistry. registerDependency(PhysicalTypeIdentifier. getMetadataIdentiferType(), getProvidesType()); addMetadataTrigger( new JavaType(RooMyadvanced.class.getName())); }
In the preceding code, the addMetadataTrigger
method accepts RooMyadvanced
Java type. It means that whenever a Java type is annotated with @RooMyadvanced
annotation, MyadvancedMetadataProvider
will create an instance of MyadvancedMetadata
.
The metadata trigger is removed by the metadata provider in the deactivate
method, as shown here for the MyadvancedMetadataProvider
class:
protected void deactivate(ComponentContext context) { ... removeMetadataTrigger( new JavaType(RooMyadvanced.class.getName())); }
Let's now look at how Spring Roo works behind the scenes to generate code when a Java type is annotated with the @RooMyadvanced
annotation.
The following sequence diagram shows how the myadvanced add-on processes the myadvanced
add
--type
sample.roo.flightapp.domain.Flight
command, where the Flight
class represents a JPA entity in your Roo project to which you want to add the @RooMyadvanced
annotation.
The figure shows that when the myadvanced
add
command is executed, the add
method of MyadvancedCommands
instance is invoked and the type
argument value is passed to the add
method. You may notice that the add
method accepts an argument of JavaType
type, but we didn't register a custom converter with the Roo shell for it. This is because Roo is responsible for converting the type
argument value to JavaType
type. The JavaType
contains the simple and package name information about the type
argument value. In our case, JavaType
argument passed to the add
method contains simple and package name information about the Flight
class that we specified as value of the type
argument. The add
method of MyadvancedCommands
invokes the annotateType
method of the MyadvancedOperationsImpl
class and passes the JavaType
instance containing information about the Flight
class. The annotateType
method annotates the Flight.java
file with the @RooMyadvanced
annotation.
Annotating Flight.java
with the @RooMyadvanced
annotation results in issuing a notification to the file monitor service of Roo that the Flight.java
file has been modified. The following sequence diagram shows how file monitor service of Roo notifies change in Flight.java
file to MetadataDependencyRegistry
:
The preceding figure shows that the file monitor service notifies PhysicalTypeMetadaProvider
that the Flight.java
file has been modified. As discussed earlier, PhysicalTypeMetadaProvider
provides metadata for a Java type in the Roo project. PhysicalTypeMetadaProvider
is notified when Flight.java
is modified because PhysicalTypeMetadaProvider
is a registered listener for file change events. After receiving the file change notification, PhysicalTypeMetadaProvider
asks MetadataDependencyRegistry
instance to inform any registered downstream dependencies. We saw earlier that MyadvancedMetadataProvider
's activate
method registers MID:com.roo.addon.myadvanced.MyadvancedMetadata
as the downstream dependency of MID:org.springframework.roo.classpath.PhysicalTypeIdentifier
. The MID:org.springframework.roo.classpath.PhysicalTypeIdentifier
represents a class-level metadata identification string created by PhysicalTypeMetadataProvider
and represents a Java type in the Roo project. So, the change in Flight.java
results in notifying the metadata provider that creates the MID:com.roo.addon.myadvanced.MyadvancedMetadata
metadata identification string, which is MyadvancedMetadataProvider
.
The following sequence diagram shows how MetadataDependencyRegistry
notifies MyadvancedMetadataProvider
to create MyadvancedMetadata
:
In the preceding figure, MetadataProvider
represents an interface that is implemented by all the metadata providers in Roo, and MetadataItem
represents the metadata that is created by MetadataProvider
implementations. In the case of the myadvanced add-on, MyadvancedMetadataProvider
implements the MetadataProvider
interface and MyadvancedMetadata
implements the MetadataItem
interface.
The previous sequence diagram shows that MetadataDependencyRegistry
notifies MetadataService
to inform the MetadataProvider
(which is MyadvancedMetadataProvider
in the case of the myadvanced add-on) of the downstream dependency.
MetadataService
is a central service in Roo which knows about all the metadata providers in the system. You don't need to register your metadata providers with MetadataService
because it
can automatically detect an OSGi service as a metadata provider if it implements the MetadataProvider
interface.
A MetadataItem
(which is MyadvancedMetadata
in the case of the myadvanced add-on) is created when MetadataProvider
(which is MyadvancedMetadataProvider
in the case of the myadvanced add-on) of the downstream dependency is notified, as we'll see shortly. MetadataService
makes use of the MetadataIdentificationUtils
utility class to obtain the MetadataProvider
class corresponding to the metadata identification string of the downstream dependency. Once the MetadataProvider
for the downstream dependency is obtained, MetadataService
notifies the MetadataProvider
.
The MetadataProvider
needs to know the Java type for which the MetadataItem
is to be created. For instance, in the case of the myadvanced add-on example, MyadvancedMetadataProvider
needs to know that MyadvancedMetadata
needs to be created corresponding to the Flight.java
class. MetadataProvider
converts class-level MID (MID:com.roo.addon.myadvanced.MyadvancedMetadata
) of downstream dependency into instance-level MID (MID:com.roo.addon.myadvanced.MyadvancedMetadata
#SRC_MAIN_JAVA?sample.roo.flightapp.domain.Flight
) to identify the Java type for which the MetadataItem
is to be created. When the MetadataItem
instance is created, it results in code generation.
Now let's look at some of the methods of MyadvancedMetadataProvider
, which play an important role in creating the MyadvancedMetadata
instance:
import ...roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem; ... public final class MyadvancedMetadataProvider extends AbstractItdMetadataProvider { ... protected ItdTypeDetailsProvidingMetadataItem getMetadata(String metadataIdentificationString, JavaType aspectName, PhysicalTypeMetadata governorPhysicalTypeMetadata, String itdFilename) { return new MyadvancedMetadata(metadataIdentificationString, aspectName, governorPhysicalTypeMetadata); } public String getItdUniquenessFilenameSuffix() { return "Myadvanced"; } protected String getGovernorPhysicalTypeIdentifier( String metadataIdentificationString) { JavaType javaType = MyadvancedMetadata. getJavaType(metadataIdentificationString); Path path = MyadvancedMetadata. getPath(metadataIdentificationString); return PhysicalTypeIdentifier.createIdentifier(javaType, path); } protected String createLocalIdentifier(JavaType javaType, Path path) { return MyadvancedMetadata.createIdentifier(javaType, path); } public String getProvidesType() { return MyadvancedMetadata.getMetadataIdentiferType(); } }
The MyadvancedMetadataProvider
class extends the AbstractItdMetadataProvider
abstract class and makes use of the template method design pattern. The methods shown in the preceding code are invoked by the concrete methods defined in the AbstractItdMetadataProvider
class. The following table describes the purpose of each of these methods:
The getMetadata
method is responsible for creating the MyadvancedMetadata
by passing information that MyadvancedMetadata
is dependent upon. The following table describes the arguments passed to the getMetadata
method:
Method argument |
Description |
---|---|
This represents instance-level metadata for
| |
This represents a | |
Represents the | |
This represents the name of the AspectJ ITD file that |
Now, let's look at the MyadvancedMetadata
class that is responsible for creating the AspectJ ITD file and adding methods and fields to it.
The following code shows the MyadvancedMetadata
class:
public class MyadvancedMetadata extends AbstractItdTypeDetailsProvidingMetadataItem { private static final String PROVIDES_TYPE_STRING = MyadvancedMetadata.class.getName(); private static final String PROVIDES_TYPE = MetadataIdentificationUtils.create(PROVIDES_TYPE_STRING); public MyadvancedMetadata(String identifier, JavaType aspectName, PhysicalTypeMetadata governorPhysicalTypeMetadata) { super(identifier, aspectName, governorPhysicalTypeMetadata); builder.addField(getSampleField()); builder.addMethod(getSampleMethod()); itdTypeDetails = builder.build(); } private FieldMetadata getSampleField() { ... } private MethodMetadata getSampleMethod() { ... } ... public static final String getMetadataIdentiferType() { return PROVIDES_TYPE; } ... }
The preceding code shows that MyadvancedMetadata
defines two constants and a couple of methods. The PROVIDES_TYPE_STRING
constant refers to the fully-qualified name of the MyadvancedMetadata
class and PROVIDES_TYPE
refers to the metadata type provided by the MyadvancedMetadata
class. The value of PROVIDES_TYPE
is MID:com.roo.addon.myadvanced.MyadvancedMetadata
.
MyadvancedMetadata
extends the AbstractItdTypeDetailsProvidingMetadataItem
abstract class, which provides the common functionality for add-ons that want to create an AspectJ ITD file corresponding to a Java type. The constructor of MyadvancedMetatada
makes use of information passed by the MyadvancedMetadataProvider
to create the AspectJ ITD file. To simplify creation of AspectJ ITD file, Roo's ItdTypeDetailsBuilder
instance (represented by the builder
variable in the constructor) is used. The addField
and addMethod
methods of ItdTypeDetailsBuilder
are used to add information about fields and methods that form part of the AspectJ ITD. The getSampleField
and getSampleMethod
methods in the above code return FieldMetadata
and MethodMetadata
, which represent the field and method to be added to the AspectJ ITD.
The following code shows the getSampleField
method of MyadvancedMetadata
class:
private FieldMetadata getSampleField() {
int modifier = 0;
FieldMetadataBuilder fieldBuilder =
new FieldMetadataBuilder(getId(),
modifier,
new ArrayList<AnnotationMetadataBuilder>(),
new JavaSymbolName("sampleField"),
JavaType.STRING_OBJECT);
return fieldBuilder.build();
}
Roo's FieldMetadataBuilder
is used to create a FieldMetadata
instance. The following are the details of the arguments passed to the FieldMetadataBuilder
constructor:
getId()
: identifies the Java type into which the field will be introduced by the AspectJ ITDmodifier
: represents the access modifier for the fieldnew
ArrayList<AnnotationMetadataBuilder>()
: contains information about the annotations that must be added to the fieldnew
JavaSymbolName("sampleField")
: name of the fieldJavaType.STRING_OBJECT
: Java type of the fieldSimilarly, the getSampleMethod
method of MyadvancedMetadata
makes use of Roo's MethodMetadataBuilder
to create an instance of MethodMetadata
.
Now that you know how the myadvanced add-on works, you can use it in your Roo project the same way we used the mysimple add-on.
Roo provides a metadata
for
type
command to view metadata for a Java type. You can also use the metadata
trace
command to see how metadata event notifications happen.
3.144.30.236