From 17af80b7687436a3ac3ff0930bfcbea52d8cf663 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Fri, 13 Jan 2012 19:44:31 +0100 Subject: [PATCH] SONAR-3169 API: new utility class org.sonar.api.utils.FieldUtils --- .../java/org/sonar/api/utils/FieldUtils.java | 70 ++++++++++ .../org/sonar/api/utils/FieldUtilsTest.java | 132 ++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/utils/FieldUtils.java create mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/utils/FieldUtilsTest.java diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/FieldUtils.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/FieldUtils.java new file mode 100644 index 00000000000..6efb1507f85 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/FieldUtils.java @@ -0,0 +1,70 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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 3 of the License, or (at your option) any later version. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.api.utils; + +import com.google.common.collect.Lists; +import org.apache.commons.lang.ClassUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.List; + +/** + * Add features missing in org.apache.commons.lang3.reflect.FieldUtils + * + * @since 2.14 + */ +public final class FieldUtils { + private FieldUtils() { + } + + /** + * Get accessible Field breaking scope if requested. Superclasses/interfaces are considered. + * + * @param clazz the class to reflect, must not be null + * @param forceAccess whether to break scope restrictions using the setAccessible method. + * False only matches public fields. + */ + public static List getFields(Class clazz, boolean forceAccess) { + List result = Lists.newArrayList(); + Class c = clazz; + while (c != null) { + for (Field declaredField : c.getDeclaredFields()) { + if (!Modifier.isPublic(declaredField.getModifiers())) { + if (forceAccess) { + declaredField.setAccessible(true); + } else { + continue; + } + } + result.add(declaredField); + } + c = c.getSuperclass(); + } + + for (Object anInterface : ClassUtils.getAllInterfaces(clazz)) { + for (Field declaredField : ((Class) anInterface).getDeclaredFields()) { + result.add(declaredField); + } + } + + return result; + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/FieldUtilsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/FieldUtilsTest.java new file mode 100644 index 00000000000..18f2b36e6d1 --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/FieldUtilsTest.java @@ -0,0 +1,132 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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 3 of the License, or (at your option) any later version. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.api.utils; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.List; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import static org.junit.matchers.JUnitMatchers.hasItem; + +public class FieldUtilsTest { + + @Test + public void shouldGetFieldsOfSingleClass() { + List fields = FieldUtils.getFields(FieldsWithDifferentModifiers.class, true); + assertThat(fields, hasItem(new FieldMatcher("publicField"))); + assertThat(fields, hasItem(new FieldMatcher("protectedField"))); + assertThat(fields, hasItem(new FieldMatcher("packageField"))); + assertThat(fields, hasItem(new FieldMatcher("privateField"))); + assertThat(fields, hasItem(new FieldMatcher("publicStaticField"))); + assertThat(fields, hasItem(new FieldMatcher("protectedStaticField"))); + assertThat(fields, hasItem(new FieldMatcher("packageStaticField"))); + assertThat(fields, hasItem(new FieldMatcher("privateStaticField"))); + assertThat(fields.size(), is(8)); + } + + @Test + public void shouldGetFieldsOfClassHierarchy() { + List fields = FieldUtils.getFields(Child.class, true); + + assertThat(fields, hasItem(new FieldMatcher("publicField"))); + assertThat(fields, hasItem(new FieldMatcher("protectedField"))); + assertThat(fields, hasItem(new FieldMatcher("packageField"))); + assertThat(fields, hasItem(new FieldMatcher("privateField"))); + assertThat(fields, hasItem(new FieldMatcher("publicStaticField"))); + assertThat(fields, hasItem(new FieldMatcher("protectedStaticField"))); + assertThat(fields, hasItem(new FieldMatcher("packageStaticField"))); + assertThat(fields, hasItem(new FieldMatcher("privateStaticField"))); + + assertThat(fields, hasItem(new FieldMatcher("childPrivateField"))); + + assertThat(fields.size(), is(8 + 1)); + } + + @Test + public void shouldGetOnlyAccessibleFields() { + List fields = FieldUtils.getFields(Child.class, false); + + assertThat(fields, hasItem(new FieldMatcher("publicField"))); + assertThat(fields, hasItem(new FieldMatcher("publicStaticField"))); + assertThat(fields.size(), is(2)); + } + + @Test + public void shouldGetFieldsOfInterface() { + List fields = FieldUtils.getFields(InterfaceWithFields.class, true); + + assertThat(fields, hasItem(new FieldMatcher("INTERFACE_FIELD"))); + assertThat(fields.size(), is(1)); + } + + @Test + public void shouldGetFieldsOfInterfaceImplementation() { + List fields = FieldUtils.getFields(InterfaceImplementation.class, true); + + assertThat(fields, hasItem(new FieldMatcher("INTERFACE_FIELD"))); + assertThat(fields.size(), is(1)); + } + + static interface InterfaceWithFields { + String INTERFACE_FIELD = "foo"; + } + + static class InterfaceImplementation implements InterfaceWithFields { + } + + static class FieldsWithDifferentModifiers { + public String publicField; + protected String protectedField; + String packageField; + private String privateField; + + public static String publicStaticField; + protected static String protectedStaticField; + static String packageStaticField; + private static String privateStaticField; + } + + static class Child extends FieldsWithDifferentModifiers { + private String childPrivateField; + } + + + static class FieldMatcher extends BaseMatcher { + private String name; + + FieldMatcher(String name) { + this.name = name; + } + + public boolean matches(Object o) { + Field field = (Field) o; + return name.equals(field.getName()); + } + + public void describeTo(Description description) { + description.appendText("Field with name: ").appendValue(name); + } + } +} -- 2.39.5