Just An Application

November 2, 2009

An Extended NewAnnotation Wizard For Eclipse: Creating The Annotation

By default, for a class inheriting from NewTypeWizardPage, the creation of the Java type is performed by the inherited method

    public void createType(IProgressMonitor monitor)

This method in turn calls

    protected void createTypeMembers(
                       IType            newType,
                       ImportsManager   imports,
                       IProgressMonitor monitor)
                   throws 
                       CoreException

which is documented as a hook method, and it is this method which the example in the documentation overrides.

To create the annotated definition we need to add the referenced Annotation types and Enums to the list of imports and annotate the created Annotation. Both the created type, in this case the Annotation, and the ImportsManager are being passed to the hook method, so it looks as though it should be possible to do what is necessary by overriding this method.

Adding the imports to the ImportsManager is easily done.


        ...

        if (documented)
        {
            imports.addImport(DOCUMENTED_ANNOTATION_TYPE);
        }
        if (inherited)
        {
            imports.addImport(INHERITED_ANNOTATION_TYPE);
        }
        switch (retention)
        {
            case CLASS:
				
                break;
				
                default:
				
                    imports.addImport(RETENTION_ANNOTATION_TYPE);
                    imports.addImport(RETENTION_POLICY_ENUM_TYPE);
        }
        if (targets.size() != 0)
        {
            imports.addImport(TARGET_ANNOTATION_TYPE);
            imports.addImport(ELEMENT_TYPE_ENUM_TYPE);
        }

        ...

with the constants being defined as follows


        private static final String DOCUMENTED_ANNOTATION_TYPE	= "java.lang.annotation.Documented";
	
        private static final String INHERITED_ANNOTATION_TYPE	= "java.lang.annotation.Inherited";
	
        private static final String RETENTION_ANNOTATION_TYPE	= "java.lang.annotation.Retention";
	
        private static final String TARGET_ANNOTATION_TYPE      = "java.lang.annotation.Target";
	
        private static final String ELEMENT_TYPE_ENUM_TYPE      = "java.lang.annotation.ElementType";
	
        private static final String RETENTION_POLICY_ENUM_TYPE	= "java.lang.annotation.RetentionPolicy";

For the Documented and Inherited meta-annotations only the Annotation types themselves need to be imported. In the Retention and Target cases the Enum value types are also imported.

Adding the Annotations themselves to the newly created type turns out to be more difficult. The IType interface extends the IAnnotable amongst others, but none of the methods on IAnnotable or any of the super-interfaces, or on IType itself apparently enable the addition of Annotations.

It is entirely possible that somewhere in the maze of twisty little interfaces there is a way to do so, but I have yet to stumble upon it.

In the end, following a good deal of random experimentation I discovered the


    protected String constructCUContent(
                         ICompilationUnit cu,
                         String           typeContent,
                         String           lineDelimiter)
                     throws 
                         CoreException
 

method on NewTypeWizardPage.

The typeContent argument contains the source of the annotation as created.

Overriding this method modifying the typeContent argument and then invoking the overridden method turns out to have the required effect.


        @Override
        protected String constructCUContent(
                             ICompilationUnit 	theCompilationUnit,
                             String             theTypeContent, 
                             String             theLineDelimiter) 
                         throws 
                             CoreException 
        {	
            StringBuilder builder = new StringBuilder();
		
            if (documented)
            {
                builder.append("@Documented ");
            }
            if (inherited)
            {
                builder.append("@Inherited ");
            }
            switch (retention)
            {
                case CLASS:
			
                    break;
				
                default:
				
                    builder.append("@Retention(RetentionPolicy.");
                    builder.append(retention);
                    builder.append(") ");
            }
		
            int nTargets = targets.size();
		
            if (nTargets != 0)
            {
                builder.append("@Target(");
			
                if (nTargets != 1)
                {
                    boolean first = true;
				
                    builder.append("{");
                    for (ElementType type : targets)
                    {
                        if (!first)
                        {
                            builder.append(", ");
                        }
                        else
                        {
                            first = false;
                        }
                        builder.append("ElementType.");
                        builder.append(type);
                    }
                    builder.append("}");
                }
                else
                {
                    for (ElementType type : targets)
                    {
                        builder.append("ElementType.");
                        builder.append(type);
                    }
                }
                builder.append(") ");
            }
            builder.append(theTypeContent);
            return super.constructCUContent(theCompilationUnit,  builder.toString(), theLineDelimiter);
        }

In CLOS this would have been an :around method. Sigh …


Copyright (c) 2009 By Simon Lewis. All Rights Reserved

Advertisements

1 Comment »

  1. You have no idea how useful this has been to me! I’m currently working on an eclipse plugin at work and I’ve been struggling to figure out how to set up my wizard to do what I want it to do. Your posts are fantastic!

    Comment by James Ravenscroft — November 16, 2011 @ 2:27 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: