In depth analysis of java reflection (VI) – Reflection call exception handling

premise

The java reflection API is in javase 1 7, but Oracle jdk11 was used when writing this article, because jdk11 also uploaded the source code under the sun package. You can directly view the corresponding source code and debug through the IDE.

This article mainly introduces a problem that must be encountered when using reflection - Reflection call exception handling.

Reflection call exception handling

The following conditions are mainly considered when an exception occurs in the reflection call:

Handling property operation exception

Let's first look at the method of setting properties:

public void set(Object obj,Object value) throws IllegalArgumentException,illegalaccessexception

In fact, you can learn from the method annotation that four exceptions will be thrown:

The first three exceptions are well understood. The last exceptionininitializererror may be a little strange. Its throwing condition is that exceptions are always thrown during the initialization and parsing of static code blocks or during the initialization of static variables. The author has tried many examples and failed to create a case. An example is found from stackoverflow:

public class Example {
    public static void main(String[] args) throws Exception {
        Field field = Fail.class.getDeclaredField("number");
        field.set(null,42); // Fail class isn't initialized at this point
    }
}

class Fail {
    static int number;
    static {
        boolean val = true;
        if (val)
            throw new RuntimeException(); // causes initialization to end with an exception
    }
}

To put it simply, the initialization order of static code blocks and static variables is consistent with the order they are written in the class file. If a class is not initialized and directly uses its static code blocks and static variables through the field #set (object obj, object value) call, an exceptionininitializererror exception will appear.

The exception thrown by the property acquisition method is consistent with the set value method, which will not be expanded in detail here:

public Object get(Object obj) throws IllegalArgumentException,illegalaccessexception

Handling constructor call exceptions

Constructor call is mainly used for object instantiation. First, look at the signature of newinstance method:

public T newInstance(Object ... initargs) throws InstantiationException,illegalaccessexception,IllegalArgumentException,InvocationTargetException

Here is just an example to illustrate the scenario of instantiationexception:

public abstract class AbstractSample {

	public AbstractSample() {
	}

	public static void main(String[] args) throws Exception{
		Constructor<AbstractSample> declaredConstructor = AbstractSample.class.getDeclaredConstructor();
		declaredConstructor.newInstance();
	}
}

Like the abstract class abstractsample above, it contains a default public construct. Using constructor #newinstance() will throw an instantialexception exception:

Exception in thread "main" java.lang.InstantiationException
	at java.base/jdk.internal.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at club.throwable.jdk.sample.reflection.reflect.AbstractSample.main(AbstractSample.java:18)

Handling method call exceptions

Method call is the most frequently used reflection operation in reflection, mainly the method#invoke (object obj, object... Args) method:

public Object invoke(Object obj,Object... args) throws illegalaccessexception,InvocationTargetException

It mainly includes the following exceptions:

Focus on invocationtargetexception (inherited from reflectiveoperationexception, and reflectiveoperationexception inherited from exception, that is, it is a checked exception and must be explicitly caught):

public class InvocationTargetException extends ReflectiveOperationException {

    private static final long serialVersionUID = 4085088731926701167L;
    
    // 持有的目标异常实例
    private Throwable target;

    public InvocationTargetException(Throwable target) {
        super((Throwable)null);  // Disallow initCause
        this.target = target;
    }

    public InvocationTargetException(Throwable target) {
        super((Throwable)null);  // Disallow initCause
        this.target = target;
    } 

    public Throwable getTargetException() {
        return target;
    }

    public Throwable getCause() {
        return target;
    }    
}    

It is learned from the comments that the invoking exception of method or constructor will throw this invocationtargetexception to wrap the source exception. The source exception instance is held by the invocationtargetexception member target as the target, The original target exception can be obtained through invocationtargetexception #gettargetexception() or invocationtargetexception #getcause(). Note here that invocationtargetexception uses null when overriding the parent class construction, so calling its GetMessage () method will get null.

for instance:

public class InvocationTargetExceptionMain {

	public void method() {
		throw new NullPointerException("Null");
	}

	public static void main(String[] args) throws NoSuchMethodException,SecurityException {
		InvocationTargetExceptionMain main = new InvocationTargetExceptionMain();
		Method method = InvocationTargetExceptionMain.class.getDeclaredMethod("method");
		try {
			method.invoke(main);
		} catch (illegalaccessexception e) {
			//no-op
		} catch (InvocationTargetException e) {
			System.out.println("InvocationTargetException#message:" + e.getMessage());
			if (e.getTargetException() instanceof NullPointerException) {
				NullPointerException nullPointerException = (NullPointerException) e.getTargetException();
				System.out.println("NullPointerException#message:" + nullPointerException.getMessage());
			}
		}
	}
}

Output after operation:

InvocationTargetException#message:null
NullPointerException#message:Null

The scenario of throwing invocationtargetexception in constructor #newinstance () is similar.

Summary

In reflection operations, the frequency of method calls is the highest, followed by instantiating objects through constructors. We need to focus on the exception handling in these two places, especially the exception type invocationtargetexception. Remember to obtain the original target exception type before making judgment, otherwise it will easily lead to logic errors (recently, the author stepped on this pit when doing a function).

Personal blog

(end of this paper e-a-20181215 c-2-d)

The official account of Technology (Throwable Digest), which is not regularly pushed to the original technical article (never copied or copied):

Entertainment official account ("sand sculpture"), select interesting sand sculptures, videos and videos, push them to relieve life and work stress.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>