1 /* 2 * Copyright (C) 2008 The Android Open Source Project 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 android.signature.cts; 18 19 import java.lang.reflect.Modifier; 20 import java.util.ArrayList; 21 import java.util.Collection; 22 import java.util.List; 23 24 /** 25 * Represents class descriptions loaded from a jdiff xml file. Used 26 * for CTS SignatureTests. 27 */ 28 public class JDiffClassDescription { 29 30 public enum JDiffType { 31 INTERFACE, CLASS 32 } 33 34 private final String mPackageName; 35 private final String mShortClassName; 36 37 /** 38 * Package name + short class name 39 */ 40 private final String mAbsoluteClassName; 41 42 private int mModifier; 43 private boolean mIsPrevious; 44 45 private String mExtendedClass; 46 private final List<String> implInterfaces = new ArrayList<>(); 47 private final List<JDiffField> jDiffFields = new ArrayList<>(); 48 private final List<JDiffMethod> jDiffMethods = new ArrayList<>(); 49 private final List<JDiffConstructor> jDiffConstructors = new ArrayList<>(); 50 51 private JDiffType mClassType; 52 53 /** 54 * Creates a new JDiffClassDescription. 55 * 56 * @param pkg the java package this class will end up in. 57 * @param className the name of the class. 58 */ JDiffClassDescription(String pkg, String className)59 public JDiffClassDescription(String pkg, String className) { 60 mPackageName = pkg; 61 mShortClassName = className; 62 mAbsoluteClassName = mPackageName + "." + mShortClassName; 63 mIsPrevious = false; 64 } 65 setPreviousApiFlag(boolean isPreviousApi)66 public JDiffClassDescription setPreviousApiFlag(boolean isPreviousApi) { 67 mIsPrevious = isPreviousApi; 68 return this; 69 } 70 isPreviousApi()71 boolean isPreviousApi() { 72 return mIsPrevious; 73 } 74 getPackageName()75 String getPackageName() { 76 return mPackageName; 77 } 78 getShortClassName()79 public String getShortClassName() { 80 return mShortClassName; 81 } 82 getModifier()83 int getModifier() { 84 return mModifier; 85 } 86 getExtendedClass()87 String getExtendedClass() { 88 return mExtendedClass; 89 } 90 getImplInterfaces()91 List<String> getImplInterfaces() { 92 return implInterfaces; 93 } 94 getFields()95 List<JDiffField> getFields() { 96 return jDiffFields; 97 } 98 getMethods()99 List<JDiffMethod> getMethods() { 100 return jDiffMethods; 101 } 102 getConstructors()103 List<JDiffConstructor> getConstructors() { 104 return jDiffConstructors; 105 } 106 getClassType()107 JDiffType getClassType() { 108 return mClassType; 109 } 110 111 /** 112 * adds implemented interface name. 113 * 114 * @param iname name of interface 115 */ addImplInterface(String iname)116 public void addImplInterface(String iname) { 117 implInterfaces.add(iname); 118 } 119 120 /** 121 * Adds a field. 122 * 123 * @param field the field to be added. 124 */ addField(JDiffField field)125 public void addField(JDiffField field) { 126 jDiffFields.add(field); 127 } 128 129 /** 130 * Adds a method. 131 * 132 * @param method the method to be added. 133 */ addMethod(JDiffMethod method)134 public void addMethod(JDiffMethod method) { 135 jDiffMethods.add(method); 136 } 137 138 /** 139 * Adds a constructor. 140 * 141 * @param tc the constructor to be added. 142 */ addConstructor(JDiffConstructor tc)143 public void addConstructor(JDiffConstructor tc) { 144 jDiffConstructors.add(tc); 145 } 146 convertModifiersToAccessLevel(int modifiers)147 private static String convertModifiersToAccessLevel(int modifiers) { 148 if ((modifiers & Modifier.PUBLIC) != 0) { 149 return "public"; 150 } else if ((modifiers & Modifier.PRIVATE) != 0) { 151 return "private"; 152 } else if ((modifiers & Modifier.PROTECTED) != 0) { 153 return "protected"; 154 } else { 155 // package protected 156 return ""; 157 } 158 } 159 convertModifersToModifierString(int modifiers)160 private static String convertModifersToModifierString(int modifiers) { 161 StringBuilder sb = new StringBuilder(); 162 String separator = ""; 163 164 // order taken from Java Language Spec, sections 8.1.1, 8.3.1, and 8.4.3 165 if ((modifiers & Modifier.ABSTRACT) != 0) { 166 sb.append(separator).append("abstract"); 167 separator = " "; 168 } 169 if ((modifiers & Modifier.STATIC) != 0) { 170 sb.append(separator).append("static"); 171 separator = " "; 172 } 173 if ((modifiers & Modifier.FINAL) != 0) { 174 sb.append(separator).append("final"); 175 separator = " "; 176 } 177 if ((modifiers & Modifier.TRANSIENT) != 0) { 178 sb.append(separator).append("transient"); 179 separator = " "; 180 } 181 if ((modifiers & Modifier.VOLATILE) != 0) { 182 sb.append(separator).append("volatile"); 183 separator = " "; 184 } 185 if ((modifiers & Modifier.SYNCHRONIZED) != 0) { 186 sb.append(separator).append("synchronized"); 187 separator = " "; 188 } 189 if ((modifiers & Modifier.NATIVE) != 0) { 190 sb.append(separator).append("native"); 191 separator = " "; 192 } 193 if ((modifiers & Modifier.STRICT) != 0) { 194 sb.append(separator).append("strictfp"); 195 } 196 197 return sb.toString(); 198 } 199 200 abstract static class JDiffElement { 201 final String mName; 202 int mModifier; 203 JDiffElement(String name, int modifier)204 JDiffElement(String name, int modifier) { 205 mName = name; 206 mModifier = modifier; 207 } 208 } 209 210 /** 211 * Represents a field. 212 */ 213 public static final class JDiffField extends JDiffElement { 214 final String mFieldType; 215 private final String mFieldValue; 216 JDiffField(String name, String fieldType, int modifier, String value)217 public JDiffField(String name, String fieldType, int modifier, String value) { 218 super(name, modifier); 219 220 mFieldType = fieldType; 221 mFieldValue = value; 222 } 223 224 /** 225 * A string representation of the value within the field. 226 */ getValueString()227 public String getValueString() { 228 return mFieldValue; 229 } 230 231 /** 232 * Make a readable string according to the class name specified. 233 * 234 * @param className The specified class name. 235 * @return A readable string to represent this field along with the class name. 236 */ toReadableString(String className)237 String toReadableString(String className) { 238 return className + "#" + mName + "(" + mFieldType + ")"; 239 } 240 toSignatureString()241 public String toSignatureString() { 242 StringBuilder sb = new StringBuilder(); 243 244 // access level 245 String accesLevel = convertModifiersToAccessLevel(mModifier); 246 if (!"".equals(accesLevel)) { 247 sb.append(accesLevel).append(" "); 248 } 249 250 String modifierString = convertModifersToModifierString(mModifier); 251 if (!"".equals(modifierString)) { 252 sb.append(modifierString).append(" "); 253 } 254 255 sb.append(mFieldType).append(" "); 256 257 sb.append(mName); 258 259 return sb.toString(); 260 } 261 } 262 263 /** 264 * Represents a method. 265 */ 266 public static class JDiffMethod extends JDiffElement { 267 final String mReturnType; 268 final ArrayList<String> mParamList; 269 final ArrayList<String> mExceptionList; 270 JDiffMethod(String name, int modifier, String returnType)271 public JDiffMethod(String name, int modifier, String returnType) { 272 super(name, modifier); 273 274 if (returnType == null) { 275 mReturnType = "void"; 276 } else { 277 mReturnType = scrubJdiffParamType(returnType); 278 } 279 280 mParamList = new ArrayList<>(); 281 mExceptionList = new ArrayList<>(); 282 } 283 284 /** 285 * Adds a parameter. 286 * 287 * @param param parameter type 288 */ addParam(String param)289 public void addParam(String param) { 290 mParamList.add(scrubJdiffParamType(param)); 291 } 292 293 /** 294 * Adds an exception. 295 * 296 * @param exceptionName name of exception 297 */ addException(String exceptionName)298 public void addException(String exceptionName) { 299 mExceptionList.add(exceptionName); 300 } 301 302 /** 303 * Makes a readable string according to the class name specified. 304 * 305 * @param className The specified class name. 306 * @return A readable string to represent this method along with the class name. 307 */ toReadableString(String className)308 String toReadableString(String className) { 309 return className + "#" + mName + "(" + convertParamList(mParamList) + ")"; 310 } 311 312 /** 313 * Converts a parameter array to a string 314 * 315 * @param params the array to convert 316 * @return converted parameter string 317 */ convertParamList(final ArrayList<String> params)318 private static String convertParamList(final ArrayList<String> params) { 319 320 StringBuilder paramList = new StringBuilder(); 321 322 if (params != null) { 323 for (String str : params) { 324 paramList.append(str).append(", "); 325 } 326 if (params.size() > 0) { 327 paramList.delete(paramList.length() - 2, paramList.length()); 328 } 329 } 330 331 return paramList.toString(); 332 } 333 toSignatureString()334 public String toSignatureString() { 335 StringBuilder sb = new StringBuilder(); 336 337 // access level 338 String accessLevel = convertModifiersToAccessLevel(mModifier); 339 if (!"".equals(accessLevel)) { 340 sb.append(accessLevel).append(" "); 341 } 342 343 String modifierString = convertModifersToModifierString(mModifier); 344 if (!"".equals(modifierString)) { 345 sb.append(modifierString).append(" "); 346 } 347 348 String returnType = getReturnType(); 349 if (!"".equals(returnType)) { 350 sb.append(returnType).append(" "); 351 } 352 353 sb.append(mName); 354 sb.append("("); 355 for (int x = 0; x < mParamList.size(); x++) { 356 sb.append(mParamList.get(x)); 357 if (x + 1 != mParamList.size()) { 358 sb.append(", "); 359 } 360 } 361 sb.append(")"); 362 363 // does it throw? 364 if (mExceptionList.size() > 0) { 365 sb.append(" throws "); 366 for (int x = 0; x < mExceptionList.size(); x++) { 367 sb.append(mExceptionList.get(x)); 368 if (x + 1 != mExceptionList.size()) { 369 sb.append(", "); 370 } 371 } 372 } 373 374 return sb.toString(); 375 } 376 377 /** 378 * Gets the return type. 379 * 380 * @return the return type of this method. 381 */ getReturnType()382 String getReturnType() { 383 return mReturnType; 384 } 385 } 386 387 /** 388 * Represents a constructor. 389 */ 390 public static final class JDiffConstructor extends JDiffMethod { JDiffConstructor(String name, int modifier)391 public JDiffConstructor(String name, int modifier) { 392 super(name, modifier, null); 393 } 394 395 /** 396 * Gets the return type. 397 * 398 * @return the return type of this method. 399 */ 400 @Override getReturnType()401 protected String getReturnType() { 402 // Constructors have no return type. 403 return ""; 404 } 405 } 406 407 /** 408 * Gets the list of fields found within this class. 409 * 410 * @return the list of fields. 411 */ getFieldList()412 public Collection<JDiffField> getFieldList() { 413 return jDiffFields; 414 } 415 416 /** 417 * Convert the class into a printable signature string. 418 * 419 * @return the signature string 420 */ toSignatureString()421 public String toSignatureString() { 422 StringBuilder sb = new StringBuilder(); 423 424 String accessLevel = convertModifiersToAccessLevel(mModifier); 425 if (!"".equals(accessLevel)) { 426 sb.append(accessLevel).append(" "); 427 } 428 if (!JDiffType.INTERFACE.equals(mClassType)) { 429 String modifierString = convertModifersToModifierString(mModifier); 430 if (!"".equals(modifierString)) { 431 sb.append(modifierString).append(" "); 432 } 433 sb.append("class "); 434 } else { 435 sb.append("interface "); 436 } 437 // class name 438 sb.append(mShortClassName); 439 440 // does it extends something? 441 if (mExtendedClass != null) { 442 sb.append(" extends ").append(mExtendedClass).append(" "); 443 } 444 445 // implements something? 446 if (implInterfaces.size() > 0) { 447 sb.append(" implements "); 448 for (int x = 0; x < implInterfaces.size(); x++) { 449 String interf = implInterfaces.get(x); 450 sb.append(interf); 451 // if not last elements 452 if (x + 1 != implInterfaces.size()) { 453 sb.append(", "); 454 } 455 } 456 } 457 return sb.toString(); 458 } 459 460 /** 461 * Sees if the class under test is actually an enum. 462 * 463 * @return true if this class is enum 464 */ isEnumType()465 boolean isEnumType() { 466 return "java.lang.Enum".equals(mExtendedClass); 467 } 468 469 /** 470 * Sees if the class under test is actually an annotation. 471 * 472 * @return true if this class is Annotation. 473 */ isAnnotation()474 boolean isAnnotation() { 475 return implInterfaces.contains("java.lang.annotation.Annotation"); 476 } 477 478 /** 479 * Gets the class name for the class under test. 480 * 481 * @return the class name. 482 */ getClassName()483 String getClassName() { 484 return mShortClassName; 485 } 486 487 /** 488 * Gets the package name + short class name 489 * 490 * @return The package + short class name 491 */ getAbsoluteClassName()492 public String getAbsoluteClassName() { 493 return mAbsoluteClassName; 494 } 495 496 /** 497 * Sets the modifier for the class under test. 498 * 499 * @param modifier the modifier 500 */ setModifier(int modifier)501 public void setModifier(int modifier) { 502 mModifier = modifier; 503 } 504 505 /** 506 * Sets the return type for the class under test. 507 * 508 * @param type the return type 509 */ setType(JDiffType type)510 public void setType(JDiffType type) { 511 mClassType = type; 512 } 513 514 /** 515 * Sets the class that is beign extended for the class under test. 516 * 517 * @param extendsClass the class being extended. 518 */ setExtendsClass(String extendsClass)519 void setExtendsClass(String extendsClass) { 520 mExtendedClass = extendsClass; 521 } 522 523 /** 524 * Cleans up jdiff parameters to canonicalize them. 525 * 526 * @param paramType the parameter from jdiff. 527 * @return the scrubbed version of the parameter. 528 */ scrubJdiffParamType(String paramType)529 private static String scrubJdiffParamType(String paramType) { 530 // <? extends java.lang.Object and <?> are the same, so 531 // canonicalize them to one form. 532 return paramType 533 .replace("? extends java.lang.Object", "?") 534 .replace("? super java.lang.Object", "? super ?"); 535 } 536 537 @Override toString()538 public String toString() { 539 return mAbsoluteClassName; 540 } 541 } 542