Typ Generic Reflections ermitteln

mrno

Erfahrenes Mitglied
Hallo zusammen,

ich hoffe ihr könnt mir mal wieder weiterhelfen.

Ich will meine Parserklassen dynamisch mit Generic Attributes laden.
Gibt es bei folgenden Code eine Möglichkeit herauszufinden von welchem Typ mein Generic Object sein soll?

Code:
public static <T> T parse(String data){
		Class T = ?
		Parser parser=new Parser.getParser(type);
		return parser.parse(data);
	}

Würde eine Generic Class verwendet werden ist dies über
Code:
getClass().getGenericSuperclass()
möglich. Da es sich aber oben nur um eine Methode handelt geht dieses so nicht. Hoffe da gibt es eine andere Möglichkeit.
 
Hallo,

Informationen zu Generics werden zur Compilezeit aus dem Bytecode entfernt (type erasure), es gibt jedoch ein paar "Tricks" wie man die Information "erhalten" kann.

schau mal hier:
Java:
package de.tutorials;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.List;

import com.sun.xml.internal.rngom.digested.DDataPattern.Param;

public class GenericParserExample {

   public static void main(String[] args) {

      String source = "[1,2,3]";

      /*
       * Variante 1 Typ explizit mitgeben
       */
      List<Integer> list1 = Parser.parse1(source, List.class);
      System.out.println(list1);

      /*
       * Variante 2 Typ implizit über Varargs ComponentType ermitteln
       * 
       * Für den Varags Parameter types wird beim Aufruf durch den Compiler implizt eine Array-Instanziierung vom Typ T 
       * mit den übergeben Argumenten definiert. Werden keine Varargs-Argumente übergeben wird in dem obigen Beispiel
       * die Anweisung new List[0] beim Methodenaufruf generiert.  
       */
      List<Integer> list2 = Parser.parse2(source);
      System.out.println(list2);

      /*
       * Variante 3 Anonyme inner class definieren
       */
      List<Integer> list3 = new GenericParser<List<Integer>>(){}.parse(source);
      System.out.println(list3);
      
      /*
       * Variante 4 Explizite typisierte Klasse defineren
       */
      List<Integer> list4 = new IntListParser().parse(source);
      System.out.println(list4);
   }

   static class Parser {
      
      public static <T> T parse1(String source, Class<T> type) { 
	 System.out.printf("Get Parser for: %s in %s%n",type , Thread.currentThread().getStackTrace()[1]);
	 return type.cast(null);
      }

      
      public static <T> T parse2(String source, T... types) {  
	 @SuppressWarnings("unchecked")
	 Class<T> type = (Class<T>) types.getClass().getComponentType();
	 System.out.printf("Get Parser for: %s in %s%n", type , Thread.currentThread().getStackTrace()[1]);
	 return type.cast(null);
      }
   }
      
   static abstract class GenericParser<T>{
      public T parse(String source){
	 
	 Type type = ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	 
	 if(type instanceof ParameterizedType){
	    type = ((ParameterizedType) type).getRawType();
	 }
	 
	 System.out.printf("Get Parser for: %s in %s%n", type , Thread.currentThread().getStackTrace()[1]);
	 //return type.cast(null);
	 return null;
      }
   }
   
   static class IntListParser extends GenericParser<List<Integer>>{
      
   }
   
   
}

Ausgabe:
Code:
Get Parser for: interface java.util.List in de.tutorials.GenericParserExample$Parser.parse1(GenericParserExample.java:53)
null
Get Parser for: interface java.util.List in de.tutorials.GenericParserExample$Parser.parse2(GenericParserExample.java:61)
null
Get Parser for: interface java.util.List in de.tutorials.GenericParserExample$GenericParser.parse(GenericParserExample.java:75)
null
Get Parser for: interface java.util.List in de.tutorials.GenericParserExample$GenericParser.parse(GenericParserExample.java:75)
null

Ich würde Dir empfehlen hier die explizite Variante 1 vorzuziehen. Variante 1 ist IMHO klarer, verständlicher, performanter und nicht so fehleranfällig wie Variante 2.

Gruß Tom
 
Zurück