Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/grammar/lexer.flex =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/grammar/lexer.flex (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/grammar/lexer.flex (working copy) @@ -22,6 +22,7 @@ private boolean javaDocNewLine; private boolean javaDocStartedContent; private StringBuffer codeBody = new StringBuffer(8192); + private boolean annoExpected; private boolean newMode; private boolean enumMode; private boolean appendingToCodeBody; @@ -67,8 +68,15 @@ Eol = \r|\n|\r\n WhiteSpace = {Eol} | [ \t\f] CommentChar = ( [^ \t\r\n*] | "*"+ [^ \t\r\n/*] ) +IntegerLiteral = (( [1-9] ([0-9])* ) | ( "0" [xX] ([0-9]|[a-f]|[A-F])+ ) | ( "0" ([0-7])* )) ([lL])? +Exponent = [eE] [+-]? ([0-9])+ +FloatLiteral = ( [0-9]+ ("." [0-9]+)? ({Exponent})? ([fFdD])? ) | + ( "." [0-9]+ ({Exponent})? ([fFdD])? ) | + ( ([0-9])+ {Exponent} ([fFdD])? ) | + ( ([0-9])+ ({Exponent})? [fFdD] ) +Id = [:jletter:] [:jletterdigit:]* -%state JAVADOC CODEBLOCK PARENBLOCK ASSIGNMENT STRING CHAR SINGLELINECOMMENT MULTILINECOMMENT +%state JAVADOC CODEBLOCK PARENBLOCK ASSIGNMENT STRING CHAR SINGLELINECOMMENT MULTILINECOMMENT ANNOTATION ANNOSTRING ANNOCHAR %% @@ -101,6 +109,7 @@ "]" { nestingDepth--; return Parser.SQUARECLOSE; } "(" { nestingDepth++; + if( annoExpected ) { pushState(ANNOTATION); } if (enumMode) { pushState(PARENBLOCK); } else { @@ -113,21 +122,28 @@ ">" { return Parser.GREATERTHAN; } "&" { return Parser.AMPERSAND; } "?" { return Parser.QUERY; } - "@" { return Parser.AT; } + "@" { + return Parser.AT; + } + "class" { classDepth++; return Parser.CLASS; } "interface" { classDepth++; - return Parser.INTERFACE; + return Parser.INTERFACE; } "enum" { classDepth++; enumMode = true; return Parser.ENUM; } + "@" {WhiteSpace}* "interface" { + classDepth++; + return Parser.ANNOINTERFACE; + } "{" { nestingDepth++; @@ -165,10 +181,15 @@ pushState(ASSIGNMENT); } - [:jletter:] [:jletterdigit:]* { - return Parser.IDENTIFIER; + [:jletter:] [:jletterdigit:]* { + annoExpected = false; + return Parser.IDENTIFIER; } + "@" {WhiteSpace}* {Id} ( {WhiteSpace}* "." {WhiteSpace}* {Id} )* { + annoExpected = true; + return Parser.ANNOTATION; + } } { @@ -202,13 +223,60 @@ } } + { + "(" { nestingDepth++; return Parser.PARENOPEN; } + ")" { if( --nestingDepth == classDepth) { popState(); } return Parser.PARENCLOSE; } + + "," { return Parser.COMMA; } + "=" { return Parser.EQUALS; } + + "{" { nestingDepth++; return Parser.BRACEOPEN; } + "}" { nestingDepth--; return Parser.BRACECLOSE; } + + "\"" { appendingToCodeBody=true; codeBody.append("\""); pushState(ANNOSTRING); } + \' { appendingToCodeBody=true; codeBody.append("\'"); pushState(ANNOCHAR); } + + "." { return Parser.DOT; } + + "<" { return Parser.LESSTHAN; } + ">" { return Parser.GREATERTHAN; } + "*" { return Parser.STAR; } + "/" { return Parser.SLASH; } + "+" { return Parser.PLUS; } + "-" { return Parser.MINUS; } + + {IntegerLiteral} { return Parser.INTEGER_LITERAL; } + {FloatLiteral} { return Parser.FLOAT_LITERAL; } + "true" | "false" { return Parser.BOOLEAN_LITERAL; } + + [:jletter:] [:jletterdigit:]* { + return Parser.IDENTIFIER; + } + + "@" {WhiteSpace}* [:jletter:] [:jletterdigit:]* { + return Parser.ANNOTATION; + } + + { + "\"" { codeBody.append("\""); popState(); appendingToCodeBody=false; return Parser.ANNOSTRING; } + "\\\"" { codeBody.append("\\\""); } + "\\\\" { codeBody.append("\\\\"); } + } + + { + \' { codeBody.append("\'"); popState(); appendingToCodeBody=false; return Parser.ANNOCHAR; } + "\\'" { codeBody.append("\\'"); } + "\\\\" { codeBody.append("\\\\"); } + } +} + { "(" { nestingDepth++; } ")" { - nestingDepth--; + nestingDepth--; if (nestingDepth == classDepth) { popState(); - return Parser.PARENBLOCK; + return Parser.PARENBLOCK; } } } Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/grammar/parser.y =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/grammar/parser.y (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/grammar/parser.y (working copy) @@ -2,19 +2,22 @@ import com.thoughtworks.qdox.parser.*; import com.thoughtworks.qdox.parser.structs.*; import java.io.IOException; +import java.util.LinkedList; %} -%token SEMI DOT DOTDOTDOT COMMA STAR EQUALS +%token SEMI DOT DOTDOTDOT COMMA STAR EQUALS ANNOSTRING ANNOCHAR SLASH PLUS MINUS %token PACKAGE IMPORT PUBLIC PROTECTED PRIVATE STATIC FINAL ABSTRACT NATIVE STRICTFP SYNCHRONIZED TRANSIENT VOLATILE -%token CLASS INTERFACE ENUM THROWS EXTENDS IMPLEMENTS SUPER DEFAULT +%token CLASS INTERFACE ENUM ANNOINTERFACE THROWS EXTENDS IMPLEMENTS SUPER DEFAULT %token BRACEOPEN BRACECLOSE SQUAREOPEN SQUARECLOSE PARENOPEN PARENCLOSE LESSTHAN GREATERTHAN AMPERSAND QUERY AT %token JAVADOCSTART JAVADOCEND JAVADOCEOL %token CODEBLOCK PARENBLOCK -%token INTEGER_LITERAL FLOAT_LITERAL // strongly typed tokens/types -%token IDENTIFIER JAVADOCTAG JAVADOCTOKEN +%token IDENTIFIER JAVADOCTAG JAVADOCTOKEN ANNOTATION +%token BOOLEAN_LITERAL INTEGER_LITERAL FLOAT_LITERAL %type fullidentifier modifier classtype typedeclspecifier typename memberend +%type annotationValueConstant annotationSymConstant +%type annoElementValue %type dimensions %type varargs %type type arrayidentifier @@ -81,7 +84,7 @@ dimensions: /* empty */ { $$ = 0; } -| dimensions SQUAREOPEN SQUARECLOSE { + | dimensions SQUAREOPEN SQUARECLOSE { $$ = $1 + 1; }; @@ -105,20 +108,82 @@ ; -// ----- ANNOTATIONS +// ----- ANNOTATIONS +annotationValueConstant: + FLOAT_LITERAL { $$ = $1; } | + INTEGER_LITERAL { $$ = $1; } | + BOOLEAN_LITERAL { $$ = $1; } | + fullidentifier { $$ = $1; } | + fullidentifier DOT CLASS { $$ = $1 + ".class"; } | + ANNOSTRING { + // would prefer to set this as a returned token in flex... how? + String str = lexer.getCodeBody(); + str = str.substring( 1, str.length() - 1 ); + $$ = str; + } | + ANNOCHAR { + String str = lexer.getCodeBody(); + str = str.substring( 1, str.length() - 1 ); + $$ = str; + }; + +annotationSymConstant: + LESSTHAN { $$ = "<"; } | + GREATERTHAN { $$ = ">"; } | + STAR { $$ = "*"; } | + SLASH { $$ = "/"; } | + PLUS { $$ = "+"; } | + MINUS { $$ = "/"; }; + +annotationValueConstants: + annotationValueConstant { + annoConstants.add( $1 ); + } | annotationValueConstants annotationSymConstant annotationValueConstant { + annoConstants.add( $2 ); + annoConstants.add( $3 ); + }; + annotation: - AT IDENTIFIER | - AT IDENTIFIER PARENOPEN annotationarglist PARENCLOSE; - -annotationarglist: - | - annotationarglist COMMA | - annotationarglist fullidentifier | - annotationarglist fullidentifier DOT CLASS | - annotationarglist BRACEOPEN annotationarglist BRACECLOSE; /* array */ | - annotationarglist annotation; + { ano = new AnnoDef(); } annotationWork { builder.addAnnotation(ano); }; +annotationWork: + ANNOTATION { + ano.lineNumber = line; + ano.name = $1.substring(1).trim(); + } annoParens; + +annoParens: + | + PARENOPEN annoParenContents PARENCLOSE; + +annoParenContents: + annoElementValue { ano.args.put( "value", $1 ); } | + annoElementValuePairs; + +annoElementValuePairs: + annoElementValuePair | + annoElementValuePairs COMMA annoElementValuePair; + +annoElementValuePair: + IDENTIFIER EQUALS annoElementValue { ano.args.put( $1, $3 ); }; + +annoElementValue: + PARENOPEN annoElementValue PARENCLOSE { $$ = $2; } | + annotationValueConstants { $$ = annoConstants; annoConstants = new LinkedList(); } | + { AnnoDef tmpAno = new AnnoDef(); + tmpAno.tempAnno = ano; + ano = tmpAno; + } annotationWork { $$ = ano; ano = ano.tempAnno; } | + annoElementValueArrayInitializer { $$ = annoValues; annoValues = new LinkedList(); }; + +annoElementValueArrayInitializer: + BRACEOPEN annoElementValues BRACECLOSE; + +annoElementValues: + annoElementValue { annoValues.add( $1 ); } | + annoElementValues COMMA annoElementValue { annoValues.add( $3 ); }; + // ----- TYPES type: @@ -216,7 +281,7 @@ classorinterface: CLASS { cls.type = ClassDef.CLASS; } | INTERFACE { cls.type = ClassDef.INTERFACE; } | - AT INTERFACE { cls.type = ClassDef.ANNOTATION_TYPE; }; + ANNOINTERFACE { cls.type = ClassDef.ANNOTATION_TYPE; }; opt_extends: | EXTENDS extendslist; @@ -344,6 +409,7 @@ private StringBuffer textBuffer = new StringBuffer(); private ClassDef cls = new ClassDef(); private MethodDef mth = new MethodDef(); +private AnnoDef ano = new AnnoDef(); private FieldDef param = new FieldDef(); private java.util.Set modifiers = new java.util.HashSet(); private TypeDef fieldType; @@ -351,6 +417,9 @@ private int column; private boolean debugLexer; +private LinkedList annoConstants = new LinkedList(); +private LinkedList annoValues = new LinkedList(); + private void appendToBuffer(String word) { if (textBuffer.length() > 0) { char lastChar = textBuffer.charAt(textBuffer.length() - 1); @@ -407,9 +476,10 @@ } private class Value { + Object oval; String sval; int ival; - boolean bval; + boolean bval; TypeDef type; } @@ -423,4 +493,4 @@ fd.body = body; builder.addField(fd); } - + Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/AbstractJavaEntity.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/AbstractJavaEntity.java (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/AbstractJavaEntity.java (working copy) @@ -12,6 +12,7 @@ protected List modifiers = new ArrayList(); private String comment; private DocletTag[] tags = new DocletTag[0]; + private Annotation[] annotations = new Annotation[0]; private JavaClassParent parent; private int lineNumber = -1; @@ -39,6 +40,11 @@ return tags; } + public Annotation[] getAnnotations() + { + return annotations; + } + public DocletTag[] getTagsByName(String name) { List specifiedTags = new ArrayList(); for (int i = 0; i < tags.length; i++) { @@ -139,6 +145,10 @@ tagList.toArray(this.tags); } + public void setAnnotations(Annotation[] annotations) { + this.annotations = annotations; + } + //helper methods for querying the modifiers public boolean isAbstract() { return isModifierPresent("abstract"); Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/Annotation.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/Annotation.java (revision 0) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/Annotation.java (revision 0) @@ -0,0 +1,74 @@ +package com.thoughtworks.qdox.model; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * + * @author Eric Redmond + */ +public class Annotation implements Serializable +{ + private final Type type; + private final int lineNumber; + + private Map namedParameters; + private AbstractJavaEntity context; + + public Annotation(Type type, + AbstractJavaEntity context, + Map namedParameters, + int lineNumber) + { + this.type = type; + this.context = context; + this.namedParameters = namedParameters == null ? new HashMap(0) : namedParameters; + this.lineNumber = lineNumber; + } + + /** + * @return the annotation type + */ + public Type getType() { + return type; + } + + /** + * @param key name of a named-parameter + * @return the corresponding value, + * or null if no such named-parameter was present + */ + public Object getNamedParameter(String key) { + return namedParameters.get( key ); + } + + /** + * @return a Map containing all the named-parameters + */ + public Map getNamedParameterMap() { + return namedParameters; + } + + public final AbstractJavaEntity getContext() { + return context; + } + + public int getLineNumber() { + return lineNumber; + } + + public String toString() { + StringBuffer result = new StringBuffer(); + result.append('@'); + result.append(type.getValue()); + result.append('('); + if( !namedParameters.isEmpty() ) { + for(Iterator i = namedParameters.entrySet().iterator(); i.hasNext();) result.append( i.next() + ","); + result.deleteCharAt( result.length()-1 ); + } + result.append(')'); + return result.toString(); + } +} Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/JavaClass.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/JavaClass.java (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/JavaClass.java (working copy) @@ -18,6 +18,7 @@ private static Type OBJECT = new Type("java.lang.Object"); private static Type ENUM = new Type("java.lang.Enum"); + private static Type ANNOTATION = new Type("java.lang.annotation.Annotation"); private List methods = new LinkedList(); private JavaMethod[] methodsArray; @@ -27,6 +28,7 @@ private JavaClass[] classesArray; private boolean interfce; private boolean isEnum; + private boolean isAnnotation; // Don't access this directly. Use asType() to get my Type private Type type; @@ -69,7 +71,7 @@ if (isEnum) { return ENUM; - } else if (!interfce && (superClass == null) && !iAmJavaLangObject) { + } else if (!interfce && !isAnnotation && (superClass == null) && !iAmJavaLangObject) { return OBJECT; } @@ -109,7 +111,7 @@ writeAccessibilityModifier(result); writeNonAccessibilityModifiers(result); - result.write(isEnum ? "enum " : interfce ? "interface " : "class "); + result.write(isEnum ? "enum " : interfce ? "interface " : isAnnotation ? "@interface " : "class "); result.write(name); // subclass @@ -173,6 +175,10 @@ this.isEnum = isEnum; } + public void setAnnotation(boolean isAnnotation) { + this.isAnnotation = isAnnotation; + } + public void addMethod(JavaMethod meth) { meth.setParent(this); methods.add(meth); Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/ModelBuilder.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/ModelBuilder.java (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/model/ModelBuilder.java (working copy) @@ -1,17 +1,20 @@ package com.thoughtworks.qdox.model; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + import com.thoughtworks.qdox.parser.Builder; +import com.thoughtworks.qdox.parser.structs.AnnoDef; import com.thoughtworks.qdox.parser.structs.ClassDef; import com.thoughtworks.qdox.parser.structs.FieldDef; import com.thoughtworks.qdox.parser.structs.MethodDef; import com.thoughtworks.qdox.parser.structs.TagDef; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - /** * @author Joe Walnes */ @@ -21,6 +24,7 @@ private final JavaSource source; private JavaClassParent currentParent; private JavaClass currentClass; + private List currentAnnoDefs; private String lastComment; private List lastTagSet; private DocletTagFactory docletTagFactory; @@ -35,6 +39,7 @@ source = new JavaSource(); source.setClassLibrary(classLibrary); currentParent = source; + currentAnnoDefs = new ArrayList(); } public void addPackage(String packageName) { @@ -63,7 +68,9 @@ currentClass.setName(def.name); currentClass.setInterface(ClassDef.INTERFACE.equals(def.type)); currentClass.setEnum(ClassDef.ENUM.equals(def.type)); + currentClass.setAnnotation(ClassDef.ANNOTATION_TYPE.equals(def.type)); + // superclass if (currentClass.isInterface()) { currentClass.setSuperClass(null); @@ -92,11 +99,15 @@ // javadoc addJavaDoc(currentClass); - // ignore annotation types (for now) - if (ClassDef.ANNOTATION_TYPE.equals(def.type)) { - return; - } - +// // ignore annotation types (for now) +// if (ClassDef.ANNOTATION_TYPE.equals(def.type)) { +// System.out.println( currentClass.getFullyQualifiedName() ); +// return; +// } + + // annotations + setAnnotations( currentClass ); + currentParent.addClass(currentClass); currentParent = currentClass; classLibrary.add(currentClass.getFullyQualifiedName()); @@ -180,6 +191,9 @@ // javadoc addJavaDoc(currentMethod); + // annotations + setAnnotations( currentMethod ); + currentClass.addMethod(currentMethod); } @@ -204,9 +218,59 @@ // javadoc addJavaDoc(currentField); + // annotations + setAnnotations( currentField ); + currentClass.addField(currentField); } + private void setAnnotations( AbstractJavaEntity entity ) { + if( !currentAnnoDefs.isEmpty() ) { + Annotation[] annotations = new Annotation[currentAnnoDefs.size()]; + int index = 0; + for (Iterator iter = currentAnnoDefs.iterator(); iter.hasNext();) { + AnnoDef def = (AnnoDef)iter.next(); + annotations[index++] = buildAnnotation( def, entity ); + } + + entity.setAnnotations( annotations ); + currentAnnoDefs.clear(); + } + } + + private Annotation buildAnnotation( AnnoDef def, AbstractJavaEntity entity ) { + Type annoType = createType(def.name, 0); + + Map args = new HashMap(); + for (Iterator iter = def.args.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = (Map.Entry)iter.next(); + Object value = entry.getValue(); + + if( value instanceof AnnoDef ) { + args.put( entry.getKey(), buildAnnotation( (AnnoDef)value, entity ) ); + } + else if( value instanceof List ) { + List values = (List)value; + if( values.size() == 1 ) { + // TODO: what about types? + args.put( entry.getKey(), values.get( 0 ) ); + } + else { + args.put( entry.getKey(), values ); + } + } + } + + Annotation anno = new Annotation( annoType, entity, args, def.lineNumber ); + return anno; + } + + + // Don't resolve until we need it... class hasn't been defined yet. + public void addAnnotation( AnnoDef def ) { + currentAnnoDefs.add( def ); + } + public JavaSource getSource() { return source; } Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/parser/Builder.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/parser/Builder.java (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/parser/Builder.java (working copy) @@ -1,5 +1,6 @@ package com.thoughtworks.qdox.parser; +import com.thoughtworks.qdox.parser.structs.AnnoDef; import com.thoughtworks.qdox.parser.structs.ClassDef; import com.thoughtworks.qdox.parser.structs.FieldDef; import com.thoughtworks.qdox.parser.structs.MethodDef; @@ -23,4 +24,5 @@ void addField(FieldDef def); + void addAnnotation(AnnoDef def); } Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/parser/structs/AnnoDef.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/parser/structs/AnnoDef.java (revision 0) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/java/com/thoughtworks/qdox/parser/structs/AnnoDef.java (revision 0) @@ -0,0 +1,34 @@ +package com.thoughtworks.qdox.parser.structs; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class AnnoDef extends LocatedDef +{ + public String name = ""; + public Map args = new HashMap(); + public AnnoDef tempAnno = null; // holds an annotation to construct nested values + + public boolean equals(Object obj) { + AnnoDef annoDef = (AnnoDef) obj; + return annoDef.name.equals(name) && annoDef.args.equals(args); + } + + public int hashCode() { + return name.hashCode() + args.hashCode(); + } + + public String toString() { + StringBuffer result = new StringBuffer(); + result.append('@'); + result.append(name); + result.append('('); + if( !args.isEmpty() ) { + for(Iterator i = args.entrySet().iterator(); i.hasNext();) result.append( i.next() + ","); + result.deleteCharAt( result.length()-1 ); + } + result.append(')'); + return result.toString(); + } +} Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/AnnotationsTest.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/AnnotationsTest.java (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/AnnotationsTest.java (working copy) @@ -1,12 +1,21 @@ package com.thoughtworks.qdox; -import com.thoughtworks.qdox.model.JavaClass; import java.io.StringReader; + import junit.framework.TestCase; +import com.thoughtworks.qdox.model.JavaClass; +import com.thoughtworks.qdox.model.Type; + public class AnnotationsTest extends TestCase { - private JavaDocBuilder builder = new JavaDocBuilder(); + private JavaDocBuilder builder; + public AnnotationsTest() + { + builder = new JavaDocBuilder(); + //builder.setDebugLexer( true ); + //builder.setDebugParser( true ); + } public void testShouldIgnoreSimpleClassAnnotation() { String source = "" @@ -33,6 +42,7 @@ public void testShouldIgnoreMethodParameterAnnotation() { String source = "" + "public class X {\n" + + " String field = new String( \"hey\" );\n" + " public void setX(@name String x) {}\n" + "}\n"; @@ -70,10 +80,10 @@ } public void testShouldIgnoreArrayValuedSingleMemberClassAnnotations() { - String source = "" - + "@Endorsers({\"Children\", \"Unscrupulous dentists\"})\n" + String source = "" /** @hey=\"yo\" someval = \"yep\" */ + + "@ Endorsers({(\"Children\"), \"Unscrupulous dentists\"})\n" + "public class Lollipop {\n" - + " @Cheese({\"Edam\", \"Gruyere\"})\n" + + " @Cheese( hey=@ano({\"Edam\", \"Gruyere\", 2}), t=5.5f, c=4)\n" + " void doStuff() { }\n" + "}\n"; @@ -83,24 +93,29 @@ public void testShouldIgnoreComplexSingleMemberClassAnnotations() { String source = "" - + "@Author(@Name(first = \"Joe\", last = \"Hacker\"))\n" // I won't take it personally! ;) -joe + + "@Author(@Name(first = \"Joe\", last = true))\n" // I won't take it personally! ;) -joe + "public class BitTwiddle {\n" - + " @Author(@Name(first = \"Joe\", last = \"Hacker\"))\n" + + " @Author(@Name(first = \'c\', last = 2.5e3f))\n" + " void doStuff() { }\n" + "}\n"; builder.addSource(new StringReader(source)); assertNotNull(builder.getClassByName("BitTwiddle")); + assertNotNull( builder.getClassByName("BitTwiddle").getAnnotations()[0].getNamedParameter("value") ); + assertEquals( "Author", builder.getClassByName("BitTwiddle") + .getMethodBySignature("doStuff", new Type[] {}) + .getAnnotations()[0].getType().getValue() ); } public void testShouldIgnoreAnnotationDeclaration() { - String source = "" + String source = "package org.jabba;\n" + + "@MyAnno\n" + "public @interface Note {\n" + " String text;\n" + "}\n"; builder.addSource(new StringReader(source)); - assertEquals(0, builder.getClasses().length); + assertEquals(1, builder.getClasses().length); } public void testShouldIgnoreAnnotationWithClassType() { @@ -138,6 +153,13 @@ assertEquals("Person", builder.getClassByName("Person").getName()); } + // from QDOX-108 + public void testFQNAnnotations() { + String source = "" + + "@com.mycompany.Fnord(a=1)\n" + + "public interface Foo extends Bar {}\n"; - + builder.addSource(new StringReader(source)); + assertEquals("Foo", builder.getClassByName("Foo").getName()); + } } Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/model/ModelBuilderTest.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/model/ModelBuilderTest.java (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/model/ModelBuilderTest.java (working copy) @@ -88,7 +88,7 @@ JavaSource source = builder.getSource(); - assertEquals(0, source.getClasses().length); + assertEquals(1, source.getClasses().length); } public void testClassExtends() throws Exception { Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/parser/LexerTest.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/parser/LexerTest.java (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/parser/LexerTest.java (working copy) @@ -528,8 +528,7 @@ Lexer lexer = new JFlexLexer(new StringReader(in)); assertLex(Parser.PUBLIC, lexer); - assertLex(Parser.AT, lexer); - assertLex(Parser.INTERFACE, lexer); + assertLex(Parser.ANNOINTERFACE, lexer); assertLex(Parser.IDENTIFIER, "Copyright", lexer); assertLex(Parser.BRACEOPEN, lexer); assertLex(Parser.IDENTIFIER, "int", lexer); @@ -553,16 +552,19 @@ + "public class LexerTest extends TestCase {}\n"; Lexer lexer = new JFlexLexer(new StringReader(in)); - assertLex(Parser.AT, lexer); - assertLex(Parser.IDENTIFIER, "Copyright", lexer); + assertLex(Parser.ANNOTATION, "@Copyright", lexer); assertLex(Parser.PARENOPEN, lexer); assertLex(Parser.IDENTIFIER, "year", lexer); + assertLex(Parser.EQUALS, lexer); + assertLex(Parser.INTEGER_LITERAL, "2004", lexer); assertLex(Parser.COMMA, lexer); assertLex(Parser.IDENTIFIER, "month", lexer); + assertLex(Parser.EQUALS, lexer); + assertLex(Parser.ANNOSTRING, lexer); assertLex(Parser.PARENCLOSE, lexer); - assertLex(Parser.AT, lexer); - assertLex(Parser.IDENTIFIER, "Note", lexer); + assertLex(Parser.ANNOTATION, "@Note", lexer); assertLex(Parser.PARENOPEN, lexer); + assertLex(Parser.ANNOSTRING, lexer); assertLex(Parser.PARENCLOSE, lexer); assertLex(Parser.PUBLIC, lexer); assertLex(Parser.CLASS, lexer); Index: C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/parser/MockBuilder.java =================================================================== --- C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/parser/MockBuilder.java (revision 457) +++ C:/Documents and Settings/eredmond/blaze/qdox2/src/test/com/thoughtworks/qdox/parser/MockBuilder.java (working copy) @@ -1,5 +1,6 @@ package com.thoughtworks.qdox.parser; +import com.thoughtworks.qdox.parser.structs.AnnoDef; import com.thoughtworks.qdox.parser.structs.ClassDef; import com.thoughtworks.qdox.parser.structs.MethodDef; import com.thoughtworks.qdox.parser.structs.FieldDef; @@ -124,6 +125,10 @@ myAddFieldParameter0Values.addActual(arg0); } + public void addAnnotation( AnnoDef def ) { + + } + public void verify() { myAddPackageCalls.verify(); myAddPackageParameter0Values.verify();