Get a private field via reflection, in Java - java

I have a Java class named "MyClass" with a private attribute, of type "AnotherClass". MyClass has a private constructor, and "AnotherClass" has public constructor. "AnotherClass" has also a private String field, "value", which is initialized in constructor. I want to access in "Main" class this String.
The first class:
public class MyClass {
private AnotherClass obj;
private MyClass() {
obj = new AnotherClass();
}
}
The second class:
public class AnotherClass {
private String value;
public AnotherClass() {
value = "You got the private value!";
}
}
The main class:
public class Main {
static String name;
static AnotherClass obj;
public static void main(String[] args) throws Exception {
Class myClass;
myClass = Class.forName("main.MyClass");
Constructor<MyClass>[] constructors = myClass
.getDeclaredConstructors();
for (Constructor c : constructors) {
if (c.getParameters().length == 0) {
c.setAccessible(true);
MyClass myCls= (MyClass) c.newInstance();
Field myObjField = myClass
.getDeclaredField("obj");
myObjField.setAccessible(true);
obj = (AnotherClass) myObjField.get(myCls);
// If "value" is public, the program prints "You got the private value!"
// So "obj" is returned correctly, via reflection
// name = obj.value;
// System.out.println(name);
// Now I want to get the field "value" of "obj"
Field myStringField = obj.getClass().getDeclaredField("value");
myStringField.setAccessible(true);
// This line throws an exception
name = (String) myStringField.get(obj.getClass());
System.out.println(name);
}
}
}
}
I expect to see in the console "You got the private value!", but the program throws an exception:
Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.lang.String field main.AnotherClass.value to java.lang.Class
So, I want to retrieve the private field, "value", without modifying "MyClass" and "AnotherClass", and without calling the public constructor from AnotherClass directly in main() . I want to get the value from "obj".

Change this line
name = (String) myStringField.get(obj.getClass());
to this
name = (String) myStringField.get(obj);
The get method requires an object to access the field of (unless it's a static field)

Related

Setting annotated field value using reflection in generic class. (IllegalArgumentException)

I have been facing an issue that implies Reflection, Annotations and Generics in Java. I have a class that creates a new instance of a generic type called B. Then it will search for any Field with the MyCustomAnnotation annotation and sets its value to a determined one.
The class that does this is:
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class MyInstanceCreator<B> {
private final String myValue = "Hello world!";
public B createInstance(Class<B> classType) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
B obj = classType.getConstructor().newInstance();
for(Field f: classType.getDeclaredFields()) {
if(f.isAnnotationPresent(MyCustomAnnotation.class)) {
System.out.println("Is annotated!");
updateField(obj, f);
}
}
return obj;
}
private void updateField(B instance, Field field) throws IllegalAccessException {
field.setAccessible(true);
field.set(myValue, instance);
field.setAccessible(false);
}
}
The annotation class:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomAnnotation {}
The custom type has an annotated Field of type String:
public class MyCustomType {
#MyCustomAnnotation
private String value;
public String getValue() {
return value;
}
}
Finally my main class is:
public class MyClass {
public static void main(String args[]) {
try {
MyInstanceCreator<MyCustomType> iCreator = new MyInstanceCreator<>();
MyCustomType myObj = iCreator.createInstance(MyCustomType.class);
System.out.println(myObj.getValue());
} catch(Exception e) {
e.printStackTrace();
}
}
}
The output of the program is:
Is annotated!
java.lang.IllegalArgumentException: Can not set java.lang.String field MyCustomType.value to java.lang.String
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.base/java.lang.reflect.Field.set(Field.java:780)
at MyInstanceCreator.updateField(MyInstanceCreator.java:21)
at MyInstanceCreator.createInstance(MyInstanceCreator.java:13)
at MyClass.main(MyClass.java:5)
It does not make any sense to me why reflection cannot assign a java.lang.String value to a java.lang.String field as the IllegalArgumentException message says. I must be missing something but I can't seem to figure it out.
Any help is appreciated!
Here's your problem…
...
field.set(myValue, instance);
...
Here's your fix…
...
field.set(instance, myValue);
...
Here are the docs…
public void set​(Object obj, Object value)…
...
Parameters:
obj - the object whose field should be modified
value - the new value for the field of obj being modified
…

Read static field of interface via reflection

I've got an interface:
public interface Interface {
public static final String FIELD1 = "BAR";
public static final String FIELD2 = "FOO";
.........
}
I'm trying to read the field name via reflection using this code:
Field[] fields = Interface.class.getFields();
for (Field f : fields) {
............
}
The problem is that the array has always length zero. Why?
Edit: I'm using proguard and I think the problem is related with interface obfuscation.
I am running the same code as you have provided and able to print the name of the fields from the interface.
import java.lang.reflect.Field;
public class Prop {
public static void main(String[] args)
{
Field[] fields = Interface.class.getFields();
for (Field f : fields) {
System.out.println(f.getName());
}
}
}
interface Interface {
public static final String FIELD1 = "BAR";
public static final String FIELD2 = "FOO";
}
Ouput:
FIELD1
FIELD2
Simply use:
Field[] fields = Interface.class.getDeclaredFields();
Instead of :
Field[] fields = Interface.class.getFields();
It worked fine for me!

'X.class' to get it's 'X' type?

I have written simple container that registers a class and it's interface and has a method to create object from that information like this:
public class DIContainer {
protected static DIContainer instance;
protected Hashtable<Class<?>, Class<?>> classMap;
protected DIContainer(){
this.classMap = new Hashtable<Class<?>, Class<?>>();
}
public static DIContainer getInstance(){
if (DIContainer.instance == null)
DIContainer.instance = new DIContainer();
return DIContainer.instance;
}
public void regClass(Class<?> interf, Class<?> classToReg){
this.classMap.put(interf, classToReg);
}
public Object create(Class<?> interf) throws Exception{
if(!this.classMap.containsKey(interf))
throw new Exception("No such class registered with "+interf.getName()+" interface");
return this.classMap.get(interf).newInstance();
}
}
But I want before creating new instance to bypass it to proxy, for it to create, so I have this proxy class:
public class MyProxy implements InvocationHandler
{
private Map map;
private Object obj;
public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
return Proxy.newProxyInstance(map.getClass().getClassLoader(),
interfaces,
new MyProxy(map, obj));
}
public MyProxy(Map map, Object obj)
{
this.map = map;
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws
Throwable
{
try {
return m.invoke(obj, args);
} catch (NoSuchMethodError e)
{
//Object result;
String methodName = m.getName();
if (methodName.startsWith("get"))
{
String name = methodName.substring(methodName.indexOf("get")+3);
return map.get(name);
}
else if (methodName.startsWith("set"))
{
String name = methodName.substring(methodName.indexOf("set")+3);
map.put(name, args[0]);
return null;
}
else if (methodName.startsWith("is"))
{
String name = methodName.substring(methodName.indexOf("is")+2);
return(map.get(name));
}
return null;
}
}
}
But for proxy class I need to provide type of class and it's interface, but I only have it's information with X.class. Can get the type (for example if it's class X) X, when I have X.class? Maybe I'm doing this the wrong way and I need to change something in order for it to work, but right now I figured I need to get that class type, so then I could provide it for proxy?
Because if I would right something like this:
X.class x;
I would get error. So I need to write like this X x;, but I only have X.class
Update:
To explain it simply, is it possible to get this:
X obj;
when you only have X.class (with X.class.newInstance it would instantiate it (like with new?), but I need not instantiated obj yet).
Update2
I tried this:
Object x = (Object) MyProxy.newInstance(map, this.classMap.get(interf).newInstance(), new Class[] {this.classMap.get(interf)});
But then I get this error:
Exception in thread "main" java.lang.IllegalArgumentException: class lab.X is not visible from class loader
My class X looks like this:
public class X implements I{
String name;
X(){}
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
}
and it's interface looks like this:
public interface I {
public String getName();
public void setName(String name);
}
If I understand correctly, you are trying to instantiate an element of the class X.class? If that is the case, all you need to do is call X.class.newInstance().
java.lang.IllegalArgumentException: class lab.X is not visible from
class loader
Isn't this error message quite clear? You need to make sure that the same class loader is being used.
In here:
public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
return Proxy.newProxyInstance(map.getClass().getClassLoader(),
interfaces,
new MyProxy(map, obj));
}
you shouldn't be using the class loader of the map, I'd think you should use class loader of the target object or pass the proper class loader as a separate argument.
I think there are other problems in your approach as well, such as not synchronizing your container creation and not using generics for your proxy type.
For the first part, class DIContainer, it would be better to use:
protected final Map<Class<?>, Class<?>> classMap;
protected DIContainer() {
classMap = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
}
public <I> void regClass(Class<I> interf, Class<? extends I> classToReg) {
this.classMap.put(interf, classToReg);
}
public <T> T create(Class<T> interf) throws Exception {
Class<?> implClass = classMap.get(interf);
if (implClass == null) {
throw new Exception("No such class registered with " + interf.getName()
+ " interface");
}
Constructor<?> c = implClass.getConstructor();
c.setAccessible(true); // If default constructor not public
return interf.cast(c.newInstance());
}
Safe typing, though still partly at run-time.
More or less obsolete Hashtable replaced by equivalent
Calling newInstance on the class bypasses exceptions thrown on getting the default constructor and doing that one's newInstance.
The second part of the question: I fail to understand it; the interface class(es) is what is proxied. In the create above you could easily proxy Class<T> and yield a (seemingly) T object. And you could delegate in the proxy class to an T object created as in the create above.

How to use string to compare with field names in java?

I have a class named MyClass. It has many fields of type MyField. How do I return a reference to a particular field whose name matches a String's value?
public class MyClass{
public MyField field1;
public MyField field2;
public MyField field3;
public MyField whichField(String nameOfField){
//e.g. String = "field3", then return field3
//of course I can do if else, but it will be tedious If I have long list of MyField fields, can I iterate over all field names, and return whose name matches?
}
}
edit
I tried reflection from the answers below, I create a temp placeholder, and I wish to reutrn it but,
MyField temp = MyClass.class.getDeclaredField(whichFieldString);
doesnt work, I get type mismatch, cant convert error
How do I cast this?
How do I return this field?
As an alternative:
If all fields are of the same type and are accessed by their field name (most of the time) you could avoid the hassle and brittleness of using reflection by utilizing a Map.
The map associates a key (in your case the "field name") with a value. Instead of an arbitrary number of fields, MyClass would look like:
public class MyClass {
private final Map<String, MyField> fields = new HashMap<>();
/* code to initially fill the map */
public MyField whichField(String fieldName) {
return fields.get(fieldName);
}
}
You can do this with reflection. Class A has the fields we want to search through:
public class A {
private String field1;
private String field2;
private String field3;
}
And B shows how to iterate over the fields declared in A, matching on a particular field name:
public class B {
public B() {
Field field = findFieldByName("field1");
System.out.println(field);
}
private Field findFieldByName(String name) {
Field[] fields = A.class.getDeclaredFields();
for(Field f : fields) {
if(f.getName().equals(name)) {
return f;
}
}
return null;
}
public static void main(String[] args) {
new B();
}
}
You'll have to use reflection:
import java.lang.reflect.Field;
public class MyClass {
public MyField field1;
public MyField field2;
public MyField field3;
public MyField whichField(String nameOfField) {
MyField fieldName = null;
Field[] fields = MyClass.class.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals(nameOfField)) {
// Do whatever you want to do
}
}
return null;
}
}
class MyField {
}
You may want to use a collection, e.g. Map<String, MyField>.
You can do it easily with reflection
Class<MyClass> clazz = MyClass.class;
Field requieredField = clazz.getDeclaredField("myFielldName");
EDIT
This solution is pertinent is the number of fields is fixed. As it was mentioned in comments and answers, if you want to store a dynamic number of values, then a Map (or a Collection if you only need to enumerate the values) is much more suitable.

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]

Categories

Resources