[dna-commits] DNA SVN: r287 - in trunk/dna-common/src: test/java/org/jboss/dna/common/util and 1 other directory.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Fri Jun 13 14:16:28 EDT 2008


Author: rhauch
Date: 2008-06-13 14:16:28 -0400 (Fri, 13 Jun 2008)
New Revision: 287

Added:
   trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java
   trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java
Log:
Added a reflection utility.

Added: trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java	                        (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java	2008-06-13 18:16:28 UTC (rev 287)
@@ -0,0 +1,404 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors. 
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.common.util;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * Utility class for working reflectively with objects.
+ * 
+ * @author Randall Hauch
+ */
+public class Reflection {
+
+    /**
+     * Build the list of classes that correspond to the list of argument objects.
+     * 
+     * @param arguments the list of argument objects.
+     * @return the list of Class instances that correspond to the list of argument objects; the resulting list will contain a null
+     *         element for each null argument.
+     */
+    public static Class<?>[] buildArgumentClasses( Object... arguments ) {
+        if (arguments == null || arguments.length == 0) return EMPTY_CLASS_ARRAY;
+        Class<?>[] result = new Class<?>[arguments.length];
+        int i = 0;
+        for (Object argument : arguments) {
+            if (argument != null) {
+                result[i] = argument.getClass();
+            } else {
+                result[i] = null;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Build the list of classes that correspond to the list of argument objects.
+     * 
+     * @param arguments the list of argument objects.
+     * @return the list of Class instances that correspond to the list of argument objects; the resulting list will contain a null
+     *         element for each null argument.
+     */
+    public static List<Class<?>> buildArgumentClassList( Object... arguments ) {
+        if (arguments == null || arguments.length == 0) return Collections.emptyList();
+        List<Class<?>> result = new ArrayList<Class<?>>(arguments.length);
+        for (Object argument : arguments) {
+            if (argument != null) {
+                result.add(argument.getClass());
+            } else {
+                result.add(null);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Convert any argument classes to primitives.
+     * 
+     * @param arguments the list of argument classes.
+     * @return the list of Class instances in which any classes that could be represented by primitives (e.g., Boolean) were
+     *         replaced with the primitive classes (e.g., Boolean.TYPE).
+     */
+    public static List<Class<?>> convertArgumentClassesToPrimitives( Class<?>... arguments ) {
+        if (arguments == null || arguments.length == 0) return Collections.emptyList();
+        List<Class<?>> result = new ArrayList<Class<?>>(arguments.length);
+        for (Class<?> clazz : arguments) {
+            if (clazz == Boolean.class) clazz = Boolean.TYPE;
+            else if (clazz == Character.class) clazz = Character.TYPE;
+            else if (clazz == Byte.class) clazz = Byte.TYPE;
+            else if (clazz == Short.class) clazz = Short.TYPE;
+            else if (clazz == Integer.class) clazz = Integer.TYPE;
+            else if (clazz == Long.class) clazz = Long.TYPE;
+            else if (clazz == Float.class) clazz = Float.TYPE;
+            else if (clazz == Double.class) clazz = Double.TYPE;
+            else if (clazz == Void.class) clazz = Void.TYPE;
+            result.add(clazz);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the name of the class. The result will be the fully-qualified class name, or the readable form for arrays and
+     * primitive types.
+     * 
+     * @param clazz the class for which the class name is to be returned.
+     * @return the readable name of the class.
+     */
+    public static String getClassName( final Class<?> clazz ) {
+        final String fullName = clazz.getName();
+        final int fullNameLength = fullName.length();
+
+        // Check for array ('[') or the class/interface marker ('L') ...
+        int numArrayDimensions = 0;
+        while (numArrayDimensions < fullNameLength) {
+            final char c = fullName.charAt(numArrayDimensions);
+            if (c != '[') {
+                String name = null;
+                // Not an array, so it must be one of the other markers ...
+                switch (c) {
+                    case 'L': {
+                        name = fullName.subSequence(numArrayDimensions + 1, fullNameLength).toString();
+                        break;
+                    }
+                    case 'B': {
+                        name = "byte";
+                        break;
+                    }
+                    case 'C': {
+                        name = "char";
+                        break;
+                    }
+                    case 'D': {
+                        name = "double";
+                        break;
+                    }
+                    case 'F': {
+                        name = "float";
+                        break;
+                    }
+                    case 'I': {
+                        name = "int";
+                        break;
+                    }
+                    case 'J': {
+                        name = "long";
+                        break;
+                    }
+                    case 'S': {
+                        name = "short";
+                        break;
+                    }
+                    case 'Z': {
+                        name = "boolean";
+                        break;
+                    }
+                    case 'V': {
+                        name = "void";
+                        break;
+                    }
+                    default: {
+                        name = fullName.subSequence(numArrayDimensions, fullNameLength).toString();
+                    }
+                }
+                if (numArrayDimensions == 0) {
+                    // No array markers, so just return the name ...
+                    return name;
+                }
+                // Otherwise, add the array markers and the name ...
+                if (numArrayDimensions < BRACKETS_PAIR.length) {
+                    name = name + BRACKETS_PAIR[numArrayDimensions];
+                } else {
+                    for (int i = 0; i < numArrayDimensions; i++) {
+                        name = name + BRACKETS_PAIR[1];
+                    }
+                }
+                return name;
+            }
+            ++numArrayDimensions;
+        }
+
+        return fullName;
+    }
+
+    private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[] {};
+    private static final String[] BRACKETS_PAIR = new String[] {"", "[]", "[][]", "[][][]", "[][][][]", "[][][][][]"};
+
+    private Class<?> targetClass;
+    private Map<String, LinkedList<Method>> methodMap = null; // used for the brute-force method finder
+
+    /**
+     * Construct a Reflection instance that cache's some information about the target class. The target class is the Class object
+     * upon which the methods will be found.
+     * 
+     * @param targetClass the target class
+     * @throws IllegalArgumentException if the target class is null
+     */
+    public Reflection( Class<?> targetClass ) {
+        ArgCheck.isNotNull(targetClass, "targetClass");
+        this.targetClass = targetClass;
+    }
+
+    /**
+     * Return the class that is the target for the reflection methods.
+     * 
+     * @return the target class
+     */
+    public Class<?> getTargetClass() {
+        return this.targetClass;
+    }
+
+    /**
+     * Find the method on the target class that matches the supplied method name.
+     * 
+     * @param methodName the name of the method that is to be found.
+     * @return the Method objects that have a matching name, or an empty array if there are no methods that have a matching name.
+     */
+    public Method[] findMethods( String methodName ) {
+        return findMethods(Pattern.compile(methodName));
+    }
+
+    /**
+     * Find the method on the target class that matches the supplied method name.
+     * 
+     * @param methodNamePattern the regular expression pattern for the name of the method that is to be found.
+     * @return the Method objects that have a matching name, or an empty array if there are no methods that have a matching name.
+     */
+    public Method[] findMethods( Pattern methodNamePattern ) {
+        final Method[] allMethods = this.targetClass.getMethods();
+        final List<Method> result = new ArrayList<Method>();
+        for (int i = 0; i < allMethods.length; i++) {
+            final Method m = allMethods[i];
+            if (methodNamePattern.matcher(m.getName()).matches()) {
+                result.add(m);
+            }
+        }
+        return result.toArray(new Method[result.size()]);
+    }
+
+    /**
+     * Find the method on the target class that matches the supplied method name.
+     * 
+     * @param methodName the name of the method that is to be found.
+     * @return the first Method object found that has a matching name, or null if there are no methods that have a matching name.
+     */
+    public Method findFirstMethod( String methodName ) {
+        return findFirstMethod(Pattern.compile(methodName));
+    }
+
+    /**
+     * Find the method on the target class that matches the supplied method name.
+     * 
+     * @param methodNamePattern the regular expression pattern for the name of the method that is to be found.
+     * @return the first Method object found that has a matching name, or null if there are no methods that have a matching name.
+     */
+    public Method findFirstMethod( Pattern methodNamePattern ) {
+        final Method[] allMethods = this.targetClass.getMethods();
+        for (int i = 0; i < allMethods.length; i++) {
+            final Method m = allMethods[i];
+            if (methodNamePattern.matcher(m.getName()).matches()) {
+                return m;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find the best method on the target class that matches the signature specified with the specified name and the list of
+     * arguments. This method first attempts to find the method with the specified arguments; if no such method is found, a
+     * NoSuchMethodException is thrown.
+     * <P>
+     * This method is unable to find methods with signatures that include both primitive arguments <i>and</i> arguments that are
+     * instances of <code>Number</code> or its subclasses.
+     * 
+     * @param methodName the name of the method that is to be invoked.
+     * @param arguments the array of Object instances that correspond to the arguments passed to the method.
+     * @return the Method object that references the method that satisfies the requirements, or null if no satisfactory method
+     *         could be found.
+     * @throws NoSuchMethodException if a matching method is not found.
+     * @throws SecurityException if access to the information is denied.
+     */
+    public Method findBestMethodOnTarget( String methodName,
+                                          Object... arguments ) throws NoSuchMethodException, SecurityException {
+        Class<?>[] argumentClasses = buildArgumentClasses(arguments);
+        return findBestMethodWithSignature(methodName, argumentClasses);
+    }
+
+    /**
+     * Find the best method on the target class that matches the signature specified with the specified name and the list of
+     * argument classes. This method first attempts to find the method with the specified argument classes; if no such method is
+     * found, a NoSuchMethodException is thrown.
+     * 
+     * @param methodName the name of the method that is to be invoked.
+     * @param argumentsClasses the list of Class instances that correspond to the classes for each argument passed to the method.
+     * @return the Method object that references the method that satisfies the requirements, or null if no satisfactory method
+     *         could be found.
+     * @throws NoSuchMethodException if a matching method is not found.
+     * @throws SecurityException if access to the information is denied.
+     */
+    public Method findBestMethodWithSignature( String methodName,
+                                               Class<?>... argumentsClasses ) throws NoSuchMethodException, SecurityException {
+
+        // Attempt to find the method
+        Method result;
+
+        // -------------------------------------------------------------------------------
+        // First try to find the method with EXACTLY the argument classes as specified ...
+        // -------------------------------------------------------------------------------
+        Class<?>[] classArgs = null;
+        try {
+            classArgs = argumentsClasses != null ? argumentsClasses : new Class[] {};
+            result = this.targetClass.getMethod(methodName, classArgs); // this may throw an exception if not found
+            return result;
+        } catch (NoSuchMethodException e) {
+            // No method found, so continue ...
+        }
+
+        // ---------------------------------------------------------------------------------------------
+        // Then try to find a method with the argument classes converted to a primitive, if possible ...
+        // ---------------------------------------------------------------------------------------------
+        List<Class<?>> argumentsClassList = convertArgumentClassesToPrimitives(argumentsClasses);
+        try {
+            classArgs = argumentsClassList.toArray(new Class[argumentsClassList.size()]);
+            result = this.targetClass.getMethod(methodName, classArgs); // this may throw an exception if not found
+            return result;
+        } catch (NoSuchMethodException e) {
+            // No method found, so continue ...
+        }
+
+        // ---------------------------------------------------------------------------------------------
+        // Still haven't found anything. So far, the "getMethod" logic only finds methods that EXACTLY
+        // match the argument classes (i.e., not methods declared with superclasses or interfaces of
+        // the arguments). There is no canned algorithm in Java to do this, so we have to brute-force it.
+        // The following algorithm will find the first method that matches by doing "instanceof", so it
+        // may not be the best method. Since there is some overhead to this algorithm, the first time
+        // caches some information in class members.
+        // ---------------------------------------------------------------------------------------------
+        Method method;
+        LinkedList<Method> methodsWithSameName;
+        if (this.methodMap == null) {
+            this.methodMap = new HashMap<String, LinkedList<Method>>();
+            Method[] methods = this.targetClass.getMethods();
+            for (int i = 0; i != methods.length; ++i) {
+                method = methods[i];
+                methodsWithSameName = this.methodMap.get(method.getName());
+                if (methodsWithSameName == null) {
+                    methodsWithSameName = new LinkedList<Method>();
+                    this.methodMap.put(method.getName(), methodsWithSameName);
+                }
+                methodsWithSameName.addFirst(method); // add lower methods first
+            }
+        }
+
+        // ------------------------------------------------------------------------
+        // Find the set of methods with the same name (do this twice, once with the
+        // original methods and once with the primitives) ...
+        // ------------------------------------------------------------------------
+        // List argClass = argumentsClasses;
+        for (int j = 0; j != 2; ++j) {
+            methodsWithSameName = this.methodMap.get(methodName);
+            if (methodsWithSameName == null) {
+                throw new NoSuchMethodException(methodName);
+            }
+            Iterator<Method> iter = methodsWithSameName.iterator();
+            Class<?>[] args;
+            Class<?> clazz;
+            boolean allMatch;
+            while (iter.hasNext()) {
+                method = iter.next();
+                args = method.getParameterTypes();
+                if (args.length == argumentsClassList.size()) {
+                    allMatch = true; // assume they all match
+                    for (int i = 0; i < args.length; ++i) {
+                        clazz = argumentsClassList.get(i);
+                        if (clazz != null) {
+                            if (!args[i].isAssignableFrom(clazz)) {
+                                allMatch = false; // found one that doesn't match
+                                i = args.length; // force completion
+                            }
+                        } else {
+                            // a null is assignable for everything except a primitive
+                            if (args[i].isPrimitive()) {
+                                allMatch = false; // found one that doesn't match
+                                i = args.length; // force completion
+                            }
+                        }
+                    }
+                    if (allMatch) {
+                        return method;
+                    }
+                }
+            }
+        }
+
+        throw new NoSuchMethodException(methodName);
+    }
+
+}


Property changes on: trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java	                        (rev 0)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java	2008-06-13 18:16:28 UTC (rev 287)
@@ -0,0 +1,167 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors. 
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.common.util;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class ReflectionTest {
+
+    private String string;
+    private List<String> stringList;
+    private Reflection stringReflection;
+    private Reflection stringListReflection;
+
+    @Before
+    public void setUp() throws Exception {
+        string = "This is string #";
+        stringList = new ArrayList<String>();
+        for (int i = 0; i != 10; ++i) {
+            stringList.add(string + (i + 1));
+        }
+        stringReflection = new Reflection(String.class);
+        stringListReflection = new Reflection(List.class);
+    }
+
+    @Test
+    public void shouldGetClassNameForClass() {
+        assertThat(Reflection.getClassName(String.class), is(String.class.getName()));
+        assertThat(Reflection.getClassName(ArrayList.class), is(ArrayList.class.getName()));
+        assertThat(Reflection.getClassName(StringUtil.class), is(StringUtil.class.getName()));
+    }
+
+    @Test
+    public void shouldGetClassNameOfInterface() {
+        assertThat(Reflection.getClassName(CharSequence.class), is(CharSequence.class.getName()));
+        assertThat(Reflection.getClassName(List.class), is(List.class.getName()));
+    }
+
+    @Test
+    public void shouldGetClassNameWithPrimitive() {
+        assertThat(Reflection.getClassName(Integer.TYPE), is("int"));
+        assertThat(Reflection.getClassName(Boolean.TYPE), is("boolean"));
+        assertThat(Reflection.getClassName(Long.TYPE), is("long"));
+        assertThat(Reflection.getClassName(Short.TYPE), is("short"));
+        assertThat(Reflection.getClassName(Float.TYPE), is("float"));
+        assertThat(Reflection.getClassName(Double.TYPE), is("double"));
+        assertThat(Reflection.getClassName(Character.TYPE), is("char"));
+        assertThat(Reflection.getClassName(Byte.TYPE), is("byte"));
+        assertThat(Reflection.getClassName(Void.TYPE), is("void"));
+    }
+
+    @Test
+    public void shouldGetClassNameWith1DPrimitiveArray() {
+        assertThat(Reflection.getClassName(new int[0].getClass()), is("int[]"));
+        assertThat(Reflection.getClassName(new boolean[0].getClass()), is("boolean[]"));
+        assertThat(Reflection.getClassName(new long[0].getClass()), is("long[]"));
+        assertThat(Reflection.getClassName(new short[0].getClass()), is("short[]"));
+        assertThat(Reflection.getClassName(new float[0].getClass()), is("float[]"));
+        assertThat(Reflection.getClassName(new double[0].getClass()), is("double[]"));
+        assertThat(Reflection.getClassName(new char[0].getClass()), is("char[]"));
+        assertThat(Reflection.getClassName(new byte[0].getClass()), is("byte[]"));
+    }
+
+    @Test
+    public void shouldGetClassNameWith2DPrimitiveArray() {
+        assertThat(Reflection.getClassName(new int[0][0].getClass()), is("int[][]"));
+        assertThat(Reflection.getClassName(new boolean[0][0].getClass()), is("boolean[][]"));
+        assertThat(Reflection.getClassName(new long[0][0].getClass()), is("long[][]"));
+        assertThat(Reflection.getClassName(new short[0][0].getClass()), is("short[][]"));
+        assertThat(Reflection.getClassName(new float[0][0].getClass()), is("float[][]"));
+        assertThat(Reflection.getClassName(new double[0][0].getClass()), is("double[][]"));
+        assertThat(Reflection.getClassName(new char[0][0].getClass()), is("char[][]"));
+        assertThat(Reflection.getClassName(new byte[0][0].getClass()), is("byte[][]"));
+    }
+
+    @Test
+    public void shouldGetClassNameWith3DPrimitiveArray() {
+        assertThat(Reflection.getClassName(new int[0][0][0].getClass()), is("int[][][]"));
+        assertThat(Reflection.getClassName(new boolean[0][0][0].getClass()), is("boolean[][][]"));
+        assertThat(Reflection.getClassName(new long[0][0][0].getClass()), is("long[][][]"));
+        assertThat(Reflection.getClassName(new short[0][0][0].getClass()), is("short[][][]"));
+        assertThat(Reflection.getClassName(new float[0][0][0].getClass()), is("float[][][]"));
+        assertThat(Reflection.getClassName(new double[0][0][0].getClass()), is("double[][][]"));
+        assertThat(Reflection.getClassName(new char[0][0][0].getClass()), is("char[][][]"));
+        assertThat(Reflection.getClassName(new byte[0][0][0].getClass()), is("byte[][][]"));
+    }
+
+    @Test
+    public void shouldGetClassNameWith8DPrimitiveArray() {
+        assertThat(Reflection.getClassName(new int[0][0][0][0][0][0][0][0].getClass()), is("int[][][][][][][][]"));
+        assertThat(Reflection.getClassName(new boolean[0][0][0][0][0][0][0][0].getClass()), is("boolean[][][][][][][][]"));
+        assertThat(Reflection.getClassName(new long[0][0][0][0][0][0][0][0].getClass()), is("long[][][][][][][][]"));
+        assertThat(Reflection.getClassName(new short[0][0][0][0][0][0][0][0].getClass()), is("short[][][][][][][][]"));
+        assertThat(Reflection.getClassName(new float[0][0][0][0][0][0][0][0].getClass()), is("float[][][][][][][][]"));
+        assertThat(Reflection.getClassName(new double[0][0][0][0][0][0][0][0].getClass()), is("double[][][][][][][][]"));
+        assertThat(Reflection.getClassName(new char[0][0][0][0][0][0][0][0].getClass()), is("char[][][][][][][][]"));
+        assertThat(Reflection.getClassName(new byte[0][0][0][0][0][0][0][0].getClass()), is("byte[][][][][][][][]"));
+    }
+
+    @Test
+    public void shouldHaveTargetClass() {
+        assertThat(stringReflection.getTargetClass() == String.class, is(true));
+        assertThat(stringListReflection.getTargetClass() == List.class, is(true));
+    }
+
+    @Test
+    public void shouldFindMethodsWithExactMatchingName() {
+        Method[] stringMethods = stringReflection.findMethods("indexOf");
+        assertThat(stringMethods.length, is(4));
+        for (Method method : stringMethods) {
+            assertThat(method.getName(), is("indexOf"));
+        }
+        stringMethods = stringReflection.findMethods("length");
+        assertThat(stringMethods.length, is(1));
+        for (Method method : stringMethods) {
+            assertThat(method.getName(), is("length"));
+        }
+    }
+
+    @Test
+    public void shouldFindMethodsWithNameMatchingRegularExpression() {
+        Method[] stringMethods = stringReflection.findMethods("indexO.");
+        assertThat(stringMethods.length, is(4));
+        for (Method method : stringMethods) {
+            assertThat(method.getName(), is("indexOf"));
+        }
+        stringMethods = stringReflection.findMethods(".+gth");
+        assertThat(stringMethods.length, is(1));
+        for (Method method : stringMethods) {
+            assertThat(method.getName(), is("length"));
+        }
+    }
+
+    @Test
+    public void shouldNotFindMethodsWhenThereAreNoMethodsWithThatName() {
+        assertThat(stringReflection.findMethods("size").length, is(0));
+        assertThat(stringListReflection.findMethods("argleBargle").length, is(0));
+    }
+
+}


Property changes on: trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain




More information about the dna-commits mailing list