2016-07-02 10 views
1

バックグラウンドについては、私が開発しているプログラミング言語(つまりJVM言語)のフレームワークに取り組んでおり、Javaクラスでフレームワークをテストしていました。下のすべての奇妙なラッパー。ジェネリック型のジェネリックパラメータを取得する


私の質問は、どうやって型パラメータの境界の型変数を得るのですか?現在、私は次があります。

public static TemplateGenerics of(Class clazz) { 
    TemplateGenerics generics = new TemplateGenerics(); //TemplateGenerics is a wrapper class for generics that appear in the class header 
    Stream.of(clazz.getTypeParameters()).forEach(typeVariable -> { 
     java.lang.reflect.Type b = typeVariable.getBounds()[0]; 
     try { 
      Class c = Primitives.resolveClass(b.getTypeName().split("<", 2)[0]); //Is there a better way to do this? 
      TemplateGenerics sub = TemplateGenerics.of(c); //Recursivley get the generics - it fails here 
      generics.getConditionals().add(new Conditional(new Type.Hierarchical(sub, c.getName()), Conditional.Condition.EXTENDS, typeVariable.getName())); //Conditional is another wrapper class that handles bounds of the generic, 
                                          //Type.Hierachical is yet another wrapper class that wraps types that appear in class headers 
     } catch (ClassNotFoundException e) { 
      throw new RuntimeException(e); //For testing purposes 
     } 
    }); 
    return generics; 
} 

しかし、それはこのようなものに遭遇したとき、このでStackOverflowExceptionで失敗します。

public class A<T extends A<T>> ...

それだけで何度もの型パラメータを取得しようとし続けているので。私は、型変数の型変数を取得する方法を見つけることができませんでした...私はgetGenericDeclarationを使いこなそうとしましたが、必要なものを返さないようです。どんな助けでも大歓迎です。

+2

'A >'と 'B >'も考慮する必要があります。一般に、サイクルを避けるためには、すでに処理されたタイプと現在処理さ処理を開始するが、終了しないタイプに遭遇した場合は、いくつかのプレースホルダを使用する必要があります。そして、すべてのタイプを処理した後、適切な結果でプレースホルダを置き換えてください。 – csharpfolk

+0

ええ、私はマップでそのようなことを試みました。私が必要とする情報をどのように入手するのか正確にはわかりません。 –

答えて

1

@csharpfolkは、すでに解析されていることを把握し、それを活用することを示唆するのは正しいです。以下はコンパイル&実行可能な例で、これはあなたの問題に対して実際にどのように見えるかをデモします。

package so.answers; 

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.stream.Stream; 

public class TemplateGenerics { 

    private final List<Conditional> conditionals = new ArrayList<>(); 

    public List<Conditional> getConditionals(){ 
     return conditionals; 
    } 

    public String toString(){ 
     return getConditionals().toString(); 
    } 

    public static TemplateGenerics of(Class<?> clazz) { 
     return TemplateGenerics.of(clazz, new HashMap<>()); 
    } 

    private static TemplateGenerics of(Class<?> clazz, Map<Class<?>, TemplateGenerics> existingGenericsForClasses) { 
     if(existingGenericsForClasses.containsKey(clazz)){ 
      return existingGenericsForClasses.get(clazz); 
     } 
     final TemplateGenerics generics = new TemplateGenerics(); 
     existingGenericsForClasses.put(clazz, generics); 

     Stream.of(clazz.getTypeParameters()).forEach(typeVariable -> { 
      java.lang.reflect.Type b = typeVariable.getBounds()[0]; 
      try { 
       Class<?> c = Primitives.resolveClass(b.getTypeName().split("<", 2)[0]); //Is there a better way to do this? 
       TemplateGenerics sub = TemplateGenerics.of(c, existingGenericsForClasses); //Recursivley get the generics - it fails here 
       generics.getConditionals().add(new Conditional(new Type.Hierarchical(sub, c.getName()), Conditional.Condition.EXTENDS, typeVariable.getName())); //Conditional is another wrapper class that handles bounds of the generic, 
                                           //Type.Hierachical is yet another wrapper class that wraps types that appear in class headers 
      } catch (ClassNotFoundException e) { 
       throw new RuntimeException(e); //For testing purposes 
      } 
     }); 
     return generics; 
    } 

    public static class Conditional{ 
     public static enum Condition{ 
      EXTENDS, 
      SUPER 
     } 

     private final Type.Hierarchical hierarchical; 
     private final Condition condition; 
     private final String typeName; 

     public Conditional(Type.Hierarchical hierarchical, Condition condition, String typeName){ 
      this.hierarchical = hierarchical; 
      this.condition = condition; 
      this.typeName = typeName; 
     } 

     public String toString(){ 
      return "Conditional$typeName="+typeName+" " 
        +"Conditional$condition="+condition+" " 
        +"Conditional$hierarchical={"+hierarchical+"} ";      
     } 
    } 

    public static class Primitives{ 
     public static Class<?> resolveClass(String name) throws ClassNotFoundException{ 
      String trimmedName = name.replaceFirst(TemplateGenerics.class.getCanonicalName()+".", ""); 

      //not sure why this nonsense with the trimmed name 
      //is necessary, but you seem to already have a better 
      //version of this method anyway 
      if(trimmedName.contains(TemplateGenerics.class.getCanonicalName())){ 
       name = trimmedName; 
      } 
      return Primitives.class.getClassLoader().loadClass(name); 
     } 
    } 

    public static class Type{ 
     public static class Hierarchical{ 
      private TemplateGenerics generics; 
      private String name; 

      public Hierarchical(TemplateGenerics generics, String name){ 
       this.generics = generics; 
       this.name = name; 
      } 


      private boolean printing; 

      public String toString(){ 
       try{ 
        if(!printing){ 
         printing = true; 
         return "Hierarchical$name="+name+ " Hierarchical$generics=("+generics+")"; 
        } else { 
         return "Hierarchical$name="+name; 
        } 
       } finally { 
        printing = false; 
       } 
      } 
     } 
    } 

    public static class B{ 

    } 

    public static class C<T extends B>{ 

    } 

    public static class A<T extends A<T>>{ 

    } 

    public static class X<T extends Y>{ 

    } 

    public static class Y<T extends X>{ 

    } 

    public static void main(String[] args){ 
     System.out.println("For A:"+TemplateGenerics.of(A.class)); 
     System.out.println("For C:"+TemplateGenerics.of(C.class)); 
     System.out.println("For X:"+TemplateGenerics.of(X.class)); 
    } 
} 

出力:

For A:[Conditional$typeName=T Conditional$condition=EXTENDS Conditional$hierarchical={Hierarchical$name=so.answers.TemplateGenerics$A Hierarchical$generics=([Conditional$typeName=T Conditional$condition=EXTENDS Conditional$hierarchical={Hierarchical$name=so.answers.TemplateGenerics$A} ])} ] 
For C:[Conditional$typeName=T Conditional$condition=EXTENDS Conditional$hierarchical={Hierarchical$name=so.answers.TemplateGenerics$B Hierarchical$generics=([])} ] 
For X:[Conditional$typeName=T Conditional$condition=EXTENDS Conditional$hierarchical={Hierarchical$name=so.answers.TemplateGenerics$Y Hierarchical$generics=([Conditional$typeName=T Conditional$condition=EXTENDS Conditional$hierarchical={Hierarchical$name=so.answers.TemplateGenerics$X Hierarchical$generics=([Conditional$typeName=T Conditional$condition=EXTENDS Conditional$hierarchical={Hierarchical$name=so.answers.TemplateGenerics$Y} ])} ])} ] 

あなたが直接ジェネリック医薬品ではなく、種類を印刷することにより、少し冗長に見えるし、印刷をクリーンアップすることができます。しかし、これはソリューションの顕著な特徴をすべて示しています。

+0

**注記編集**:ビットを印刷してクリーンアップ – augray

+0

ありがとう!それは私がやったことと基本的に同じです。 –

関連する問題