diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index 4f49e8a3b49..7cae36cb931 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -295,6 +295,8 @@ Release 2.2.0 - UNRELEASED IMPROVEMENTS + HADOOP-9661. Allow metrics sources to be extended. (sandyr via tucu) + OPTIMIZATIONS BUG FIXES diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MetricsSourceBuilder.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MetricsSourceBuilder.java index 82672fcf406..06692974959 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MetricsSourceBuilder.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MetricsSourceBuilder.java @@ -33,6 +33,7 @@ import org.apache.hadoop.metrics2.MetricsInfo; import org.apache.hadoop.metrics2.MetricsSource; import org.apache.hadoop.metrics2.annotation.Metric; import org.apache.hadoop.metrics2.annotation.Metrics; +import org.apache.hadoop.util.ReflectionUtils; /** * Helper class to build {@link MetricsSource} object from annotations. @@ -63,10 +64,10 @@ public class MetricsSourceBuilder { Class cls = source.getClass(); registry = initRegistry(source); - for (Field field : cls.getDeclaredFields()) { + for (Field field : ReflectionUtils.getDeclaredFieldsIncludingInherited(cls)) { add(source, field); } - for (Method method : cls.getDeclaredMethods()) { + for (Method method : ReflectionUtils.getDeclaredMethodsIncludingInherited(cls)) { add(source, method); } } @@ -97,7 +98,7 @@ public class MetricsSourceBuilder { Class cls = source.getClass(); MetricsRegistry r = null; // Get the registry if it already exists. - for (Field field : cls.getDeclaredFields()) { + for (Field field : ReflectionUtils.getDeclaredFieldsIncludingInherited(cls)) { if (field.getType() != MetricsRegistry.class) continue; try { field.setAccessible(true); diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java index bf12de633fb..4fee5f4f952 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java @@ -25,7 +25,10 @@ import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -302,4 +305,36 @@ public class ReflectionUtils { buffer.moveData(); dst.readFields(buffer.inBuffer); } + + /** + * Gets all the declared fields of a class including fields declared in + * superclasses. + */ + public static List getDeclaredFieldsIncludingInherited(Class clazz) { + List fields = new ArrayList(); + while (clazz != null) { + for (Field field : clazz.getDeclaredFields()) { + fields.add(field); + } + clazz = clazz.getSuperclass(); + } + + return fields; + } + + /** + * Gets all the declared methods of a class including methods declared in + * superclasses. + */ + public static List getDeclaredMethodsIncludingInherited(Class clazz) { + List methods = new ArrayList(); + while (clazz != null) { + for (Method method : clazz.getDeclaredMethods()) { + methods.add(method); + } + clazz = clazz.getSuperclass(); + } + + return methods; + } } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestReflectionUtils.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestReflectionUtils.java index cb7ea38beb6..56e86ef9ff1 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestReflectionUtils.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestReflectionUtils.java @@ -18,9 +18,12 @@ package org.apache.hadoop.util; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.HashMap; +import java.util.List; import static org.junit.Assert.*; import org.junit.Before; @@ -109,6 +112,51 @@ public class TestReflectionUtils { System.gc(); assertTrue(cacheSize()+" too big", cacheSize() fields = ReflectionUtils.getDeclaredFieldsIncludingInherited( + child.getClass()); + boolean containsParentField = false; + boolean containsChildField = false; + for (Field field : fields) { + if (field.getName().equals("parentField")) { + containsParentField = true; + } else if (field.getName().equals("childField")) { + containsChildField = true; + } + } + + List methods = ReflectionUtils.getDeclaredMethodsIncludingInherited( + child.getClass()); + boolean containsParentMethod = false; + boolean containsChildMethod = false; + for (Method method : methods) { + if (method.getName().equals("getParentField")) { + containsParentMethod = true; + } else if (method.getName().equals("getChildField")) { + containsChildMethod = true; + } + } + + assertTrue("Missing parent field", containsParentField); + assertTrue("Missing child field", containsChildField); + assertTrue("Missing parent method", containsParentMethod); + assertTrue("Missing child method", containsChildMethod); + } + + // Used for testGetDeclaredFieldsIncludingInherited + private class Parent { + private int parentField; + @SuppressWarnings("unused") + public int getParentField() { return parentField; } + } private static class LoadedInChild { }