Make a reflection utility ①

Introduction

Sometimes I do a single unit with JUnit, but it is troublesome to create a process to execute a private method each time, so make a note here. It's not limited to testing, but it's probably used only for test code.

Method to execute private method

Params.java


package com.example.demo.util;

import java.lang.reflect.Method;

public class ReflectionUtil {

	/**
	 *Execute a private method (no arguments).
	 * @Instance that executes the param obj method
	 * @param methodName method name
	 * @param params argument
	 * @return value of the return method
	 * @throws Exception
	 */
	public static Object invokePrivate(Object obj, String methodName) throws Exception {
		Class<?> clazz = obj.getClass();
		Method method = clazz.getDeclaredMethod(methodName);
		method.setAccessible(true);
		return method.invoke(obj);
	}

	/**
	 *Execute a private method (with arguments).
	 * @Instance that executes the param obj method
	 * @param methodName method name
	 * @param params argument
	 * @return value of the return method
	 * @throws Exception
	 */
	public static Object invokePrivate(Object obj, String methodName, Params params) throws Exception {
		if(params == null ){
			throw new NullPointerException("params is required");
		}
		Class<?> clazz = obj.getClass();
		Method method = clazz.getDeclaredMethod(methodName, params.getTypes());
		method.setAccessible(true);
		return method.invoke(obj, params.getArgs());
	}
}

By the way, getDeclaredMethod gets a method object from a java.lang.Class object, so you don't need to instantiate it for a static method. So you can pass the class directly to the first argument of invokePrivate and execute getDeclaredMethod.

Class that summarizes arguments

A class for grouping the arguments required to execute a private method with the above arguments.

Params.java


package com.example.demo.util;

import java.util.ArrayList;
import java.util.List;

import lombok.Data;

public class Params {

	private List<Param> paramList;

	public Params() {
		paramList = new ArrayList<>();
	}

	/**
	 *Constructor that specifies arguments at the same time as initialization.
	 * @param type
	 * @param arg
	 */
	public <T> Params(Class<T> type, T arg) {
		this();
		add(type, arg);
	}

	/**
	 *Set arguments and their types.
	 * @param type
	 * @param arg
	 */
	public <T> void add(Class<T> type, T arg) {
		paramList.add(new Param(type, arg));
	}

	/**
	 *Returns the set argument type as an array.
	 * @return
	 */
	public Class<?>[] getTypes() {
		Class<?>[] types = new Class[paramList.size()];
		for (int i = 0; i < paramList.size(); i++) {
			types[i] = paramList.get(i).getType();
		}
		return types;
	}

	/**
	 *Returns the set argument as an array.
	 * @return
	 */
	public Object[] getArgs() {
		Object[] args = new Object[paramList.size()];
		for (int i = 0; i < paramList.size(); i++) {
			args[i] = paramList.get(i).getArg();
		}
		return args;
	}

	/**
	 *A class that represents one argument.<br />
	 *It has an argument object and its type as attributes.
	 *
	 */
	@Data
	private class Param {
		private Class<?> type;
		private Object arg;

		<T> Param(Class<T> type, T arg) {
			this.type = type;
			this.arg = arg;
		}
	}
}

Try to run

--Private method to be tested

Private method to be tested

Prepare a private method with arguments as appropriate.

Test.java


	private String doSomthing(int i, Long l, String str){
		System.out.println(Integer.toString(i));
		System.out.println(l.toString());
		System.out.println(str);
		return "Done!";
	}

test case

UtilTest.java


	@Test
	public void test1() {
		AService test = new AService();	
		//Try to specify the first argument in the constructor
		Params params = new Params(int.class, 1);
		//Then add with add
		params.add(Long.class, 20L);
		params.add(String.class, "Third argument");
		try {
			//Run
			String ret = (String) ReflectionUtil.invokePrivate(test, "doSomthing", params);
			System.out.println(ret);
		} catch (Exception e) {
			e.printStackTrace();
			fail();
		}
	}

When actually using it, it is easier to see invokePrivate if it is statically imported.

Execution result

Execution result


1
20
Third argument
Done!

By the way,

UtilTest.java


	/**
	 *If null is specified instead of params.
	 */
	@Test
	public void testParamsNull() {
		AServices = new AService();
		try {
			ReflectionUtil.invokePrivate(s, TARGET_METHOD, null);
			fail();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 *When the arguments set in params do not match.
	 */
	@Test
	public void testParamsInvalid() {
		AService s = new AService();
		Params params = new Params(int.class, 1);
		params.add(Long.class, 20L);
		try {
			ReflectionUtil.invokePrivate(s, TARGET_METHOD, params);
			fail();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

Execution result testParamsNull()


java.lang.NullPointerException: params is required
	at com.example.demo.util.ReflectionUtil.invokePrivate(ReflectionUtil.java:32)
	at com.example.demo.UtilTest.test1(UtilTest.java:33)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	:

Execution result testParamsInvalid()


java.lang.NoSuchMethodException: com.example.demo.service.AService.doSomthing(int, java.lang.Long)
	at java.lang.Class.getDeclaredMethod(Class.java:2122)
	at com.example.demo.util.ReflectionUtil.invokePrivate(ReflectionUtil.java:35)
	at com.example.demo.UtilTest.test1(UtilTest.java:33)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	:

that's all.

Recommended Posts

Make a reflection utility ②
Make a reflection utility ③
Make a reflection utility ①
[Java] Make it a constant
Make a rhombus using Java
Make a digging maze with Ruby2D
Make a language! (Making a simple calculator ②)
Try to make a simple callback
Make a slideshow tool with JavaFX
How to make a Java container
Make a Christmas tree with swift
How to make a JDBC driver
Priority Queue max Make it a queue
Make a language! (JavaCC environment construction)
Make a garbage reminder with line-bot-sdk-java
Make a list map with LazyMap
A murmur about the utility class
How to make a splash screen
How to make a Jenkins plugin
How to make a Maven project
Make a SOAP call in C #
Try to make a peepable iterator
How to make a Java array
Make a typing game with ruby
How to make a Java calendar Summary
Make a note of Ruby keyword arguments
Let's make a Christmas card with Processing!
Make a family todo list with Sinatra
How to make a Discord bot (Java)
Make a family todo list with Sinatra
Let's make a smart home with Ruby!
Make a login function with Rails anyway
[docker] [nginx] Make a simple ALB with nginx
Make a site template easily with Rails
[Java] Let's make a DB access library!