Reflective Getter and Setter Method
In this post, I will show you Java code for getting getter and setter method from given object.
The code is below:
public final static Method getSetterMethod(Object o, String propertyName, Class<?> paramterType) throws SecurityException, NoSuchMethodException{ return o.getClass().getMethod("set"+toUpperFirstChar(propertyName), paramterType); } public final static Method getGetterMethod(Object o, String propertyName) throws SecurityException, NoSuchMethodException{ return o.getClass().getMethod("get"+toUpperFirstChar(propertyName)); } public final static String toUpperFirstChar(String str){ if(str.isEmpty()) return ""; return str.substring(0, 1).toUpperCase()+str.substring(1, str.length()); }
Where to Use Reflective Getter and Setter?
You may have a question - "Where should we use reflective getter and setter method?"
If you already know where to use them, you can skip the following article ;)
Ok, let's continue. In my experience, the most useful case is calling setter function when solving root by newton method etc.
Assume you have the following kind of existence newton method solver class.
package com.dukesoftware.utils.solve; import com.dukesoftware.utils.math.function.Function; public class NewtonMethod { private final int maxTrial; private final double d; private final double reduceFactor; public NewtonMethod(int maxTrial, double d, double reduceFactor){ this.maxTrial = maxTrial; this.d = d; this.reduceFactor = reduceFactor; } public double solve(Function func, double x1, double x2, double tol) { final double lowerLimit = -tol; final double upperLimit = tol; double d = this.d; double x = x1, f; for(int i = 0; i < maxTrial; i++){ f = func.f(x); x = x - f * d / (func.f(x+d)-f); if(f > lowerLimit && f < upperLimit){ return x; } d *= reduceFactor; } throw new RuntimeException("Not Solved: x=" + x); } } public interface Function { double f(double x); }
Of course it is easy to apply this NewtonMethod solver class to function whose argument suits with the Function interface.
public void testNewtonMethod() throws Exception { final int num = -3; final double allowDiff = 0.0001; RootSolver solver = new NewtonMethod(1000, allowDiff, 0.5); double expect = Math.sqrt(-num); double actual = solver.solve((x) -> x * x + num, 0, 4, 0.001); assertEquals(expect, actual, allowDiff); }
But what should we do for applying the NewtonMethod solver class to function whose argument does not suit with the Function interface?
private static class TestSrcFunc implements ToDoubleFunction{ @Override public double applyAsDouble(Input t) { return t.getA()*t.getA()*t.getB()-t.getC()*t.getB()*t.getB(); } } public static class Input{ private double a; private double b; private double c; public double getA() { return a; } public void setA(double a) { this.a = a; } public double getB() { return b; } public void setB(double b) { this.b = b; } public double getC() { return c; } public void setC(double c) { this.c = c; } }
In this case, you can use reflective getter.
The code is a bit longer but you can specify which property in Input class to use for solving by only giving String property name.
public void testNewtonMethodByDataObj_UsingReflection() throws Exception { final double allowDiff = 0.0001; RootSolver solver = new NewtonMethod(1000, allowDiff, 0.5); Input input = new Input(); input.setB(4); input.setC(1); TestSrcFunc srcFunc = new TestSrcFunc(); Method setter = ReflectionUtils.getSetterMethod(input, "a", double.class); // reflection assertEquals(2d, solver.solve(x -> { try { setter.invoke(input, x); } catch (Exception e) { throw new RuntimeException(e); } return srcFunc.applyAsDouble(input); }, 1, 18, 0.001), allowDiff); }
Of course you don't have to use reflective setter for the above case.
The advantage of reflection is when your program needs to read the target property dynamically from config file or something.
If you don't use reflection, you should create anonymous inner class which wraps the target setter method, and pass them based on property name.
If you use reflection, you simply take the property name String from the config file and directly pass it to the ReflectionUtils.getSetterMethod method.
コメント