/** * Finds the reflected class for the class under test. * * @return the reflected class, or null if not found. */ @SuppressWarnings("unchecked") private Class<?> findMatchingClass() { // even if there are no . in the string, split will return an // array of length 1 String[] classNameParts = mShortClassName.split("\\."); String currentName = mPackageName + "." + classNameParts[0]; try { // Check to see if the class we're looking for is the top // level class. Class<?> clz = Class.forName(currentName, false, this.getClass().getClassLoader()); if (clz.getCanonicalName().equals(mAbsoluteClassName)) { return clz; } // Then it must be an inner class. for (int x = 1; x < classNameParts.length; x++) { clz = findInnerClassByName(clz, classNameParts[x]); if (clz == null) { return null; } if (clz.getCanonicalName().equals(mAbsoluteClassName)) { return clz; } } } catch (ClassNotFoundException e) { SignatureTestLog.e("ClassNotFoundException for " + mPackageName + "." + mShortClassName, e); return null; } return null; }
/** Checks whether the constructor parsed from API xml file and Java reflection are compliant. */ @SuppressWarnings("unchecked") private void checkConstructorCompliance() { for (JDiffConstructor con : jDiffConstructors) { try { Constructor<?> c = findMatchingConstructor(con); if (c == null) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISSING_METHOD, con.toReadableString(mAbsoluteClassName), "No method with correct signature found:" + con.toSignatureString()); } else { if (c.isVarArgs()) { // some method's parameter are variable args con.mModifier |= METHOD_MODIFIER_VAR_ARGS; } if (c.getModifiers() != con.mModifier) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISMATCH_METHOD, con.toReadableString(mAbsoluteClassName), "Non-compatible method found when looking for " + con.toSignatureString()); } } } catch (Exception e) { SignatureTestLog.e("Got exception when checking constructor compliance", e); mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION, con.toReadableString(mAbsoluteClassName), "Exception!"); } } }
/** * Checks that the class found through reflection matches the specification from the API xml file. */ @SuppressWarnings("unchecked") private void checkClassCompliance() { try { mAbsoluteClassName = mPackageName + "." + mShortClassName; mClass = findMatchingClass(); if (mClass == null) { // No class found, notify the observer according to the class type if (JDiffType.INTERFACE.equals(mClassType)) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISSING_INTERFACE, mAbsoluteClassName, "Classloader is unable to find " + mAbsoluteClassName); } else { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISSING_CLASS, mAbsoluteClassName, "Classloader is unable to find " + mAbsoluteClassName); } return; } if (!checkClassModifiersCompliance()) { logMismatchInterfaceSignature( mAbsoluteClassName, "Non-compatible class found when looking for " + toSignatureString()); return; } if (!checkClassAnnotationCompliace()) { logMismatchInterfaceSignature(mAbsoluteClassName, "Annotation mismatch"); return; } if (!mClass.isAnnotation()) { // check father class if (!checkClassExtendsCompliance()) { logMismatchInterfaceSignature(mAbsoluteClassName, "Extends mismatch"); return; } // check implements interface if (!checkClassImplementsCompliance()) { logMismatchInterfaceSignature(mAbsoluteClassName, "Implements mismatch"); return; } } } catch (Exception e) { SignatureTestLog.e("Got exception when checking field compliance", e); mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION, mAbsoluteClassName, "Exception!"); } }
/** * Checks that the method found through reflection matches the specification from the API xml * file. */ private void checkMethodCompliance() { for (JDiffMethod method : jDiffMethods) { try { // this is because jdiff think a method in an interface is not abstract if (JDiffType.INTERFACE.equals(mClassType)) { method.mModifier |= Modifier.ABSTRACT; } Method m = findMatchingMethod(method); if (m == null) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISSING_METHOD, method.toReadableString(mAbsoluteClassName), "No method with correct signature found:" + method.toSignatureString()); } else { if (m.isVarArgs()) { method.mModifier |= METHOD_MODIFIER_VAR_ARGS; } if (m.isBridge()) { method.mModifier |= METHOD_MODIFIER_BRIDGE; } if (m.isSynthetic()) { method.mModifier |= METHOD_MODIFIER_SYNTHETIC; } // FIXME: A workaround to fix the final mismatch on enumeration if (mClass.isEnum() && method.mName.equals("values")) { return; } if (!areMethodModifiedCompatibile(method, m)) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISMATCH_METHOD, method.toReadableString(mAbsoluteClassName), "Non-compatible method found when looking for " + method.toSignatureString()); } } } catch (Exception e) { SignatureTestLog.e("Got exception when checking method compliance", e); mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION, method.toReadableString(mAbsoluteClassName), "Exception!"); } } }
/** Checks all fields in test class for compliance with the API xml. */ @SuppressWarnings("unchecked") private void checkFieldsCompliance() { for (JDiffField field : jDiffFields) { try { Field f = findMatchingField(field); if (f == null) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISSING_FIELD, field.toReadableString(mAbsoluteClassName), "No field with correct signature found:" + field.toSignatureString()); } else if (f.getModifiers() != field.mModifier) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISMATCH_FIELD, field.toReadableString(mAbsoluteClassName), "Non-compatible field modifiers found when looking for " + field.toSignatureString()); } else if (!f.getType().getCanonicalName().equals(field.mFieldType)) { // type name does not match, but this might be a generic String genericTypeName = null; Type type = f.getGenericType(); if (type != null) { genericTypeName = type instanceof Class ? ((Class) type).getName() : type.toString(); } if (genericTypeName == null || !genericTypeName.equals(field.mFieldType)) { mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.MISMATCH_FIELD, field.toReadableString(mAbsoluteClassName), "Non-compatible field type found when looking for " + field.toSignatureString()); } } } catch (Exception e) { SignatureTestLog.e("Got exception when checking field compliance", e); mResultObserver.notifyFailure( SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION, field.toReadableString(mAbsoluteClassName), "Exception!"); } } }