Any way to Invoke a private method? - java

I have a class that uses XML and reflection to return Objects to another class.
Normally these objects are sub fields of an external object, but occasionally it's something I want to generate on the fly. I've tried something like this but to no avail. I believe that's because Java won't allow you to access private methods for reflection.
Element node = outerNode.item(0);
String methodName = node.getAttribute("method");
String objectName = node.getAttribute("object");
if ("SomeObject".equals(objectName))
object = someObject;
else
object = this;
method = object.getClass().getMethod(methodName, (Class[]) null);
If the method provided is private, it fails with a NoSuchMethodException. I could solve it by making the method public, or making another class to derive it from.
Long story short, I was just wondering if there was a way to access a private method via reflection.

You can invoke private method with reflection. Modifying the last bit of the posted code:
Method method = object.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
Object r = method.invoke(object);
There are a couple of caveats. First, getDeclaredMethod will only find method declared in the current Class, not inherited from supertypes. So, traverse up the concrete class hierarchy if necessary. Second, a SecurityManager can prevent use of the setAccessible method. So, it may need to run as a PrivilegedAction (using AccessController or Subject).

Use getDeclaredMethod() to get a private Method object and then use method.setAccessible() to allow to actually call it.

If the method accepts non-primitive data type then the following method can be used to invoke a private method of any class:
public static Object genericInvokeMethod(Object obj, String methodName,
Object... params) {
int paramCount = params.length;
Method method;
Object requiredObj = null;
Class<?>[] classArray = new Class<?>[paramCount];
for (int i = 0; i < paramCount; i++) {
classArray[i] = params[i].getClass();
}
try {
method = obj.getClass().getDeclaredMethod(methodName, classArray);
method.setAccessible(true);
requiredObj = method.invoke(obj, params);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return requiredObj;
}
The Parameter accepted are obj, methodName and the parameters. For example
public class Test {
private String concatString(String a, String b) {
return (a+b);
}
}
Method concatString can be invoked as
Test t = new Test();
String str = (String) genericInvokeMethod(t, "concatString", "Hello", "Mr.x");

you can do this using ReflectionTestUtils of Spring (org.springframework.test.util.ReflectionTestUtils)
ReflectionTestUtils.invokeMethod(instantiatedObject,"methodName",argument);
Example : if you have a class with a private method square(int x)
Calculator calculator = new Calculator();
ReflectionTestUtils.invokeMethod(calculator,"square",10);

Let me provide complete code for execution protected methods via reflection. It supports any types of params including generics, autoboxed params and null values
#SuppressWarnings("unchecked")
public static <T> T executeSuperMethod(Object instance, String methodName, Object... params) throws Exception {
return executeMethod(instance.getClass().getSuperclass(), instance, methodName, params);
}
public static <T> T executeMethod(Object instance, String methodName, Object... params) throws Exception {
return executeMethod(instance.getClass(), instance, methodName, params);
}
#SuppressWarnings("unchecked")
public static <T> T executeMethod(Class clazz, Object instance, String methodName, Object... params) throws Exception {
Method[] allMethods = clazz.getDeclaredMethods();
if (allMethods != null && allMethods.length > 0) {
Class[] paramClasses = Arrays.stream(params).map(p -> p != null ? p.getClass() : null).toArray(Class[]::new);
for (Method method : allMethods) {
String currentMethodName = method.getName();
if (!currentMethodName.equals(methodName)) {
continue;
}
Type[] pTypes = method.getParameterTypes();
if (pTypes.length == paramClasses.length) {
boolean goodMethod = true;
int i = 0;
for (Type pType : pTypes) {
if (!ClassUtils.isAssignable(paramClasses[i++], (Class<?>) pType)) {
goodMethod = false;
break;
}
}
if (goodMethod) {
method.setAccessible(true);
return (T) method.invoke(instance, params);
}
}
}
throw new MethodNotFoundException("There are no methods found with name " + methodName + " and params " +
Arrays.toString(paramClasses));
}
throw new MethodNotFoundException("There are no methods found with name " + methodName);
}
Method uses apache ClassUtils for checking compatibility of autoboxed params

One more variant is using very powerfull JOOR library https://github.com/jOOQ/jOOR
MyObject myObject = new MyObject()
on(myObject).get("privateField");
It allows to modify any fields like final static constants and call yne protected methods without specifying concrete class in the inheritance hierarhy
<!-- https://mvnrepository.com/artifact/org.jooq/joor-java-8 -->
<dependency>
<groupId>org.jooq</groupId>
<artifactId>joor-java-8</artifactId>
<version>0.9.7</version>
</dependency>

Related

How to create Instance from genericReturnType

Here I need to create an object of java.util.List<com.entity.User>, where
I have java.util.List<com.entity.User> is available as string only.
demo class
class Demo {
public List<User> allUser() {
// some stuff
}
}
In another class
Method method = null;
try {
Class cls= Class.forName("Demo"); // fully qualified Name here for sure
Method[] methods = cls.getMethods();
for (Method _method:methods) {
if(_method.getName().equals("allUser")) {
method = _method;
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(method != null) {
java.lang.reflect.Type genericReturnType = method.getGenericReturnType();
}
Here I need to create an object of java.util.List<com.entity.User>, I only have
genericReturnType = java.util.List<com.entity.User>
I tried
Class clazz = Class.forName(genericReturnType.getTypeName());
This returns java.lang.ClassNotFoundException
I want to create instance of java.util.List<com.entity.User>
the thing is that the method allUser can be anything and return type of method can be anything
stuff till Method genericReturnType seems fine. I need to create an object with the help of genericReturnType.
NOTE: consider that there is no any syntex error in code.
let me simplify this.
// I want to achive this
String clsName = "java.util.List<com.entity.User>"; // consider fully qualified name
Class cls = Class.forName(clsName); // from here I got error java.lang.ClassNotFoundException
Object clsInstance = (Object) cls.newInstance();
I want to do some process with com.entity.User if there is list of User is there, (there might any kind of list there instead of User) so I need to identify generic type of List as well.
Thanks in advance.
You can extract the generic type this after casting the Type into a ParameterizedType:
ReflectionTest.java
public class ReflectionTest {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Method method = null;
try {
Class cls = Class.forName("Demo"); // fully qualified Name here for sure
Method[] methods = cls.getMethods();
for (Method _method : methods) {
if (_method.getName().equals("allUser")) {
method = _method;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (method != null) {
System.out.println(method.getReturnType());
ParameterizedType parameterizedType = (ParameterizedType) method.getGenericReturnType();
if (parameterizedType.getActualTypeArguments().length > 0 && parameterizedType.getActualTypeArguments()[0] instanceof Class<?>) {
Class type = (Class) parameterizedType.getActualTypeArguments()[0];
User user = (User) type.newInstance();
System.out.println(user.getClass());
}
}
}
}
class Demo {
public List<User> allUser() {
return Collections.emptyList();
}
}
User.java
public class User {
}

Getting sub class fields using super class using reflection?

I have a class as below.
public class Emp{
private String name;
private String age;
//setters and getters
}
Have one more class below.
public class Student extends Emp{
private int marks;
//setters and getters
}
is there anyway to get the fields of a subclass using super class using java Reflection?
I need to get Student fields using Emp instance.
we can get super class fields as below:
subClass.getClass().getSuperclass().getDeclaredFields();
similarly can i get sub class fields using super class?
Is it possible?
Thanks!
I may have misunderstood your question. Do you want to do something like the following?
Emp e = new Student(...);
[do something with e]
foo = e.marks;
If yes, do it like this:
foo = ((Emp)e).marks;
However, if you want to do something like the following:
Emp e = new Emp(...);
[do something with e]
e.marks = ....
Then no, it's not possible, and I'd suspect your internal model of java's object model is either incomplete or flawed.
In theory there is a very complicated and costly way by retrieving all loaded classes and checking which of them are derived from Emp and contain the field. If the desired class wasn't loaded yet this may not help either.
Not directly, you have to write a helper method to that.
You take a class and the field name (and possibly type) as parameters, then look for that field in the given class. If you cant find it, you take the class's superclass and repeat from the beginning. You do this until you either found the field, or getSuperClass() returned null (meaning you reached the root of the inheritance tree).
This example demonstrates how to call find and call a specified method on an object. You can easily extract and adapt the logic for fields.
public static Object call(final Object instance,
final String methodName,
final Class<?>[] signature,
final Object[] args) {
try {
if (instance == null)
return null;
Class<?> instanceClass = instance.getClass();
while (instanceClass != null) {
try {
final Method method = instanceClass.getDeclaredMethod(methodName, signature);
if (!method.isAccessible())
method.setAccessible(true);
return method.invoke(instance, args);
} catch (final NoSuchMethodException e) {
// ignore
}
instanceClass = instanceClass.getSuperclass();
}
} catch (final Throwable e) {
return null;
}
return null;
}
Is it what you want? But beware of using field.setAccesible.
Parent class:
public class ParentClass {
private String parentField = "parentFieldValue";
public void printFields() throws IllegalAccessException {
Field[] fields = getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Object fieldValue = field.get(this);
if (fieldValue instanceof String) {
String stringValue = (String) fieldValue;
System.out.println(stringValue);
}
}
}
}
Child class:
public class ChildClass extends ParentClass {
private String childField = "childFieldValue";
}
Usage:
public class Main {
public static void main(String[] args) throws IllegalAccessException {
ParentClass pc = new ParentClass();
ChildClass cc = new ChildClass();
pc.printFields();
cc.printFields();
}
}
This is the final solution!
#NonNull
public static List<Class<?>> getSubClasses() {
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
String method = trace[3].getMethodName();
if (!"<init>".equals(method)) {
throw new IllegalStateException("You can only call this method from constructor!");
}
List<Class<?>> subClasses = new ArrayList<>();
for (int i = 4; i < trace.length; i++) {
method = trace[i].getMethodName();
if ("<init>".equals(method)) {
try {
subClasses.add(Class.forName(trace[i].getClassName()));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
} else {
break;
}
}
return subClasses;
}
this are some examples of usage:
class a {
public a(){
print(getSubClasses());
}
}
class b extends a{
}
class c extends b{
}
And the result is
new a() -> []
new b() -> [b.class]
new c() -> [b.class, c.class]

how to pass multiple parameters to a method in java reflections

Hi i am using reflections to achieve something.
I have been given class name, method name of that class and parameter values that needs to be passed to that method in a file(Take any file. Not a constraint).
I have to call that method with the parameters. This methods do not return anything.
There is a huge list of methods in this classes and parameter list of each varies.
E.g: method1(String, String, int, boolean)
method1(String, int, boolean) and likewise i have different permutations and combinations.
So how can i achieve this.
I have tried hard coding things with different switch clauses but it is a real overhead and risky thing to maintain.
Can we dynamically do this thing, like on the fly read the method name and its parameter from the file and call it.
Any small code snippet will be helpful.
TIA.
Hi all i have found the solution to the above question. below is the sample code snippet.
package reflections;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionTest {
public void method1(String str, int number) {
System.out.println(str + number);
}
public void method1(String str) {
System.out.println(str);
}
public void method1() {
System.out.println("helloworld");
}
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException,
NoSuchMethodException, SecurityException, IllegalArgumentException,
InvocationTargetException {
// Step 1) Make an object array and store the parameters that you wish
// to pass it.
Object[] obj = {};// for method1()
// Object[] obj={"hello"}; for method1(String str)
// Object[] obj={"hello",1}; for method1(String str,int number)
// Step 2) Create a class array which will hold the signature of the
// method being called.
Class<?> params[] = new Class[obj.length];
for (int i = 0; i < obj.length; i++) {
if (obj[i] instanceof Integer) {
params[i] = Integer.TYPE;
} else if (obj[i] instanceof String) {
params[i] = String.class;
}
// you can do additional checks for other data types if you want.
}
String methoName = "method1"; // methodname to be invoked
String className = "reflections.ReflectionTest";// Class name
Class<?> cls = Class.forName(className);
Object _instance = cls.newInstance();
Method myMethod = cls.getDeclaredMethod(methoName, params);
myMethod.invoke(_instance, obj);
}
}
I hope this will help others too.
public class ReflectionSample
{
private Object mString = null;
private int mValue;
public ReflectionSample()
{
}
public ReflectionSample(int oValue)
{
mValue = oValue;
}
public ReflectionSample(String oString)
{
mString = oString;
}
public ReflectionSample(String oString, int oValue)
{
setValues(oString, oValue);
}
public void setValues(String oString, int oValue)
{
mString = oString;
mValue = oValue;
}
public String toString()
{
return ""+mString+":"+mValue;
}
public void run()
{
String oInput = "Teststring";
Class<?> cls;
String clsname = "main.ReflectionSample";
Object rs = null; // ReflectionSample
Object rsc = null;
System.out.println(this.getClass().getName());
try
{
System.out.println(clsname);
cls = Class.forName(clsname);
if(cls == null)
{
System.err.println(clsname + " doesn't exist");
return;
}
// Look for a constructor which has a single string
Constructor<?> ct = null;
Class<?>[] param_types = new Class<?>[1];
Object[] arguments = new Object[1];
param_types[0] = String.class;
// get the string constructor
ct = cls.getConstructor(param_types);
// We only have one object
arguments = new Object[1];
arguments[0] = oInput;
// Instantiate the object with passed in argument.
rs = ct.newInstance(arguments);
System.out.println("String constructor sample: "+rs);
// Instantiate with default constructor
param_types = new Class<?>[0];
arguments = new Object[0];
ct = cls.getConstructor(param_types);
rs = ct.newInstance(arguments);
rsc = rs; // Keep it for later, to lazy to call it again
System.out.println("Default constructor sample: "+rs);
// Instantiate with string and int constructor
param_types = new Class<?>[2];
arguments = new Object[2];
// Must be in the same order as the params I think
param_types[0] = String.class;
param_types[1] = Integer.TYPE; // <-- Its a primitive so use TYPE not Class
arguments[0] = oInput;
arguments[1] = new Integer(1);
ct = cls.getConstructor(param_types);
rs = ct.newInstance(arguments);
System.out.println("String plus int constructor sample: "+rs);
// call the setValues method
param_types[0] = String.class;
param_types[1] = Integer.TYPE; // <-- Its a primitive so use TYPE not Class
arguments[0] = oInput;
arguments[1] = 1;
System.out.println("setValues invocation before: "+rsc);
Method m = cls.getMethod("setValues", param_types);
m.invoke(rsc, arguments);
System.out.println("setValues invocation after: "+rsc);
// An alternative method to pass the parameters
m = cls.getMethod("setValues", String.class, Integer.TYPE);
m.invoke(rsc, oInput+"x", 2);
System.out.println("setValues invocation after: "+rsc);
}
catch(Throwable e)
{
System.err.println(e.getLocalizedMessage());
}
}
}
Output:
main.ReflectionSample
main.ReflectionSample
String constructor sample: Teststring:0
Default constructor sample: null:0
String plus int constructor sample: Teststring:1
setValues invocation before: null:0
setValues invocation after: Teststring:1
Hope this helps.
I don't know if this is a newer feature in Java, but I have seen that you can use invoke now with parameters as well, instead of using an array, which might make your code better to read (This is the alternative way). If you need a variable number of arguments and you don't know beforehand how many there will be, allocating the array is defeinitly working and should also be backwardcompatible.
A simple solution would be to create a Class with the Arguments required to be passed:
public class ObjectArguments {
private PrintWriter out;
private String productId;
private int action;
public ObjectArguments(PrintWriter out, String productId, int action) {
this.out = out;
this.productId = productId;
this.action = action;
}
public PrintWriter getOut() {
return out;
}
public String getProductId() {
return productId;
}
public int getAction() {
return action;
}
}
Assuming that you want to invoke a class Foo with a method named bar.
Then it would be done like this.
PrintWriter out = null;
String productId = null;
int action = 0;
Class[] paramArguments = new Class[1];
paramArguments[0] = ObjectArguments.class;
ObjectArguments newObj = new ObjectArguments(out,productId,action);
Class cls = Class.forName("Foo");
Object obj = cls.newInstance();
Method method = cls.getDeclaredMethod("bar", paramArguments);
method.invoke(obj, newObj);
For two int parameters the example is as below, similarly other datatype parameters can also be called
Method method=new Test1().getClass().getMethod(x, new Class[] {int.class,int.class});
We can call a method that needs 3 arguments int,int,string as below :
Method method=new Test1().getClass().getMethod(x, new Class[] {int.class,int.class, String.class});

Invoking all setters within a class using reflection

I have a domain object, that for the purposes of this question I will call Person with the following private variables:
String name
int age
Each of these have getters and setters. Now I also have a Map<String, String> with the following entries:
name, phil
age, 35
I would like to populate a list of all setter methods within the class Person and then looping through this list and invoking each method using the values from the map.
Is this even possible as I cannot see any examples close to this on the net. Examples are very much appreciated.
Sure it's possible! You can get all methods that start with "set" back by doing this:
Class curClass = myclass.class;
Method[] allMethods = curClass.getMethods();
List<Method> setters = new ArrayList<Method>();
for(Method method : allMethods) {
if(method.getName().startsWith("set")) {
setters.add(method);
}
}
Now you've got the methods. Do you already know how to call them for your instance of the class?
Have you tried BeanUtils.populate()) from Apache Commons BeanUtils?
BeanUtils.populate(yourObject, propertiesMap);
This is a full solution that verifies output class beforehand and consequently calls setters for all the properties that the map contains. It uses purely java.beans and java.lang.reflect.
public Object mapToObject(Map<String, Object> input, Class<?> outputType) {
Object outputObject = null;
List<PropertyDescriptor> outputPropertyDescriptors = null;
// Test if class is instantiable with default constructor
if(isInstantiable(outputType)
&& hasDefaultConstructor(outputType)
&& (outputPropertyDescriptors = getPropertyDescriptors(outputType)) != null) {
try {
outputObject = outputType.getConstructor().newInstance();
for(PropertyDescriptor pd : outputPropertyDescriptors) {
Object value = input.get(pd.getName());
if(value != null) {
pd.getWriteMethod().invoke(outputObject, value);
}
}
} catch (InstantiationException|IllegalAccessException|InvocationTargetException|NoSuchMethodException e) {
throw new IllegalStateException("Failed to instantiate verified class " + outputType, e);
}
} else {
throw new IllegalArgumentException("Specified outputType class " + outputType + "cannot be instantiated with default constructor!");
}
return outputObject;
}
private List<PropertyDescriptor> getPropertyDescriptors(Class<?> outputType) {
List<PropertyDescriptor> propertyDescriptors = null;
try {
propertyDescriptors = Arrays.asList(Introspector.getBeanInfo(outputType, Object.class).getPropertyDescriptors());
} catch (IntrospectionException e) {
}
return propertyDescriptors;
}
private boolean isInstantiable(Class<?> clazz) {
return ! clazz.isInterface() && ! Modifier.isAbstract(clazz.getModifiers());
}
private boolean hasDefaultConstructor(Class<?> clazz) {
try {
clazz.getConstructor();
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
I think you could use a library, the Apache Commons BeanUtils. If you have a map that contains field and value pairs, the class PropertyUtils can help you:
Person person = new Person();
for(Map.Entry<String, Object> entry : map.entrySet())
PropertyUtils.setProperty(person, entry.getKey(), entry.getValue());

Suggestions on extending fit.RowFixture and fit.TypeAdapter so that I can bind/invoke on a class that keeps attrs in a map

TLDR: I'd like to know how to extend fit.TypeAdaptor so that I can invoke a method that expects parameters as default implementation of TypeAdaptor invokes the binded (bound ?) method by reflection and assumes it's a no-param method...
Longer version -
I'm using fit to build a test harness for my system (a service that returns a sorted list of custom objects). In order to verify the system, I thought I'd use fit.RowFixture to assert attributes of the list items.
Since RowFixture expects the data to be either a public attribute or a public method, I thought of using a wrapper over my custom object (say InstanceWrapper) - I also tried to implement the suggestion given in this previous thread about formatting data in RowFixture.
The trouble is that my custom object has around 41 attributes and I'd like to provide testers with the option of choosing which attributes they want to verify in this RowFixture. Plus, unless I dynamically add fields/methods to my InstanceWrapper class, how will RowFixture invoke either of my getters since both expect the attribute name to be passed as a param (code copied below) ?
I extended RowFixture to bind on my method but I'm not sure how to extend TypeAdaptor so that it invokes with the attr name..
Any suggestions ?
public class InstanceWrapper {
private Instance instance;
private Map<String, Object> attrs;
public int index;
public InstanceWrapper() {
super();
}
public InstanceWrapper(Instance instance) {
this.instance = instance;
init(); // initialise map
}
private void init() {
attrs = new HashMap<String, Object>();
String attrName;
for (AttrDef attrDef : instance.getModelDef().getAttrDefs()) {
attrName = attrDef.getAttrName();
attrs.put(attrName, instance.getChildScalar(attrName));
}
}
public String getAttribute(String attr) {
return attrs.get(attr).toString();
}
public String description(String attribute) {
return instance.getChildScalar(attribute).toString();
}
}
public class MyDisplayRules extends fit.RowFixture {
#Override
public Object[] query() {
List<Instance> list = PHEFixture.hierarchyList;
return convertInstances(list);
}
private Object[] convertInstances(List<Instance> instances) {
Object[] objects = new Object[instances.size()];
InstanceWrapper wrapper;
int index = 0;
for (Instance instance : instances) {
wrapper = new InstanceWrapper(instance);
wrapper.index = index;
objects[index++] = wrapper;
}
return objects;
}
#Override
public Class getTargetClass() {
return InstanceWrapper.class;
}
#Override
public Object parse(String s, Class type) throws Exception {
return super.parse(s, type);
}
#Override
protected void bind(Parse heads) {
columnBindings = new TypeAdapter[heads.size()];
for (int i = 0; heads != null; i++, heads = heads.more) {
String name = heads.text();
String suffix = "()";
try {
if (name.equals("")) {
columnBindings[i] = null;
} else if (name.endsWith(suffix)) {
columnBindings[i] = bindMethod("description", name.substring(0, name.length()
- suffix.length()));
} else {
columnBindings[i] = bindField(name);
}
} catch (Exception e) {
exception(heads, e);
}
}
}
protected TypeAdapter bindMethod(String name, String attribute) throws Exception {
Class partypes[] = new Class[1];
partypes[0] = String.class;
return PHETypeAdaptor.on(this, getTargetClass().getMethod("getAttribute", partypes), attribute);
}
}
For what it's worth, here's how I eventually worked around the problem:
I created a custom TypeAdapter (extending TypeAdapter) with the additional public attribute (String) attrName. Also:
#Override
public Object invoke() throws IllegalAccessException, InvocationTargetException {
if ("getAttribute".equals(method.getName())) {
Object params[] = { attrName };
return method.invoke(target, params);
} else {
return super.invoke();
}
}
Then I extended fit.RowFixture and made the following overrides:
public getTargetClass() - to return my class reference
protected TypeAdapter bindField(String name) throws Exception - this is a protected method in ColumnFixture which I modified so that it would use my class's getter method:
#Override
protected TypeAdapter bindField(String name) throws Exception {
String fieldName = camel(name);
// for all attributes, use method getAttribute(String)
Class methodParams[] = new Class[1];
methodParams[0] = String.class;
TypeAdapter a = TypeAdapter.on(this, getTargetClass().getMethod("getAttribute", methodParams));
PHETypeAdapter pheAdapter = new PHETypeAdapter(fieldName);
pheAdapter.target = a.target;
pheAdapter.fixture = a.fixture;
pheAdapter.field = a.field;
pheAdapter.method = a.method;
pheAdapter.type = a.type;
return pheAdapter;
}
I know this is not a neat solution, but it was the best I could come up with. Maybe I'll get some better solutions here :-)

Categories

Resources