Monday, October 23, 2017

Java Advanced Generics Examples Part 3 - Initiation and Type Safe

Sometimes there are need to pass in annotation info as String or object instances, in order to guard the type safety, aClass.cast or aClass.asSubclass methods could be used to validate the string or object instances belong to types expected.


public class GenericTypeSafe {

       @Test
       public void testTypeSafeCache() {
             System.out.println("===testTypeSafeCache===");
             final TypeSafeCache cache = new TypeSafeCache();
             cache.put(Integer.class, 1);
             cache.put(Long.class, 1L);
             cache.put(Double.class, 1.0);
             System.out.println(cache.get(Integer.class));
             System.out.println(cache.get(Long.class));
             System.out.println(cache.get(Double.class));
       }

       @Test
       public void testTypeSafeAnnotationType() throws NoSuchMethodException, SecurityException {
             System.out.println("===testTypeSafeAnnotationType===");
             final A<String, Integer> a = new A<>("A", 1);
             Method method = a.getClass().getMethod("getU");
             System.out.println("method:" + method);
             Annotation a1 = method.getAnnotation(A1.class);
             System.out.println("annotationType:" + a1.annotationType());
             System.out.println("annotationType().getCanonicalName():" + a1.annotationType().getCanonicalName());
             System.out.println(
                           "annotationType().getClass().getCanonicalName():" + a1.annotationType().getClass().getCanonicalName());
             System.out.println(".annotationType().getTypeName():" + a1.annotationType().getTypeName());
             System.out.println(".annotationType().getGenericSuperclass():" + a1.annotationType().getGenericSuperclass());
             Annotation result = getAnnotation(method, a1.annotationType().getTypeName());
             System.out.println("result:" + result);
       }

       @Retention(RetentionPolicy.RUNTIME)
       @Target({ ElementType.METHOD })
       public @interface A1 {
       }

       public static class TypeSafeCache {
             private Map<Class<?>, Object> cache = new HashMap<>();

             public <T> void put(Class<T> type, T instance) {
                    if (type != null) {
                           cache.put(type, type.cast(instance));
                    } else {
                           throw new RuntimeException("type is null.");
                    }
             }

             public <T> T get(Class<T> type) {
                    return type.cast(cache.get(type));
             }
       }

       public static Annotation getAnnotation(final AnnotatedElement element, final String annotationTypeName) {
             Class<?> annotationType = null;
             try {
                    annotationType = Class.forName(annotationTypeName);
             } catch (Exception ex) {
                    throw new IllegalArgumentException(ex);
             }
             System.out.println("annotationType:" + annotationType);
             return element.getAnnotation(annotationType.asSubclass(Annotation.class));
       }
}



If a class has a type parameter but the instance of the type should be automatically initiated instead of being passed in, here are examples:


public class GenericInitiation {
       public static class Foo<T> {
             private Class<T> clazz;
            
             public Foo(Class<T> clazz) {
                    this.clazz = clazz;
             }
            
             public T getInstanceOfT() throws InstantiationException, IllegalAccessException {
                    return clazz.newInstance();
             }

             public T getInstanceOfTInSubClass() {
                    final ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
                    @SuppressWarnings("unchecked")
                    Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0];
                    try {
                           return type.newInstance();
                    } catch (Exception e) {
                           throw new RuntimeException(e);
                    }
             }
       }

       private static class Bar extends Foo<String> {
             public Bar(Class<String> clazz) {
                    super(clazz);
             }
       }

       @Test
       public void testInitiation() throws InstantiationException, IllegalAccessException {
             System.out.println("===testSubClassInitiation===");
             Foo<Random> foo = new Foo<>(Random.class);
             System.out.println(foo.getInstanceOfT().getClass());
             Bar bar = new Bar(String.class);
             System.out.println(bar.getInstanceOfTInSubClass().getClass());
       }
}



No comments:

Post a Comment