11package com .azure .tools .apiview .processor .analysers ;
22
3+ import com .azure .tools .apiview .processor .analysers .models .AnnotationRendererModel ;
4+ import com .azure .tools .apiview .processor .analysers .models .AnnotationRule ;
35import com .azure .tools .apiview .processor .analysers .util .MiscUtils ;
46import com .azure .tools .apiview .processor .analysers .util .TokenModifier ;
57import com .azure .tools .apiview .processor .diagnostics .Diagnostics ;
5153import com .github .javaparser .symbolsolver .resolution .typesolvers .CombinedTypeSolver ;
5254import com .github .javaparser .symbolsolver .resolution .typesolvers .ReflectionTypeSolver ;
5355
54- import java .io .File ;
5556import java .io .IOException ;
5657import java .nio .file .Files ;
5758import java .nio .file .Path ;
58- import java .util .Arrays ;
59- import java .util .Comparator ;
60- import java .util .HashMap ;
61- import java .util .HashSet ;
62- import java .util .List ;
63- import java .util .Map ;
64- import java .util .Optional ;
65- import java .util .Set ;
66- import java .util .TreeMap ;
59+ import java .util .*;
6760import java .util .concurrent .atomic .AtomicInteger ;
6861import java .util .function .Consumer ;
6962import java .util .regex .Matcher ;
7568import org .apache .commons .lang .StringEscapeUtils ;
7669
7770import static com .azure .tools .apiview .processor .analysers .util .ASTUtils .*;
71+ import static com .azure .tools .apiview .processor .analysers .util .MiscUtils .*;
7872import static com .azure .tools .apiview .processor .analysers .util .TokenModifier .INDENT ;
7973import static com .azure .tools .apiview .processor .analysers .util .TokenModifier .NEWLINE ;
8074import static com .azure .tools .apiview .processor .analysers .util .TokenModifier .NOTHING ;
@@ -101,8 +95,22 @@ public class JavaASTAnalyser implements Analyser {
10195 public static final String MODULE_INFO_KEY = "module-info" ;
10296
10397 private static final boolean SHOW_JAVADOC = true ;
104- private static final Set <String > BLOCKED_ANNOTATIONS =
105- new HashSet <>(Arrays .asList ("ServiceMethod" , "SuppressWarnings" ));
98+
99+ private static final Map <String , AnnotationRule > ANNOTATION_RULE_MAP ;
100+ static {
101+ /*
102+ For some annotations, we want to customise how they are displayed. Sometimes, we don't show them in any
103+ circumstance. Other times, we want to show them but not their attributes. This map is used to define these
104+ customisations. These rules override the default output that APIView will do, based on the location
105+ annotation in the code.
106+ */
107+ ANNOTATION_RULE_MAP = new HashMap <>();
108+ ANNOTATION_RULE_MAP .put ("ServiceMethod" , new AnnotationRule ().setHidden (true ));
109+ ANNOTATION_RULE_MAP .put ("SuppressWarnings" , new AnnotationRule ().setHidden (true ));
110+
111+ // we always want @Metadata annotations to be fully expanded, but in a condensed form
112+ ANNOTATION_RULE_MAP .put ("Metadata" , new AnnotationRule ().setShowProperties (true ).setCondensed (true ));
113+ }
106114
107115 private static final Pattern SPLIT_NEWLINE = Pattern .compile (MiscUtils .LINEBREAK );
108116
@@ -112,12 +120,13 @@ public class JavaASTAnalyser implements Analyser {
112120
113121 private final Map <String , JavadocComment > packageNameToPackageInfoJavaDoc = new HashMap <>();
114122
115- private final Diagnostics diagnostic = new Diagnostics () ;
123+ private final Diagnostics diagnostic ;
116124
117125 private int indent = 0 ;
118126
119127 public JavaASTAnalyser (APIListing apiListing ) {
120128 this .apiListing = apiListing ;
129+ diagnostic = new Diagnostics (apiListing );
121130 }
122131
123132 @ Override
@@ -1032,34 +1041,24 @@ private void getAnnotations(final NodeWithAnnotations<?> nodeWithAnnotations,
10321041 final boolean showAnnotationProperties ,
10331042 final boolean addNewline ) {
10341043 Consumer <AnnotationExpr > consumer = annotation -> {
1035- if (addNewline ) {
1036- addToken (makeWhitespace ());
1037- }
1038-
1039- addToken (new Token (TYPE_NAME , "@" + annotation .getName ().toString (), makeId (annotation , nodeWithAnnotations )));
1040- if (showAnnotationProperties ) {
1041- if (annotation instanceof NormalAnnotationExpr ) {
1042- addToken (new Token (PUNCTUATION , "(" ));
1043- NodeList <MemberValuePair > pairs = ((NormalAnnotationExpr ) annotation ).getPairs ();
1044- for (int i = 0 ; i < pairs .size (); i ++) {
1045- MemberValuePair pair = pairs .get (i );
1046-
1047- addToken (new Token (TEXT , pair .getNameAsString ()));
1048- addToken (new Token (PUNCTUATION , " = " ));
1044+ // Check the annotation rules map for any overrides
1045+ final String annotationName = annotation .getName ().toString ();
1046+ AnnotationRule annotationRule = ANNOTATION_RULE_MAP .get (annotationName );
10491047
1050- Expression valueExpr = pair . getValue ();
1051- processAnnotationValueExpression ( valueExpr );
1048+ AnnotationRendererModel model = new AnnotationRendererModel (
1049+ annotation , nodeWithAnnotations , annotationRule , showAnnotationProperties , addNewline );
10521050
1053- if (i < pairs .size () - 1 ) {
1054- addToken (new Token (PUNCTUATION , ", " ));
1055- }
1056- }
1051+ if (model .isHidden ()) {
1052+ return ;
1053+ }
10571054
1058- addToken ( new Token ( PUNCTUATION , ")" ));
1059- }
1055+ if ( model . isAddNewline ()) {
1056+ addToken ( makeWhitespace ());
10601057 }
10611058
1062- if (addNewline ) {
1059+ renderAnnotation (model ).forEach (JavaASTAnalyser .this ::addToken );
1060+
1061+ if (model .isAddNewline ()) {
10631062 addNewLine ();
10641063 } else {
10651064 addToken (new Token (WHITESPACE , " " ));
@@ -1070,43 +1069,96 @@ private void getAnnotations(final NodeWithAnnotations<?> nodeWithAnnotations,
10701069 .stream ()
10711070 .filter (annotationExpr -> {
10721071 String id = annotationExpr .getName ().getIdentifier ();
1073- return !BLOCKED_ANNOTATIONS . contains ( id ) && ! id .startsWith ("Json" );
1072+ return !id .startsWith ("Json" );
10741073 })
10751074 .sorted (Comparator .comparing (a -> a .getName ().getIdentifier ())) // we sort the annotations alphabetically
10761075 .forEach (consumer );
10771076 }
10781077
1079- private void processAnnotationValueExpression (Expression valueExpr ) {
1078+ private List <Token > renderAnnotation (AnnotationRendererModel m ) {
1079+ final AnnotationExpr a = m .getAnnotation ();
1080+ List <Token > tokens = new ArrayList <>();
1081+ tokens .add (new Token (TYPE_NAME , "@" + a .getNameAsString (), makeId (a , m .getAnnotationParent ())));
1082+ if (m .isShowProperties ()) {
1083+ if (a instanceof NormalAnnotationExpr ) {
1084+ tokens .add (new Token (PUNCTUATION , "(" ));
1085+ NodeList <MemberValuePair > pairs = ((NormalAnnotationExpr ) a ).getPairs ();
1086+ for (int i = 0 ; i < pairs .size (); i ++) {
1087+ MemberValuePair pair = pairs .get (i );
1088+
1089+ // If the pair is a boolean expression, and we are condensed, we only take the name.
1090+ // If we are not a boolean expression, and we are condensed, we only take the value.
1091+ // If we are not condensed, we take both.
1092+ final Expression valueExpr = pair .getValue ();
1093+ if (m .isCondensed ()) {
1094+ if (valueExpr .isBooleanLiteralExpr ()) {
1095+ tokens .add (new Token (MEMBER_NAME , upperCase (pair .getNameAsString ())));
1096+ } else {
1097+ processAnnotationValueExpression (valueExpr , m .isCondensed (), tokens );
1098+ }
1099+ } else {
1100+ tokens .add (new Token (MEMBER_NAME , pair .getNameAsString ()));
1101+ tokens .add (new Token (PUNCTUATION , " = " ));
1102+
1103+ processAnnotationValueExpression (valueExpr , m .isCondensed (), tokens );
1104+ }
1105+
1106+ if (i < pairs .size () - 1 ) {
1107+ tokens .add (new Token (PUNCTUATION , ", " ));
1108+ }
1109+ }
1110+
1111+ tokens .add (new Token (PUNCTUATION , ")" ));
1112+ }
1113+ }
1114+ return tokens ;
1115+ }
1116+
1117+ private void processAnnotationValueExpression (final Expression valueExpr , final boolean condensed , final List <Token > tokens ) {
10801118 if (valueExpr .isClassExpr ()) {
10811119 // lookup to see if the type is known about, if so, make it a link, otherwise leave it as text
10821120 String typeName = valueExpr .getChildNodes ().get (0 ).toString ();
10831121 if (apiListing .getKnownTypes ().containsKey (typeName )) {
10841122 final Token token = new Token (TYPE_NAME , typeName );
10851123 token .setNavigateToId (apiListing .getKnownTypes ().get (typeName ));
1086- addToken (token );
1124+ tokens . add (token );
10871125 return ;
10881126 }
10891127 } else if (valueExpr .isArrayInitializerExpr ()) {
1090- addToken (new Token (PUNCTUATION , "{ " ));
1128+ if (!condensed ) {
1129+ tokens .add (new Token (PUNCTUATION , "{ " ));
1130+ }
10911131 for (int i = 0 ; i < valueExpr .getChildNodes ().size (); i ++) {
10921132 Node n = valueExpr .getChildNodes ().get (i );
10931133
10941134 if (n instanceof Expression ) {
1095- processAnnotationValueExpression ((Expression ) n );
1135+ processAnnotationValueExpression ((Expression ) n , condensed , tokens );
10961136 } else {
1097- addToken (new Token (TEXT , valueExpr .toString ()));
1137+ tokens . add (new Token (TEXT , valueExpr .toString ()));
10981138 }
10991139
11001140 if (i < valueExpr .getChildNodes ().size () - 1 ) {
1101- addToken (new Token (PUNCTUATION , ", " ));
1141+ tokens . add (new Token (PUNCTUATION , ", " ));
11021142 }
11031143 }
1104- addToken (new Token (PUNCTUATION , " }" ));
1144+ if (!condensed ) {
1145+ tokens .add (new Token (PUNCTUATION , " }" ));
1146+ }
11051147 return ;
11061148 }
11071149
1108- // if we fall through to here, just treat it as a string
1109- addToken (new Token (TEXT , valueExpr .toString ()));
1150+ // if we fall through to here, just treat it as a string.
1151+ // If we are in condensed mode, we strip off everything before the last period
1152+ String value = valueExpr .toString ();
1153+ if (condensed ) {
1154+ int lastPeriod = value .lastIndexOf ('.' );
1155+ if (lastPeriod != -1 ) {
1156+ value = value .substring (lastPeriod + 1 );
1157+ }
1158+ tokens .add (new Token (TEXT , upperCase (value )));
1159+ } else {
1160+ tokens .add (new Token (TEXT , value ));
1161+ }
11101162 }
11111163
11121164 private void getModifiers (NodeList <Modifier > modifiers ) {
0 commit comments