Get object reference by field name - java

public class Outer {
public Inner inner = new Inner();
public void test() {
Field[] outerfields = this.getClass().getFields();
for(Field outerf : outerfields) {
Field[] innerFields = outerfields[i].getType().getFields();
for(Field innerf : innerFields) {
innerf.set(X, "TEST");
}
}
}
public class Inner {
String foo;
}
}
What should X be? How can I get the referrence of the innerf field (variable inner)?

How can I get the referrence of the innerf field (variable inner)?
You don't need it. You only need a reference to an object that contains it: in this case, outerfields[i].get(this). See the Javadoc.

OK, I started this before the other answer was accepted, but here's a complete example:
import java.lang.reflect.Field;
public class Outer
{
public static void main(String[] args) throws Exception
{
Outer outer = new Outer();
outer.test();
System.out.println("Result: "+outer.inner.foo);
}
public Inner inner = new Inner();
public void test() throws Exception
{
Field[] outerFields = this.getClass().getFields();
for (Field outerField : outerFields)
{
Class<?> outerFieldType = outerField.getType();
if (!outerFieldType.equals(Inner.class))
{
// Don't know what to do here
continue;
}
Field[] innerFields = outerFieldType.getDeclaredFields();
for (Field innerField : innerFields)
{
Class<?> innerFieldType = innerField.getType();
if (!innerFieldType.equals(String.class))
{
// Don't know what to do here
continue;
}
// This is the "public Inner inner = new Inner()"
// that we're looking for
Object outerFieldValue = outerField.get(this);
innerField.set(outerFieldValue, "TEST");
}
}
}
public class Inner
{
String foo;
}
}

Related

Why can't I access a private method with the Java Reflection API?

I'm trying to access a private method, but it doesn't let me to, and throws the exception. How can I avoid the exception? I've tried a lot of other questions, but they all just point to using setAccessible(true), which I'm already using right now.
import java.lang.reflect.*;
class Reflection {
public static void main (String[] args) {
try {
//Get class instance
ReflectionExamples re = new ReflectionExamples();
Class<?> c = re.getClass();
System.out.println("Class name is " + c.getName());
//Get constructor of class
Constructor<?> cons = c.getConstructor();
System.out.println("Constructor name is " + cons.getName());
System.out.println("List of methods are:");
//Iterate all methods
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
//Desired method to call
Method call = c.getDeclaredMethod("e");
//Unlock the private Method
call.setAccessible(true);
//Invoke the Method
call.invoke(re);
//Desired method to call
Method call2 = c.getDeclaredMethod("a");
//Invoke the method
call2.invoke(c);
} catch(Throwable e) {
System.err.println(e);
}
}
}
class ReflectionExamples {
private String string = "String222222";
public int i = 0;
public ReflectionExamples() {
string = "String";
}
private void e() {
System.out.println("Char entered is not valid.");
}
public void f(char a) {
System.out.println("awojiewfihuerhkuah");
}
public void a() {
System.out.println(string);
}
}
And I get:
java.security.AccessControlException: access denied ("java.lang.reflect.ReflectPermission" "suppressAccessChecks")

Java chained reflection

I have this chained method call
Integer.parseInt(A.get().getC().getD().toString());
I need to make this with reflection. I know that I can use Class.forName(String class) and then invoke methods, but how do I save method results so I can call that chain.
Classes:
public class A
{
public static B get() { return new B(); }
}
public class B
{
public C getC() { return new C();}
}
public class C
{
public C getD() { return new D();}
}
Suppose we have this classes:
public class A {
public B getB() { return new B(); }
public static B getBStatic() { return new B(); }
}
public class B { public C getC() { return new C();}}
public class C { public String getD() { return "done"}}
Example 1:
public static void main(String[] args) throws Exception {
Class<A> clazz = A.class;
Constructor<A> constructor = clazz.getConstructor();
A instance = constructor.newInstance();
Method getMethod = clazz.getDeclaredMethod("getB");
Object b = getMethod.invoke(instance);
Method getCMethod = b.getClass().getDeclaredMethod("getC");
Object c = getCMethod.invoke(b);
Method getDMethod = c.getClass().getDeclaredMethod("getD");
String d = (String) getDMethod.invoke(c);
System.out.println(d); // done
}
Example 2:
public static void main(String[] args) throws Exception {
reflection(new A(), "getB", "getC", "getD"); // invoke non static methods
reflection(new A(), "getBStatic", "getC", "getD"); // invoke static and nonstatic methods
reflection(A.getBStatic(), "getC", "getD"); // provide object from static method
reflection(invokeStaticMethod(A.class, "getBStatic"), "getC", "getD"); // invoke static method without instance
}
public static Object invokeStaticMethod(Class<?> clazz, String methodName) throws Exception {
return clazz.getMethod(methodName).invoke(clazz);
}
public static void reflection(Object instance, String... methods) throws Exception {
Object item = instance;
for (String methodName : methods) {
item = item.getClass().getDeclaredMethod(methodName).invoke(item);
}
System.out.println(item); // done
}

How can i create new instance of class using field type on runtime

I have this class
public static class ExampleClass {
private ExampleObject exampleObject;
public ExampleObject getExampleObject() {
return exampleObject;
}
public void setExampleObject(ExampleObject exampleObject) {
this.exampleObject = exampleObject;
}
}
public class ExampleObject {
private String exampleProp;
public String getExampleProp() {
return exampleProp;
}
public void setExampleProp(String exampleProp) {
this.exampleProp = exampleProp;
}
}
I created a loop to get field types of ExampleClass. How can I create a new instance using field type on runtime? My field type is:
I try this
Class c = Class.forName(fieldType.getName());
var ins = c.newInstance();
But code throws exception like this
java.lang.NoSuchMethodException: com.example.Main$ExampleObject.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3350)
at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2554)
at com.example.CreatorFactory.getCreator(CreatorFactory.java:29)
at com.example.AutoFill.fill(AutoFill.java:15)
at com.example.AutoCreate.<init>(AutoCreate.java:15)
at com.example.AutoCreate.build(AutoCreate.java:23)
at com.example.Main.main(Main.java:7)

Modify property of non-null field using relection/annotations

I have this:
package general;
import org.junit.Test;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
#Retention(RetentionPolicy.RUNTIME)
#interface SetTable {
String table();
}
class Star {
public String foo = "";
public String toString(){
return "<Star> : " + this.foo;
}
}
class Bar {
#SetTable(table = "xxx")
public Star s = new Star();
public String toString(){
return "<Bar> : " + this.s.toString();
}
}
class AnnotationInjector {
public static void inject(Object instance) {
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(SetTable.class)) {
SetTable set = field.getAnnotation(SetTable.class);
field.setAccessible(true); // should work on private fields
try {
field.set(instance, set.table()); // this is not what I need
// ***
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public class AnnotationTest {
#Test
public void first() {
var b = new Bar();
AnnotationInjector.inject(b);
System.out.println(b.toString());
}
}
right now the code is trying to set new Bar().s to a String, but that won't work, because new Bar().s needs to be an instance Star. But that's not what I want to do anyway. What I want to do is access s and set this:
new Bar().s.foo = "whatever"
so on the line above designated by ***
I am looking to do something like:
((Star)field).foo = "whatever";
but that's not right. Is it possible to modify a field after it's been assigned?
Counterintutively, the syntax to do this is:
Star x = (Star)field.get(instance);
this line can modify the properties of the pre-existing Star s field on Bar.
As an alternative I suggest you add an interface with method for setting the value in order to make setting the value more general instead of checking on instances and their types, and make the Star class implements it, as the following:
interface ISetValue {
void setValue(String value);
}
class Star implements ISetValue{
public String foo = "";
#Override
public void setValue(String value) {
foo = value;
}
public String toString(){
return "<Star> : " + this.foo;
}
}
And your AnnotationInjector class should check if the field implements ISetValue and onvoke setValue method for it, should be something like the following:
class AnnotationInjector {
public static void inject(Object instance) {
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(SetTable.class)) {
SetTable set = field.getAnnotation(SetTable.class);
field.setAccessible(true); // should work on private fields
try {
//field.set(instance, set.table()); // this is not what I need
// ***
//Change is here
Class fieldType = field.getType();
if(ISetValue.class.isAssignableFrom(fieldType) ){
Object fieldValue = field.get(instance);
Method myMethod = fieldValue.getClass().getInterfaces()[0].getDeclaredMethod("setValue", new Class[]{String.class});
myMethod.invoke(fieldValue,set.table());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
Now your output should be:
<Bar> : <Star> : xxx

Call private method static.private class

public class Test {
public static void main(String[] args) throws Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int num = Integer.parseInt(br.readLine().trim());
Object o;
Method[] methods = Inner.class.getEnclosingClass().getMethods();
for(int i=0;i<methods.length;i++) {
System.out.println(methods[i].invoke(new Solution(),8));
}
// Call powerof2 method here
} catch (Exception e) {
e.printStackTrace();
}
}
static class Inner {
private class Private {
private String powerof2(int num) {
return ((num & num - 1) == 0) ? "power of 2" : "not a power of 2";
}
}
}
}
Is it possible to call powerof2() method ?
I am getting java.lang.IllegalArgumentException: argument type mismatch for invoke
Yes, things declared in the same top-level class can always access each other:
public class Test {
public static void main(String[] args) throws Exception {
Inner i = new Inner(); // Create an instance of Inner
Inner.Private p = i.new Private(); // Create an instance of Private through
// the instance of Inner, this is needed since
// Private is not a static class.
System.out.println(p.powerof2(2)); // Call the method
}
static class Inner {
private class Private {
private String powerof2(int num) {
return ((num & num - 1) == 0) ? "power of 2" : "not a power of 2";
}
}
}
}
See Ideone
Reflection version:
public class Test {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchMethodException {
Class<?> privateCls = Inner.class.getDeclaredClasses()[0];
Method powerMethod = privateCls.getDeclaredMethod("powerof2", int.class);
powerMethod.setAccessible(true);
Constructor<?> constructor = privateCls.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Object instance = constructor.newInstance(new Inner());
System.out.println(powerMethod.invoke(instance, 2));
}
static class Inner {
private class Private {
private String powerof2(int num) {
return ((num & num - 1) == 0) ? "power of 2" : "not a power of 2";
}
}
}
}

Categories

Resources