1 /* 2 * Copyright (C) 2016 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.doclava; 18 19 import com.google.clearsilver.jsilver.data.Data; 20 21 import java.util.ArrayList; 22 23 /** 24 * Class for writing a JSON dictionary of Android package/class/member info that can be used for 25 * dereferencing javadoc style {@link} tags. 26 */ 27 28 public class AtLinksNavTree { 29 30 /** 31 * Write a JSON dictionary of Android package/class/member info. The hierarchy will follow this 32 * format: package name -> class name -> member name and signature -> parent package.class name 33 * if the member was inherited (or an empty string if the member was not inherited). 34 * 35 * <p>For example: 36 * <pre>{ 37 * "android": { 38 * "Manifest": { 39 * "Manifest()": "", 40 * "clone()": "java.lang.Object", 41 * "equals(java.lang.Object)": "java.lang.Object", 42 * ... 43 * }, 44 * ... 45 * }, 46 * ... 47 * }</pre> 48 * 49 * @param dir The directory path to prepend to the output path if the generated navtree is for 50 * one the a supplemental library references (such as the wearable support library) 51 */ writeAtLinksNavTree(String dir)52 public static void writeAtLinksNavTree(String dir) { 53 StringBuilder buf = new StringBuilder(); 54 55 buf.append("{"); 56 addPackages(buf, Doclava.choosePackages()); 57 buf.append("\n}"); 58 59 Data data = Doclava.makeHDF(); 60 data.setValue("navtree", buf.toString()); 61 62 String output_path; 63 if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS && (Doclava.libraryRoot != null)) { 64 output_path = dir + Doclava.libraryRoot + "at_links_navtree.json"; 65 } else { 66 output_path = "at_links_navtree.json"; 67 } 68 69 ClearPage.write(data, "at_links_navtree.cs", output_path); 70 } 71 72 /** 73 * Append the provided string builder with the navtree info for the provided list of packages. 74 * 75 * @param buf The string builder to append to. 76 * @param packages A list of PackageInfo objects. Navtree info for each package will be appended 77 * to the provided string builder. 78 */ addPackages(StringBuilder buf, PackageInfo[] packages)79 private static void addPackages(StringBuilder buf, PackageInfo[] packages) { 80 boolean is_first_package = true; 81 for (PackageInfo pkg : Doclava.choosePackages()) { 82 if (!pkg.name().contains(".internal.")) { 83 if (!is_first_package) { 84 buf.append(","); 85 } 86 buf.append("\n \"" + pkg.name() + "\": {"); 87 88 boolean is_first_class = true; 89 is_first_class = addClasses(buf, pkg.annotations(), is_first_class); 90 is_first_class = addClasses(buf, pkg.interfaces(), is_first_class); 91 is_first_class = addClasses(buf, pkg.ordinaryClasses(), is_first_class); 92 is_first_class = addClasses(buf, pkg.enums(), is_first_class); 93 is_first_class = addClasses(buf, pkg.exceptions(), is_first_class); 94 addClasses(buf, pkg.errors(), is_first_class); 95 96 buf.append("\n }"); 97 is_first_package = false; 98 } 99 } 100 } 101 102 /** 103 * Append the provided string builder with the navtree info for the provided list of classes. 104 * 105 * @param buf The string builder to append to. 106 * @param classes A list of ClassInfo objects. Navtree info for each class will be appended 107 * to the provided string builder. 108 * @param is_first_class True if this is the first child class listed under the parent package. 109 */ addClasses(StringBuilder buf, ClassInfo[] classes, boolean is_first_class)110 private static boolean addClasses(StringBuilder buf, ClassInfo[] classes, 111 boolean is_first_class) { 112 for (ClassInfo cl : classes) { 113 if (!is_first_class) { 114 buf.append(","); 115 } 116 buf.append("\n \"" + cl.name() + "\": {"); 117 118 boolean is_first_member = true; 119 is_first_member = addFields(buf, cl.fields(), is_first_member, cl); 120 is_first_member = addMethods(buf, cl.constructors(), is_first_member, cl); 121 addMethods(buf, cl.methods(), is_first_member, cl); 122 123 buf.append("\n }"); 124 is_first_class = false; 125 } 126 return is_first_class; 127 } 128 129 /** 130 * Append the provided string builder with the navtree info for the provided list of fields. 131 * 132 * @param buf The string builder to append to. 133 * @param fields A list of FieldInfo objects. Navtree info for each field will be appended 134 * to the provided string builder. 135 * @param is_first_member True if this is the first child member listed under the parent class. 136 * @param cl The ClassInfo object for the parent class of this field. 137 */ addFields(StringBuilder buf, ArrayList<FieldInfo> fields, boolean is_first_member, ClassInfo cl)138 private static boolean addFields(StringBuilder buf, ArrayList<FieldInfo> fields, 139 boolean is_first_member, ClassInfo cl) { 140 for (FieldInfo field : fields) { 141 if (!field.containingClass().qualifiedName().contains(".internal.")) { 142 if (!is_first_member) { 143 buf.append(","); 144 } 145 buf.append("\n \"" + field.name() + "\": \""); 146 if (!field.containingClass().qualifiedName().equals(cl.qualifiedName())) { 147 buf.append(field.containingClass().qualifiedName()); 148 } 149 buf.append("\""); 150 is_first_member = false; 151 } 152 } 153 return is_first_member; 154 } 155 156 /** 157 * Append the provided string builder with the navtree info for the provided list of methods. 158 * 159 * @param buf The string builder to append to. 160 * @param methods A list of MethodInfo objects. Navtree info for each method will be appended 161 * to the provided string builder. 162 * @param is_first_member True if this is the first child member listed under the parent class. 163 * @param cl The ClassInfo object for the parent class of this method. 164 */ addMethods(StringBuilder buf, ArrayList<MethodInfo> methods, boolean is_first_member, ClassInfo cl)165 private static boolean addMethods(StringBuilder buf, ArrayList<MethodInfo> methods, 166 boolean is_first_member, ClassInfo cl) { 167 for (MethodInfo method : methods) { 168 if (!method.containingClass().qualifiedName().contains(".internal.")) { 169 if (!is_first_member) { 170 buf.append(","); 171 } 172 buf.append("\n \"" + method.name() + method.signature() + "\": \""); 173 if (!method.containingClass().qualifiedName().equals(cl.qualifiedName())) { 174 buf.append(method.containingClass().qualifiedName()); 175 } 176 buf.append("\""); 177 is_first_member = false; 178 } 179 } 180 return is_first_member; 181 } 182 183 } 184