1ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski/* 2ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * Copyright (C) 2010 The Android Open Source Project 3ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * 4ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * you may not use this file except in compliance with the License. 6ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * You may obtain a copy of the License at 7ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * 8ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * 10ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * Unless required by applicable law or agreed to in writing, software 11ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * See the License for the specific language governing permissions and 14ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * limitations under the License. 15ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski */ 16ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 17ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskipackage com.android.layoutlib.bridge; 18ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 19ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport com.android.tools.layoutlib.annotations.LayoutlibDelegate; 20ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport com.android.tools.layoutlib.create.CreateInfo; 21ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 22ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.lang.reflect.Method; 23ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.lang.reflect.Modifier; 24ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.util.ArrayList; 25ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.util.List; 26ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 27ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport junit.framework.TestCase; 28ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 29ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski/** 30ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * Tests that native delegate classes implement all the required methods. 31ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * 32ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * This looks at {@link CreateInfo#DELEGATE_CLASS_NATIVES} to get the list of classes that 33ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * have their native methods reimplemented through a delegate. 34ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * 35ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * Since the reimplemented methods are not native anymore, we look for the annotation 36ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * {@link LayoutlibDelegate}, and look for a matching method in the delegate (named the same 37ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * as the modified class with _Delegate added as a suffix). 38ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * If the original native method is not static, then we make sure the delegate method also 39ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * include the original class as first parameter (to access "this"). 40ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * 41ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski */ 42ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskipublic class TestDelegates extends TestCase { 43ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 44d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta private List<String> mErrors = new ArrayList<String>(); 45d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta 46ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski public void testNativeDelegates() { 47ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 48ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski final String[] classes = CreateInfo.DELEGATE_CLASS_NATIVES; 49d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.clear(); 50d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta for (String clazz : classes) { 51d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta loadAndCompareClasses(clazz, clazz + "_Delegate"); 52ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 53d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta assertTrue(getErrors(), mErrors.isEmpty()); 54ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 55ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 56ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski public void testMethodDelegates() { 57ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski final String[] methods = CreateInfo.DELEGATE_METHODS; 58d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.clear(); 59d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta for (String methodName : methods) { 60ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // extract the class name 61ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski String className = methodName.substring(0, methodName.indexOf('#')); 62ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski String targetClassName = className.replace('$', '_') + "_Delegate"; 63ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 64ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski loadAndCompareClasses(className, targetClassName); 65ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 66d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta assertTrue(getErrors(), mErrors.isEmpty()); 67ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 68ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 69ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski private void loadAndCompareClasses(String originalClassName, String delegateClassName) { 70ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // load the classes 71ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski try { 72ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski ClassLoader classLoader = TestDelegates.class.getClassLoader(); 73ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Class<?> originalClass = classLoader.loadClass(originalClassName); 74ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Class<?> delegateClass = classLoader.loadClass(delegateClassName); 75ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 76ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski compare(originalClass, delegateClass); 77ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } catch (ClassNotFoundException e) { 78d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.add("Failed to load class: " + e.getMessage()); 79ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } catch (SecurityException e) { 80d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.add("Failed to load class: " + e.getMessage()); 81ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 82ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 83ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 84ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski private void compare(Class<?> originalClass, Class<?> delegateClass) throws SecurityException { 85ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski List<Method> checkedDelegateMethods = new ArrayList<Method>(); 86ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 87ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // loop on the methods of the original class, and for the ones that are annotated 88ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // with @LayoutlibDelegate, look for a matching method in the delegate class. 89ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // The annotation is automatically added by layoutlib_create when it replace a method 90ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // by a call to a delegate 91ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Method[] originalMethods = originalClass.getDeclaredMethods(); 92ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski for (Method originalMethod : originalMethods) { 93ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // look for methods that are delegated: they have the LayoutlibDelegate annotation 94ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if (originalMethod.getAnnotation(LayoutlibDelegate.class) == null) { 95ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski continue; 96ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 97ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 98ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // get the signature. 99ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Class<?>[] parameters = originalMethod.getParameterTypes(); 100ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 101ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // if the method is not static, then the class is added as the first parameter 102ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // (for "this") 103ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if ((originalMethod.getModifiers() & Modifier.STATIC) == 0) { 104ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 105ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Class<?>[] newParameters = new Class<?>[parameters.length + 1]; 106ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski newParameters[0] = originalClass; 107ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski System.arraycopy(parameters, 0, newParameters, 1, parameters.length); 108ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski parameters = newParameters; 109ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 110ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 111ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // if the original class is an inner class that's not static, then 112ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // we add this on the enclosing class at the beginning 113ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if (originalClass.getEnclosingClass() != null && 114ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski (originalClass.getModifiers() & Modifier.STATIC) == 0) { 115ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Class<?>[] newParameters = new Class<?>[parameters.length + 1]; 116ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski newParameters[0] = originalClass.getEnclosingClass(); 117ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski System.arraycopy(parameters, 0, newParameters, 1, parameters.length); 118ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski parameters = newParameters; 119ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 120ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 121ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski try { 122ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // try to load the method with the given parameter types. 123ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(), 124ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski parameters); 125ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 126f9a823540ce0e23e3bbdd7c1fb8bf2639e20a8bcDeepanshu Gupta // check the return type of the methods match. 127d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta if (delegateMethod.getReturnType() != originalMethod.getReturnType()) { 128d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.add( 129d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta String.format("Delegate method %1$s.%2$s does not match the " + 130d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta "corresponding framework method which returns %3$s", 131d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta delegateClass.getName(), 132d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta getMethodName(delegateMethod), 133d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta originalMethod.getReturnType().getName())); 134d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta } 135f9a823540ce0e23e3bbdd7c1fb8bf2639e20a8bcDeepanshu Gupta 136ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // check that the method has the annotation 137d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta if (delegateMethod.getAnnotation(LayoutlibDelegate.class) == null) { 138d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.add( 139d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta String.format("Delegate method %1$s for class %2$s does not have the " + 140d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta "@LayoutlibDelegate annotation", 141d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta delegateMethod.getName(), 142d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta originalClass.getName())); 143d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta } 144ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 145ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // check that the method is static 146d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta if ((delegateMethod.getModifiers() & Modifier.STATIC) != Modifier.STATIC) { 147d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.add( 148d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta String.format( 149d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta "Delegate method %1$s for class %2$s is not static", 150d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta delegateMethod.getName(), 151d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta originalClass.getName()) 152d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta ); 153d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta } 154ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 155ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // add the method as checked. 156ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski checkedDelegateMethods.add(delegateMethod); 157ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } catch (NoSuchMethodException e) { 158ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski String name = getMethodName(originalMethod, parameters); 159d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.add(String.format("Missing %1$s.%2$s", delegateClass.getName(), name)); 160ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 161ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 162ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 163ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // look for dead (delegate) code. 164ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // This looks for all methods in the delegate class, and if they have the 165ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // @LayoutlibDelegate annotation, make sure they have been previously found as a 166ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // match for a method in the original class. 167ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // If not, this means the method is a delegate for a method that either doesn't exist 168ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // anymore or is not delegated anymore. 169ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Method[] delegateMethods = delegateClass.getDeclaredMethods(); 170ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski for (Method delegateMethod : delegateMethods) { 171ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // look for methods that are delegates: they have the LayoutlibDelegate annotation 172ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if (delegateMethod.getAnnotation(LayoutlibDelegate.class) == null) { 173ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski continue; 174ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 175ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 176b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard // constructor_after methods are called by the constructor of the original class 177b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard if ("constructor_after".equals(delegateMethod.getName())) { 178b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard continue; 179b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard } 180b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard 181d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta if (!checkedDelegateMethods.contains(delegateMethod)) { 182d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta mErrors.add(String.format( 183d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta "Delegate method %1$s.%2$s is not used anymore and must be removed", 184d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta delegateClass.getName(), 185d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta getMethodName(delegateMethod))); 186d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta } 187ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 188ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 189ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 190ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 191ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski private String getMethodName(Method method) { 192ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski return getMethodName(method, method.getParameterTypes()); 193ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 194ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 195ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski private String getMethodName(Method method, Class<?>[] parameters) { 196ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // compute a full class name that's long but not too long. 197ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski StringBuilder sb = new StringBuilder(method.getName() + "("); 198ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski for (int j = 0; j < parameters.length; j++) { 199ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski Class<?> theClass = parameters[j]; 200ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski int dimensions = 0; 201ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski while (theClass.isArray()) { 202ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski dimensions++; 203ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski theClass = theClass.getComponentType(); 204ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 2059fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta sb.append(theClass.getName()); 206ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski for (int i = 0; i < dimensions; i++) { 207ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski sb.append("[]"); 208ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 209ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if (j < (parameters.length - 1)) { 210ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski sb.append(","); 211ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 212ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 213ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski sb.append(")"); 214ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 215ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski return sb.toString(); 216ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 217d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta 218d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta private String getErrors() { 219d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta StringBuilder s = new StringBuilder(); 220d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta for (String error : mErrors) { 221d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta s.append(error).append('\n'); 222d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta } 223d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta return s.toString(); 224d6b67539db5d0b4338cc1478999e20ff9f8728d2Deepanshu Gupta } 225ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski} 226