mardi 19 mai 2020

How to reuse logic for class instantiation and get around IllegalAccessException?

Goal: create a util class that will contain some reflection code, in particular code that creates a new class instance. That code is not very simple, so I want to keep it in a util function so that I can reuse it multiple times.

Approach/Idea: create ClassUtil that will have a function that returns a lambda that creates a new class instance. I will execute that lambda in MyClassFactory, a class that I know can create a new instance of MyClassOne because it will be in the same package and the default constructor is package-private access modifier, so ClassUtil cannot make an instance of that class, but since I am executing the lambda in a class that can all should be good.

Error: java.lang.IllegalAccessException: class com.util.ClassUtil cannot access a member of class com.somepackage.MyClassOne with modifiers ""

Question: How to make Java runtime think that it is MyClassFactory the one that is trying the instantiation?

UML: enter image description here
Code:

package com.somepackage

import com.util.ClassUtil;

public class MyClassFactory {

    public MyClass createMyClass() {
        String implClassFQN = <get impl class FQN from somewhere>;
        return (MyClass ) ClassUtil.createClassInstance().apply(implClassFQN);
    }
}

package com.util;

import java.lang.reflect.InvocationTargetException;
import java.util.function.Function;

public class ClassUtil {

    /**
     * @return a new instance of the class given the class fully qualified name
     */
    public static Function<String, Object> createClassInstance() {
        return (classFQN) -> {
            try {
                return Class.forName(classFQN).getDeclaredConstructor().newInstance();
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("Impl class specified in properties file not found", e);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException("Default constructor not found", e);
            } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        };
    }

}

Workaround/New Approach: would anyone know how I could have taken a different approach to achieve the same goal?

Note: If I put the code from ClassUtil into MyClassFactory it works fine, but I want it reusable.





Aucun commentaire:

Enregistrer un commentaire