Java Checked Class Instantiation using Reflection

0

In this article, we will see how to create an instance of class in a type safe manner using java reflection.
We will be using the below methods from Class.

  1. Class.isAssignableFrom(class)
  2. Class.asSubclass(class)

Assume we want to create an instance of the below type where the implementation class name will be provided externally through some property file.

IAppContext:

package com.javarticles.reflection;

public interface IAppContext {
    String getName();
}

Here is our implementation of the above type.

AppContext:

package com.javarticles.reflection;

public class AppContext implements IAppContext {
    private String name;
    
    public AppContext() {        
    }
    
    public AppContext(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }        
}

Let’s write the simplest way of creating the new instance. In checkedInstanceOfUsingTypeCast, we load the class based on the class name provided and then call Class.newInstance() to create the new instance. We then type cast it to the type of the class.

ClassUtil:

package com.javarticles.reflection;

import java.lang.reflect.InvocationTargetException;

public class ClassUtil {
    public static  T checkedInstanceOfUsingTypeCast(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {        
        final Class<?> clazz = Class.forName(className);
        Object o = clazz.newInstance();
        return (T) o;
    }    
}

Compiler also issues a warning:

Type safety: Unchecked cast from Object to T

CheckedClassInsantiationExample:

package com.javarticles.reflection;


public class CheckedClassInsantiationExample {
    public static void main(String[] args) throws Exception {
        IAppContext appContext = ClassUtil.checkedInstanceOfUsingTypeCast(
                "com.javarticles.reflection.AppContext", IAppContext.class);
        System.out.println(appContext);
        try {
            IAppContext notAContext = ClassUtil.checkedInstanceOfUsingTypeCast(
                    "com.javarticles.reflection.ClassUtil", IAppContext.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
}

There is an error when we pass in “com.javarticles.reflection.ClassUtil” as the class name. This is obvious as the code ends up instantiating ClassUtil which it then tries to type cast the object created to IAppContext.

Output:

[email protected]
java.lang.ClassCastException: com.javarticles.reflection.ClassUtil cannot be cast to com.javarticles.reflection.IAppContext
	at com.javarticles.reflection.CheckedClassInsantiationExample.main(CheckedClassInsantiationExample.java:12)

Let’s introduce a new method which now verifies that the class being instantiated if of type IAppContext. It checks this using Class.isAssignableFrom(). If the class loaded is not of the type passed in then ClassCastException is thrown. This will save us from instantiating a wrong type.

ClassUtil:

package com.javarticles.reflection;

import java.lang.reflect.InvocationTargetException;

public class ClassUtil {
    public static  T checkedInstanceOfUsingTypeCast(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {        
        final Class<?> clazz = Class.forName(className);
        Object o = clazz.newInstance();
        return (T) o;
    }
    
    public static  T checkedInstanceOfUsingTypeCast1(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {
        
        final Class<?> clazz = Class.forName(className);
        if (!type.isAssignableFrom(clazz)) {
            throw new ClassCastException();
        }
        Object o = clazz.newInstance();
        return (T) o;
    }

Let’s test our second method.

CheckedClassInsantiationExample:

package com.javarticles.reflection;


public class CheckedClassInsantiationExample {
    public static void main(String[] args) throws Exception {
        IAppContext appContext = ClassUtil.checkedInstanceOfUsingTypeCast(
                "com.javarticles.reflection.AppContext", IAppContext.class);
        System.out.println(appContext);
        try {
            IAppContext notAContext = ClassUtil.checkedInstanceOfUsingTypeCast(
                    "com.javarticles.reflection.ClassUtil", IAppContext.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // isAssignableFrom
        try {
            IAppContext notAContext = ClassUtil
                    .checkedInstanceOfUsingTypeCast1(
                            "com.javarticles.reflection.ClassUtil",
                            IAppContext.class);
        } catch (Exception e) {
             e.printStackTrace();
        }

    }
}

Output:

[email protected]
java.lang.ClassCastException: com.javarticles.reflection.ClassUtil cannot be cast to com.javarticles.reflection.IAppContext
	at com.javarticles.reflection.CheckedClassInsantiationExample.main(CheckedClassInsantiationExample.java:10)
java.lang.ClassCastException
	at com.javarticles.reflection.ClassUtil.checkedInstanceOfUsingTypeCast1(ClassUtil.java:22)
	at com.javarticles.reflection.CheckedClassInsantiationExample.main(CheckedClassInsantiationExample.java:19)

Our second method looks fine but there is still some scope of improvement. Compiler issues warning:

Type safety: Unchecked cast from Object to T

Instead of explicitly type casting we can type cast the class to its actual class and then calltargetClass.newInstantiate(). Let’s add a third method to deal with this.

ClassUtil:

package com.javarticles.reflection;

import java.lang.reflect.InvocationTargetException;

public class ClassUtil {
    public static  T checkedInstanceOfUsingTypeCast(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {        
        final Class<?> clazz = Class.forName(className);
        Object o = clazz.newInstance();
        return (T) o;
    }
    
    public static  T checkedInstanceOfUsingTypeCast1(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {
        
        final Class<?> clazz = Class.forName(className);
        if (!type.isAssignableFrom(clazz)) {
            throw new ClassCastException();
        }
        Object o = clazz.newInstance();
        return (T) o;
    }

    public static  T checkedInstanceOfUsingTypeCast2(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {
        
        final Class<?> clazz = Class.forName(className);
        if (!type.isAssignableFrom(clazz)) {
            throw new ClassCastException();
        }
        final Class<? extends T> targetClass = (Class<? extends T>) clazz;
        T o = targetClass.newInstance();
        return o;
    }       
}

The only issue with this method is the compiler warning.

Type safety: Unchecked cast from Class<capture#10-of ?> to Class<? extends T>

There is already an existing method in Class object called asSubClass() which verifies its type and then typecasts the class loaded to its actual class.
Let’s add a new method that makes use of the asSubClass().

ClassUtil:

package com.javarticles.reflection;

import java.lang.reflect.InvocationTargetException;

public class ClassUtil {
    public static  T checkedInstanceOfUsingTypeCast(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {        
        final Class<?> clazz = Class.forName(className);
        Object o = clazz.newInstance();
        return (T) o;
    }
    
    public static  T checkedInstanceOfUsingTypeCast1(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {
        
        final Class<?> clazz = Class.forName(className);
        if (!type.isAssignableFrom(clazz)) {
            throw new ClassCastException();
        }
        Object o = clazz.newInstance();
        return (T) o;
    }

    public static  T checkedInstanceOfUsingTypeCast2(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {
        
        final Class<?> clazz = Class.forName(className);
        if (!type.isAssignableFrom(clazz)) {
            throw new ClassCastException();
        }
        final Class<? extends T> targetClass = (Class<? extends T>) clazz;
        T o = targetClass.newInstance();
        return o;
    }
    
    public static  T checkedInstanceOf(final String className,
            final Class<? extends T> type) throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException,
            InstantiationException, IllegalAccessException {
        
        final Class<?> clazz = Class.forName(className);
        Class<? extends T> targetClass = clazz.asSubclass(type);
        
        T o = targetClass.newInstance();
        return o;
    }       
}

Let’s call our last method added.

CheckedClassInsantiationExample:

package com.javarticles.reflection;


public class CheckedClassInsantiationExample {
    public static void main(String[] args) throws Exception {
        IAppContext appContext = ClassUtil.checkedInstanceOfUsingTypeCast(
                "com.javarticles.reflection.AppContext", IAppContext.class);
        System.out.println(appContext);
        try {
            IAppContext notAContext = ClassUtil.checkedInstanceOfUsingTypeCast(
                    "com.javarticles.reflection.ClassUtil", IAppContext.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // isAssignableFrom
        try {
            IAppContext notAContext = ClassUtil
                    .checkedInstanceOfUsingTypeCast1(
                            "com.javarticles.reflection.ClassUtil",
                            IAppContext.class);
        } catch (Exception e) {
             e.printStackTrace();
        }
        IAppContext finalContext = ClassUtil.checkedInstanceOf(
                "com.javarticles.reflection.AppContext", IAppContext.class);
        System.out.println("Final context: " + finalContext);
    }
}

Output:

[email protected]
java.lang.ClassCastException: com.javarticles.reflection.ClassUtil cannot be cast to com.javarticles.reflection.IAppContext
Final context: [email protected]
	at com.javarticles.reflection.CheckedClassInsantiationExample.main(CheckedClassInsantiationExample.java:10)
java.lang.ClassCastException
	at com.javarticles.reflection.ClassUtil.checkedInstanceOfUsingTypeCast1(ClassUtil.java:22)
	at com.javarticles.reflection.CheckedClassInsantiationExample.main(CheckedClassInsantiationExample.java:19)

Download the source code

This was an example about checked instantiation of class using reflection.

You can download the source code here: javaCheckedInstanceOfClassExample.zip
Share.

Comments are closed.