web-dev-qa-db-ja.com

クラスが再帰的に拡張または実装するすべてのクラスとインターフェイスを検索する

Javaクラスが再帰的に拡張または実装するタイプの完全なリストを決定する簡単な方法があるかどうか疑問に思いましたか?

例えば:

class Foo extends Bar implements I1, I2 {...}
class Bar implements I3 {...}
interface I1 extends I4, I5 {...}
interface I2 {...}
interface I3 {...}
interface I4 {...}
interface I5 {...}

class ClassUtil {
    public static Set<Class<?>> getAllExtendedOrImplementedTypesRecursively(Class<?> clazz){
        ???
    }
}

import static org.junit.Assert.*;
public class ClassUtilTest {
    @Test
    public void shouldEqualClasses(){
        Set<Class<?>> types = ClassUtil.getAllExtendedOrImplementedTypesRecursively(Foo.class);
        Set<Class<?>> checklist = new HashSet<>();
        checklist.add(Foo.class);
        checklist.add(Bar.class);
        checklist.add(I1.class);
        checklist.add(I2.class);
        checklist.add(I3.class);
        checklist.add(I4.class);
        checklist.add(I5.class);
        assertTrue(checklist.containsAll(types));
        assertTrue(types.containsAll(checklist));
    }
}

ArquillianShrinkWrap作成ヘルパーを考えてみてください。

PDATE: ClassオブジェクトがComparableを実装していないため> Comparableインターフェイスを実装せずに(たとえば、のハッシュコードのみに依存して)Set(または同様のクラス)を作成する方法も見つける必要がありますクラスオブジェクト)。

PDATE:ハッシュセットを使用するようにテストを変更しました。 derp。

18
coderatchet

次のメソッドの実装は、OPが必要とすることを実行し、すべてのクラスとインターフェイスの継承階層をトラバースします。

public static Set<Class<?>> getAllExtendedOrImplementedTypesRecursively(Class<?> clazz) {
    List<Class<?>> res = new ArrayList<>();

    do {
        res.add(clazz);

        // First, add all the interfaces implemented by this class
        Class<?>[] interfaces = clazz.getInterfaces();
        if (interfaces.length > 0) {
            res.addAll(Arrays.asList(interfaces));

            for (Class<?> interfaze : interfaces) {
                res.addAll(getAllExtendedOrImplementedTypesRecursively(interfaze));
            }
        }

        // Add the super class
        Class<?> superClass = clazz.getSuperclass();

        // Interfaces does not have Java,lang.Object as superclass, they have null, so break the cycle and return
        if (superClass == null) {
            break;
        }

        // Now inspect the superclass 
        clazz = superClass;
    } while (!"Java.lang.Object".equals(clazz.getCanonicalName()));

    return new HashSet<Class<?>>(res);
}    

JFrame.classでテストしたところ、次のようになりました。

Set<Class<?>> classes = getAllExtendedOrImplementedTypesRecursively(JFrame.class);
for (Class<?> clazz : classes) {
    System.out.println(clazz.getName());
}

出力:

Java.awt.Container
Java.awt.Frame
javax.swing.JFrame
javax.swing.TransferHandler$HasGetTransferHandler
Java.awt.Window
javax.accessibility.Accessible
javax.swing.RootPaneContainer
Java.awt.Component
javax.swing.WindowConstants
Java.io.Serializable
Java.awt.MenuContainer
Java.awt.image.ImageObserver

PDATE: OPのテストケースの場合、次のように出力されます。

test.I5
test.Bar
test.I2
test.I1
test.Foo
test.I3
test.I4
13
higuaro

Apache Common Lang には、必要な2つのメソッドを持つClassUtilsがあります。 .getAllSuperClasses()および.getAllInterfaces()。

10
TA Nguyen

必要なキーはClass#getSuperclass()メソッドにあります。

public static Set<Class<?>> stuff(Class<?> target) {
    Set<Class<?>> classesInterfaces = new HashSet<>();
    classesInterfaces.add(target);
    classesInterfaces.addAll(Arrays.asList(target.getInterfaces());

    Class<?> superClass = target.getSuperclass();
    if(superClass != null)
        classesInterfaces.addAll(stuff(superClass));
}
2

私があなたの質問を正しければ、あなたは特定のクラスのすべてのスーパークラス(クラスとインターフェース)を見つけたいと思うでしょう。もしそうなら、あなたは次の解決策を確認することができます

スーパークラスを見つけるために

        Class C = getClass();
        while (C != null) {
          System.out.println(C.getSimpleName());
          C = C.getSuperclass();
        }

インターフェイスを見つけるには

        C = getClass();
        for(Class adf: C.getInterfaces()){

              System.out.println(adf.getSimpleName());
        }
1
stinepike

Java8では

import Java.util.Arrays;
import Java.util.Optional;
import Java.util.Set;
import Java.util.function.Predicate;
import Java.util.stream.Collectors;
import Java.util.stream.Stream;

public class ClassUtil {
    public static Set<Class<?>> getAllExtendedOrImplementedTypesRecursively(final Class<?> clazz) {
        return walk(clazz)
                .filter(Predicate.isEqual(Java.lang.Object.class).negate())
                .collect(Collectors.toSet());
    }

    public static Stream<Class<?>> walk(final Class<?> c) {
        return Stream.concat(Stream.of(c),
                Stream.concat(
                        Optional.ofNullable(c.getSuperclass()).map(Stream::of).orElseGet(Stream::empty),
                        Arrays.stream(c.getInterfaces())
                ).flatMap(ClassUtil::walk));
    }
}

テストコード:

import Java.util.Set;

class Test {
    public static void main(String[] args) {
        final Set<Class<?>> set = ClassUtil.getAllExtendedOrImplementedTypesRecursively(Foo.class);
        set.stream().map(Class::getName).forEach(System.out::println);
    }

    class Foo extends Bar implements I1, I2 {}
    class Bar implements I3 {}
    interface I1 extends I4, I5 {}
    interface I2 {}
    interface I3 {}
    interface I4 {}
    interface I5 {}
}

出力:

 Test $ Foo 
 Test $ Bar 
 Test $ I2 
 Test $ I5 
 Test $ I1 
 Test $ I3 
 Test $ I4 
 
1
otamega

クラスがFooの場合、コードは次のようになります。

public void getClassDetails() {

    Class klass = Foo.class;
    Class<?> superKlass = klass.getSuperClass();
    Class[] interfaces = klass.getInterfaces();
}
1
ravi.patel

質問から Javaで特定のクラスのすべてのサブクラスをどのように見つけますか?this 答えが役立つかもしれません:

クラスを使用する PojoClassImpl.Java メソッドgetSuperClass()を呼び出すことでスーパークラスを取得できます。再帰メソッドを書くにはそれで十分だと思います。

1
Miguel Jiménez

私はかつて、いくつかのShrinkWrapブランチでasmを使用して同様のメカニズムを実装しました https://github.com/mmatloka/shrinkwrap/commit/39d5c3aa63a9bb85e6d7b68782879ca10cca273b 。問題は、クラスが他のファイルに記載されていないインターフェイス実装であるオブジェクトを使用する可能性があるため、デプロイ中に失敗する可能性があることです。

少し前に私が知っていることから、公式の立場は、ShrinkWrapの中にそのような機能を含めるのではなく、ツールに依存することでした。 JBoss Tools、再帰的なクラス追加を可能にする機能はどこにあるべきですか。

0
mmatloka