samedi 25 août 2018

Would java allow me to assign this object to this generic field?

In my POJO editor I need to check whether the class name supplied by the user can be instantiated and assigned to a generic property. Guava reflection provides almost everything I need: I resolve the types and then call proptype.isSupertypeOf(implClazz), but this does not work as expected.

For example, I have the type token: java.util.Collection<java.sql.Timestamp> and I want my check to accept ArrayList and classes that extend raw ArrayList or ArrayList<Timestamp> or themselves are parameterized, but not accept a class that extends ArrayList<Integer>.

However, isSupertypeOf() only works well with fully resolved types, while incomplete and raw classes not treated as subtypes.

    package com.common.jsp.beans;

    import java.lang.reflect.Field;
    import java.lang.reflect.Type;
    import java.sql.Timestamp;
    import java.util.ArrayList;
    import java.util.Collection;

    import com.google.common.reflect.TypeToken;

    public class TestTypeInf
    {
        public static class MyCollection1 extends ArrayList<Integer> {
        }
        public static class MyCollection2 extends ArrayList<Timestamp> {
        }
        public static class MyCollection3<T> extends ArrayList<T> {
        }
        public static class MyCollection4 extends ArrayList {
        }

        public static Collection<Timestamp> fld;

        public static void main( String[] args )
                        throws Exception
        {
            // bad: fld = new MyCollection1();
            fld = new MyCollection2();
            fld = new MyCollection3(); // just a warning
            fld = new MyCollection4(); // just a warning

            Field getter = TestTypeInf.class.getField( "fld" );
            Type memberType = getter.getGenericType();

            TypeToken<?> resolved = TypeToken.of( TestTypeInf.class ).resolveType( memberType );
            System.out.println( "type of fld: " + resolved );

            checkAssignable(resolved, MyCollection1.class);
            checkAssignable(resolved, MyCollection2.class);
            checkAssignable(resolved, MyCollection3.class); // This should be totally valid
            checkAssignable(resolved, MyCollection4.class); // why no?
        }

        private static void checkAssignable(TypeToken<?> resolved, Class<?> implClass) {
            System.out.println( "fld = new " + implClass.getSimpleName() + "()" );
            System.out.println( resolved.isSupertypeOf( implClass ) ? "yes" : "no" );
        }
    }

_

type of fld: java.util.Collection<java.sql.Timestamp>
fld = new MyCollection1()
no
fld = new MyCollection2()
yes
fld = new MyCollection3()
no
fld = new MyCollection4()
no
fld = new ArrayList()
no





Aucun commentaire:

Enregistrer un commentaire