Avatar billede kernelx Juniormester
28. januar 2018 - 11:25 Der er 2 kommentarer og
2 løsninger

Nested Generic Types

Hi,

jeg har en java method, som har et argument mehr følgende generic types:
===
public class Foo {

    public void doFoo(final Map<String,List<BigInteger>> fooArg) {

    }

}
===

Jeg ved, hvordan jeg kan få fat i de generic types String og List via reflection.
Men er det også mugligt at få fat i en generic type som er del af en generic type (for eksempel BigInteger i ovenstående kode)?

Med venlig hilsen
KernelX
Avatar billede arne_v Ekspert
28. januar 2018 - 16:18 #1
Jeg tror at det er et vanskeligt problem p.g.a. Java generics type erasure.

Jeg kunne ikke komme laengere end:


import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

public class GenericsFun {
    public void something(final Map<String,List<BigInteger>> ml) {
    }
    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Method[] m = GenericsFun.class.getMethods();
        for(Method m1 : m) {
            System.out.println(m1.getName());
            Class<?>[] clz = m1.getParameterTypes();
            Type[] typ = m1.getGenericParameterTypes();
            for(int i = 0; i < m1.getParameterCount(); i++) {
                System.out.printf("  %s = %s\n",clz[i].getName(), typ[i].getTypeName());
            }
        }
    }
}
Avatar billede kernelx Juniormester
29. januar 2018 - 13:43 #2
Er det en standard output? Så man bli'r nødt til at parse det
Avatar billede kernelx Juniormester
29. januar 2018 - 18:08 #3
Jeg har fundet ud af, at Type kan enten blive casted til
Class (hvis der ikke er nogen sub generic types) eller til
ParameterizedType (hvis der er nogen sub generic types).

følgende kode er lidt ugly, men demonstrerer, hvordan det er mugligt at få fat i informationerne:

...
public void something(final Map<String,List<BigInteger>> ml) {
    }
    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        final Method[] methods = ExchangeSessionContext.class.getMethods();
        for (final Method method : methods) {
            if ("something".equals(method.getName())) {
                System.out.println(method.getName());
                final AtomicInteger counter = new AtomicInteger(0);
                final Type[] types = method.getGenericParameterTypes();
                for (final Type type : types) {
                    final int index = counter.getAndIncrement();
                    if (type instanceof ParameterizedType) {
                        final ParameterizedType parameterizedType = (ParameterizedType) type;
                        final Type[] subTypes = parameterizedType.getActualTypeArguments();
                        for (int i = 0; i < subTypes.length; i += 1) {
                            final Type subType = subTypes[i];
                            if (subType instanceof ParameterizedType) {
                                final ParameterizedType subParameterizedType = (ParameterizedType) subType;
                                final Type[] subSubTypes = subParameterizedType.getActualTypeArguments();
                                for (int i2 = 0; i2 < subSubTypes.length; i2 += 1) {
                                    final Type subSubType = subSubTypes[i2];
                                    if (subSubType instanceof Class) {
                                        final Class<?> subSubTypeCls = (Class<?>) subSubType;
                                        final Class<?> subTypeCls = (Class<?>) subParameterizedType.getRawType();
                                        System.out.println(index + ": type=parameterizedType, subIndex=" + i + ", subSubIndex=" + i2 + ", subType=" + subTypeCls.getCanonicalName() + ", subSubType=" + subSubTypeCls.getCanonicalName());
                                    }
                                }
                            } else if (subType instanceof Class) {
                                final Class<?> subClass = (Class<?>) subType;
                                System.out.println(index + ": type=parameterizedType, subIndex=" + i + ", subType=" + subClass.getCanonicalName());
                            }
                        }
                    } else {
                        final Class<?> cls = (Class<?>) type;
                        System.out.println(index + ": type=class, value=" + cls.getCanonicalName());
                    }
                }
            }
        }
    }
...

Outout:
something
0: type=parameterizedType, subIndex=0, subType=java.lang.String
0: type=parameterizedType, subIndex=1, subSubIndex=0, subType=java.util.List, subSubType=java.math.BigInteger

Mange tak for hjælpen!
Avatar billede arne_v Ekspert
30. januar 2018 - 14:44 #4
Det er godt nok et traels API.

Jeg arbejdede lidt videre med cast'ene.


import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class TypeInfo {
    private Class<?> clz;
    private List<TypeInfo> params;
    public TypeInfo(Class<?> clz) {
        this.clz = clz;
        this.params = new ArrayList<>();
    }
    public Class<?> getRawClass() {
        return clz;
    }
    public List<TypeInfo> getParams() {
        return params;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(clz.getName());
        if(getParams().size() > 0) {
            sb.append("<");
            sb.append(getParams().stream().map(TypeInfo::toString).collect(Collectors.joining(",")));
            sb.append(">");
        }
        return sb.toString();
    }
    public static TypeInfo analyze(Type typ) {
        TypeInfo res = null;
        if(typ instanceof Class) {
            res = new TypeInfo((Class<?>)typ);
        }
        if(typ instanceof ParameterizedType) {
            ParameterizedType ptyp = (ParameterizedType)typ;
            res = new TypeInfo((Class<?>)ptyp.getRawType());
            for(Type t : ptyp.getActualTypeArguments()) {
                res.getParams().add(analyze(t));
            }
        }
        return res;
    }
}



import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

public class GenericsFun {
    public void something(final Map<String,List<BigInteger>> ml) {
    }
    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Method[] m = GenericsFun.class.getMethods();
        for(Method m1 : m) {
            System.out.println(m1.getName());
            for(Type typ : m1.getGenericParameterTypes()) {
                TypeInfo typinf = TypeInfo.analyze(typ);
                System.out.println("  " + typinf);
            }
        }
    }
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester