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