NoSuchFieldException when using getDeclaredField() and field exists - java

java.lang.NoSuchFieldException: c
at java.lang.Class.getDeclaredField(Unknown Source)
at ru.onlymc.OnlyMZ.CustomEntityType.getPrivateStatic(CustomEntityType.java:177)
Method:
private static Object getPrivateStatic(Class clazz, String f) throws Exception {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
return field.get(null);
}
Calling:
private static void a(Class paramClass, String paramString, int paramInt) {
try {
((Map) getPrivateStatic(sg.class, "c")).put(paramString, paramClass);
//...
} catch (Exception exc) {
exc.printStackTrace();
}
}
sg.class (from decompile to sure about required fields really exists):
private static Map c = new HashMap();
private static Map d = new HashMap();
private static Map e = new HashMap();
private static Map f = new HashMap();
private static Map g = new HashMap();
public static HashMap a = new LinkedHashMap();

Sorry, I can't reproduce this one.
Here's the full source code that I ran:
import java.lang.reflect.*;
import java.util.*;
#SuppressWarnings("unchecked")
public class ReflectionTest {
private static Object getPrivateStatic(Class clazz, String f) throws Exception {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
return field.get(null);
}
private static void a(Class paramClass, String paramString, int paramInt) {
try {
((Map) getPrivateStatic(sg.class, "c")).put(paramString, paramClass);
//...
} catch (Exception exc) {
exc.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
a(String.class, "test", 0);
sg.printC();
}
}
class sg {
private static Map c = new HashMap();
private static Map d = new HashMap();
private static Map e = new HashMap();
private static Map f = new HashMap();
private static Map g = new HashMap();
public static HashMap a = new LinkedHashMap();
public static void printC() {
System.out.println(c);
}
}
This was the output I got when I ran it:
{test=class java.lang.String}
Given that you haven't specified the full decompiled source of the sg class, I can only guess at a couple of things that may have happened:
There is more than one class named sg, your code is using one of them but your decompiled output comes from a different one.
The fields exist within an inner class inside sg.
EDIT: the class sg you linked to below appears to contain a static field c, and contains no inner class, so I would expect to be able to use reflection to access this field. I cannot use your sg class with the ReflectionTest class I wrote above because it depends on numerous other classes with obfuscated names such as xk.
I can only conclude that you have some confusion about exactly which class you are attempting to access the field c from. I suggest altering your getPrivateStatic method to the following, which may provide a more helpful error message, including the name of the class and all of the fields within it:
private static Object getPrivateStatic(Class clazz, String f) throws Exception {
try {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
return field.get(null);
}
catch (NoSuchFieldException e) {
// Throw a more helpful exception.
throw new NoSuchFieldException(
"Could not find field named '" + f + "' in class '" + clazz +
"'. All fields: " + Arrays.asList(clazz.getDeclaredFields()));
}
}

You are trying to get the field of the object null. See documentation on Field.get(Object)
You need to provide an object to get its field content. Or you need to provide a class to get a static fields content.
So you should write the following:
private static Object getPrivateStatic(Class clazz, String f) throws Exception {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
return field.get(clazz);
}
btw. It is not considered good programming style to use reflection in production code since it e.g. makes refactoring problematic.
If you still need to use reflection (or are not working on production-code), use a framework for this kind of stuff (accessing private static field). With e.g. PrivilegedAccessor this method would be a 1-liner:
PA.getValue(clazz, f);

Related

Copy object properties by direct field access

Is there an easy way to copy an object's property's onto another object of a different class which has the same field names using direct field access - i.e. when one of the classes does not have getters or setters for the fields? I can use org.springframework.beans.BeanUtils#copyProperties(Object source, Object target) when they both have getter and setter methods, but what can I do when they don't?
It may also be relevant that the fields are public.
I know that I can write my own code to do this using reflection, but I'm hoping that there's some library that provides a one-liner.
I didn't find a 3rd-party library to do this quite how I wanted. I'll paste my code here in case it is useful to anyone:
import java.lang.reflect.Field;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An alternative to Spring's BeanUtils#copyProperties for classes that don't have getters and setters.
*/
public class FieldCopier {
private static final Logger log = LoggerFactory.getLogger(FieldCopier.class);
/** Always use the same instance, so that we can cache the fields. */
private static final FieldCopier instance = new FieldCopier();
/** Caching the paired fields cuts the time taken by about 25% */
private final Map<Map.Entry<Class<?>, Class<?>>, Map<Field, Field>> PAIRED_FIELDS = new ConcurrentHashMap<>();
/** Caching the fields cuts the time taken by about 50% */
private final Map<Class<?>, Field[]> FIELDS = new ConcurrentHashMap<>();
public static FieldCopier instance() {
return instance;
}
private FieldCopier() {
// do not instantiate
}
public <S, T> T copyFields(S source, T target) {
Map<Field, Field> pairedFields = getPairedFields(source, target);
for (Field sourceField : pairedFields.keySet()) {
Field targetField = pairedFields.get(sourceField);
try {
Object value = getValue(source, sourceField);
setValue(target, targetField, value);
} catch(Throwable t) {
throw new RuntimeException("Failed to copy field value", t);
}
}
return target;
}
private <S, T> Map<Field, Field> getPairedFields(S source, T target) {
Class<?> sourceClass = source.getClass();
Class<?> targetClass = target.getClass();
Map.Entry<Class<?>, Class<?>> sourceToTarget = new AbstractMap.SimpleImmutableEntry<>(sourceClass, targetClass);
PAIRED_FIELDS.computeIfAbsent(sourceToTarget, st -> mapSourceFieldsToTargetFields(sourceClass, targetClass));
Map<Field, Field> pairedFields = PAIRED_FIELDS.get(sourceToTarget);
return pairedFields;
}
private Map<Field, Field> mapSourceFieldsToTargetFields(Class<?> sourceClass, Class<?> targetClass) {
Map<Field, Field> sourceFieldsToTargetFields = new HashMap<>();
Field[] sourceFields = getDeclaredFields(sourceClass);
Field[] targetFields = getDeclaredFields(targetClass);
for (Field sourceField : sourceFields) {
if (sourceField.getName().equals("serialVersionUID")) {
continue;
}
Field targetField = findCorrespondingField(targetFields, sourceField);
if (targetField == null) {
log.warn("No target field found for " + sourceField.getName());
continue;
}
if (Modifier.isFinal(targetField.getModifiers())) {
log.warn("The target field " + targetField.getName() + " is final, and so cannot be written to");
continue;
}
sourceFieldsToTargetFields.put(sourceField, targetField);
}
return Collections.unmodifiableMap(sourceFieldsToTargetFields);
}
private Field[] getDeclaredFields(Class<?> clazz) {
FIELDS.computeIfAbsent(clazz, Class::getDeclaredFields);
return FIELDS.get(clazz);
}
private <S> Object getValue(S source, Field sourceField) throws IllegalArgumentException, IllegalAccessException {
sourceField.setAccessible(true);
return sourceField.get(source);
}
private <T> void setValue(T target, Field targetField, Object value) throws IllegalArgumentException, IllegalAccessException {
targetField.setAccessible(true);
targetField.set(target, value);
}
private Field findCorrespondingField(Field[] targetFields, Field sourceField) {
for (Field targetField : targetFields) {
if (sourceField.getName().equals(targetField.getName())) {
if (sourceField.getType().equals(targetField.getType())) {
return targetField;
} else {
log.warn("Different types for field " + sourceField.getName()
+ " source " + sourceField.getType() + " and target " + targetField.getType());
return null;
}
}
}
return null;
}
}
Write a simple utility class for that and you got your one liner... this task is IMHO to easy to use a library for it.
Just keep in mind to make your fields accessible if they aren't by default. Here are two functions you could adapt from our codebase:
public void injectIntoObject(Object o, Object value) {
try {
getField().set(o, value);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Illegal argument while injecting property '"+name+"' of class '"+beanDef.getName()+"' in object '"+o+"' to '"+value+"'. Got one of type "+value.getClass().getCanonicalName()+" but needed one of "+type.getCanonicalName()+"!",e);
} catch (IllegalAccessException e) {
getField().setAccessible(true);
try {
getField().set(o, value);
} catch (IllegalArgumentException e1) {
throw new RuntimeException("Illegal argument while injecting property '"+name+"' of class '"+beanDef.getName()+"' in object '"+o+"' to '"+value+"'. Got one of type "+value.getClass().getCanonicalName()+" but needed one of "+type.getCanonicalName()+"!",e);
} catch (IllegalAccessException e1) {
throw new RuntimeException("Access exception while injecting property '"+name+"' of class '"+beanDef.getName()+"' in object '"+o+"' to '"+value+"'!",e);
}
} catch (Exception e) {
throw new RuntimeException("Exception while setting property '"+name+"' of class '"+beanDef.getName()+"' in object '"+o+"' to '"+value+"'!",e);
}
}
public Object extractFromObject(Object o) {
try {
return getField().get(o);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Illegal argument while read property '"+name+"' of class '"+beanDef.getName()+"' in object '"+o+"' but needed one of "+type.getCanonicalName()+"!",e);
} catch (IllegalAccessException e) {
getField().setAccessible(true);
try {
return getField().get(o);
} catch (IllegalArgumentException e1) {
throw new RuntimeException("Illegal argument while read property '"+name+"' of class '"+beanDef.getName()+"' in object '"+o+"' but needed one of "+type.getCanonicalName()+"!",e);
} catch (IllegalAccessException e1) {
throw new RuntimeException("Access exception while read property '"+name+"' of class '"+beanDef.getName()+"' in object '"+o+"'!",e);
}
} catch (Exception e) {
throw new RuntimeException("Exception while read property '"+name+"' of class '"+beanDef.getName()+"' in object '"+o+"'!",e);
}
}
getField() returns a java.lang.Field, should be easy to implement.
I would strongly suggest that you avoid using reflection for this, as it leads to code that is difficult to understand and maintain. (Reflection is ok for testing and when creating frameworks, other than this it probably creates more problems than it solves.)
Also, if a property of an object needs to be accessed by something other than the object, it needs a scope that is not private (or an accessor/getter that is not private). That is the whole point of variable scopes. Keeping a variable private without accessors, and then using it anyways through reflection is just wrong, and will just lead to problems, as you are creating code that lies to the reader.
public class MyClass {
private Integer someInt;
private String someString;
private List<Double> someList;
//...
}
public class MyOtherClass {
private Integer someInt;
private String someString;
private List<Double> someList;
private boolean somethingElse;
public copyPropertiesFromMyClass(final MyClass myClass) {
this.someInt = myClass.getSomeInt();
this.someString = myClass.getSomeString();
this.someList = new ArrayList<>(myClass.getSomeList());
}
}

Acquiring reference to private final field in abstract class

I have a reference to object A, which is abstract. This object is also an instance of objects B, C, or D at any time.
Regardless of the extending class, I need a reference to a private final field of a certain type within A.
I do not know the name of the field, only its type, which is unique to all other fields in the abstract class. I cannot change the code of any of the four listed classes. Using getDeclaredFields() returns the fields within whatever extending class I have at the time.
How can I get a reference to this field?
You need to call getDeclaredFields() on class A itself and then use reflection to set the field accessible thusly
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test{
public static void main(String args[]){
B someB = new B();
B otherB = new B();
Field uniqueField = null;
for(Field f : A.class.getDeclaredFields()){
if(!Modifier.isFinal(f.getModifiers()))
continue;
if(!UNIQUE.class.isAssignableFrom(f.getType()))
continue;
uniqueField = f;
break;
}
if(null == uniqueField)
throw new NullPointerException();
uniqueField.setAccessible(true);
try{
System.out.println(uniqueField.get(someB) != uniqueField.get(otherB));
}catch(IllegalArgumentException | IllegalAccessException e){
throw new RuntimeException(e);
}
}
}
class UNIQUE{
}
class A{
private final UNIQUE u;
private final String someOtherMember = "";
A(){
u = new UNIQUE();
}
}
class B extends A{
}
if you don't have a direct reference to class A or if there is more than one superclass that has this unique field then you can loop over each one (making sure to check at each stop that you didn't climb all the way to object) by doing something more like this in the example above
Class<?> clazz = someB.getClass();
classClimb: do{
for(Field f : clazz.getDeclaredFields()){
if(!Modifier.isFinal(f.getModifiers()))
continue;
if(!UNIQUE.class.isAssignableFrom(f.getType()))
continue;
uniqueField = f;
break classClimb;
}
}while(Object.class != (clazz = clazz.getSuperclass()));
if(null == uniqueField)
throw new NullPointerException();
uniqueField.setAccessible(true);
try{
System.out.println(uniqueField.get(someB) != uniqueField.get(otherB));
}catch(IllegalArgumentException | IllegalAccessException e){
throw new RuntimeException(e);
}
Remember that in that case you'll have to either do the reflection on every single object, do some caching, or have multiple reflection sites that are specific to each expected superclass.
If you don't have direct to class it self then you can do something as follows -
Field[] fields = obj.getClass().getSuperclass().getDeclaredFields();
for(Field field : fields) {
if(field.getType() == String.class) { //assume the type is String
}
}
But if you have access to the class then it would be
Field[] fields = B.class.getSuperclass().getDeclaredFields();
Or even
Field[] fields = A.class.getDeclaredFields();
import java.lang.reflect.Field;
abstract class A {
private final String secret = "got it";
}
class B extends A {
private final String secret = "try again";
}
public class Test {
public static void main(String[] args) throws IllegalAccessException {
Class neededType = String.class;
A a = new B();
Class c = a.getClass();
Class sc = c.getSuperclass();
Field flds[] = sc.getDeclaredFields();
for (Field f : flds) {
if (neededType.equals(f.getType())) {
f.setAccessible(true);
System.out.println(f.get(a));
}
}
}
}

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]

Java—how can I dynamically reference an object's property?

In javascript, I can do this:
function MyObject(obj) {
for (var property in obj) {
this[property] = obj[property];
}
}
Can I do anything close in Java?
class MyObject {
String myProperty;
public MyObject(HashMap<String, String> props) {
// for each key in props where the key is also the name of
// a property in MyObject, can I assign the value to this.[key]?
}
}
Not that I disagree with Joel's answer, but I do not think it is not quite that difficult, if you essentially just want a best effort. Essentially check if it is there, and if it is try to set. If it works great if not, oh well we tried. For example:
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class MyObject {
protected String lorem;
protected String ipsum;
protected int integer;
public MyObject(Map<String, Object> valueMap){
for (String key : valueMap.keySet()){
setField(key, valueMap.get(key));
}
}
private void setField(String fieldName, Object value) {
Field field;
try {
field = getClass().getDeclaredField(fieldName);
field.set(this, value);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Map<String, Object> valueMap = new HashMap<String, Object>();
valueMap.put("lorem", "lorem Value");
valueMap.put("ipsum", "ipsum Value");
valueMap.put("integer", 100);
valueMap.put("notThere", "Nope");
MyObject f = new MyObject(valueMap);
System.out.println("lorem => '"+f.lorem+"'");
System.out.println("ipsum => '"+f.ipsum+"'");
System.out.println("integer => '"+f.integer+"'");
}
}
Yes, you can do it by reflection with something along the following lines:
/**
* Returns a list of all Fields in this object, including inherited fields.
*/
private List<Field> getFields() {
List<Field> list = new ArrayList<Field>();
getFields(list, getClass());
return list;
}
/**
* Adds the fields of the provided class to the List of Fields.
* Recursively adds Fields also from super classes.
*/
private List<Field> getFields(List<Field> list, Class<?> startClass) {
for (Field field : startClass.getDeclaredFields()) {
list.add(field);
}
Class<?> superClass = startClass.getSuperclass();
if(!superClass.equals(Object.class)) {
getFields(list, superClass);
}
}
public void setParameters(Map<String, String> props) throws IllegalArgumentException, IllegalAccessException {
for(Field field : getFields()) {
if (props.containsKey(field.getName())) {
boolean prevAccessible = field.isAccessible();
if (!prevAccessible) {
/*
* You're not allowed to modify this field.
* So first, you modify it to make it modifiable.
*/
field.setAccessible(true);
}
field.set(this, props.get(field.getName()));
/* Restore the mess you made */
field.setAccessible(prevAccessible);
}
}
}
However, if you are not very familiar with Java, this approach should be avoided if at all possible, as it is somewhat dangerous and error prone. For instance, there is no guarantee that the Field you are attempting to set are actually expecting a String. If it is the case that they are not, your program will crash and burn.
First, I would use a map if at all possible:
class MyObject {
// String myProperty; // ! not this
HashMap<String,String> myProperties; // use this instead
}
but let's say you wanted to set the fields dynamically.
public MyObject(HashMap<String, String> props) {
for (Map.Entry<String,String> entry : props.entrySet()) {
Field field = this.getClass().getField(entry.getKey());
field.set(this, entry.getValue());
}
}
of course, you will want to use a try/catch in the above constructor.
Well, if you really want to go down the reflection raod, then I suggest to have a look at the Introspector class and get the list of PropertyDescriptors from the BeanInfo.

Accessing Methods and functions of a object whose class type is dynamically known

I have an object A1 of type A. I dynamically find that out , that object A1 is of type A. I now have a property say "Name" which I want to access from A1 , how do I do it ?
Now the biggest problem is that the object A1 can even be of type B. If it is of type B then I will have to obtain the value "Address". Now How I resolve this ?
Below code does the type check ,
public static void testing(Object A1, String s) s - Classtype
{
try{
Class c = Class.forName(s);
if( c.isInstance(A1)) //
{
//Now I know that A1 is of the type C. But I dont know what type 'c' is (whether type A or type B. Because Only then I can access the appropriate member.) Like I said, type A contain 'name' and type B contains address.
// The access may not only be a member but also a method .
}
}catch (Exception e){ System.out.println(e);}
}
Any pointers would help a lot . thanks
You can know the declared fields of class
Class cls = Class.forName("MyClass");
Field fieldlist[] = cls.getDeclaredFields();
Documentation
This kind of thing is tricky and error-prone if you do it manually. You should use one of the many BeanUtils / BeanHelper classes that almost every major framework contains. Here is my own quick example implementation which you can use if you want to:
public final class BeanHelper{
/**
* Return a map of an object's properties (key: property name, value:
* property type).
*
* #exception NullPointerException
* if bean is null
*/
public static Map<String, Class<?>> describeProperties(final Object bean){
if(bean == null){
throw new NullPointerException();
}
final Map<String, Class<?>> map;
final Class<?> beanClass = bean.getClass();
if(PROPERTIES_CACHE.containsKey(beanClass)){
map = PROPERTIES_CACHE.get(beanClass);
} else{
final PropertyDescriptor[] propertyDescriptors =
getBeanInfo(beanClass);
if(propertyDescriptors.length == 0){
map = Collections.emptyMap();
} else{
final Map<String, Class<?>> innerMap =
new TreeMap<String, Class<?>>();
for(final PropertyDescriptor pd : propertyDescriptors){
innerMap.put(pd.getName(), pd.getPropertyType());
}
map = Collections.unmodifiableMap(innerMap);
}
PROPERTIES_CACHE.put(beanClass, map);
}
return map;
}
private static PropertyDescriptor[] getBeanInfo(final Class<?> beanClass){
try{
return Introspector.getBeanInfo(beanClass, Object.class)
.getPropertyDescriptors();
} catch(final IntrospectionException e){
throw new IllegalStateException(
MessageFormat.format(
"Couldn''t access bean properties for class {0}",
beanClass),
e);
}
}
/**
* Retrieve a named property from a specified object.
*
* #return the property
* #exception NullPointerException
* if one of the arguments is null
* #exception IllegalArgumentException
* if there is no such property
*/
public static Object getBeanProperty(final Object bean,
final String property){
if(bean == null || property == null){
throw new NullPointerException();
}
final Class<?> beanClass = bean.getClass();
Map<String, PropertyDescriptor> propMap;
if(PROPERTY_DESCRIPTOR_CACHE.containsKey(beanClass)){
propMap = PROPERTY_DESCRIPTOR_CACHE.get(beanClass);
} else{
final PropertyDescriptor[] beanInfo = getBeanInfo(beanClass);
if(beanInfo.length == 0){
propMap = Collections.emptyMap();
} else{
propMap =
new HashMap<String, PropertyDescriptor>(beanInfo.length);
for(final PropertyDescriptor pd : beanInfo){
propMap.put(pd.getName(), pd);
}
}
PROPERTY_DESCRIPTOR_CACHE.put(beanClass, propMap);
}
if(!propMap.containsKey(property)){
throw new IllegalArgumentException(
MessageFormat.format(
"Class {0} does not have a property ''{1}''",
beanClass,
property));
}
return invokeMethod(propMap.get(property).getReadMethod(), bean);
}
private static Object invokeMethod(final Method method,
final Object bean,
final Object... args){
try{
return method.invoke(bean, args);
} catch(final IllegalArgumentException e){
throw e;
} catch(final IllegalAccessException e){
throw new IllegalStateException(
MessageFormat.format(
"Method not accessible: {0}",
method),
e);
} catch(final InvocationTargetException e){
throw new IllegalStateException(
MessageFormat.format(
"Error in method: {0}",
method),
e);
}
}
private static final Map<Class<?>, Map<String, Class<?>>>
PROPERTIES_CACHE =
new ConcurrentHashMap<Class<?>, Map<String, Class<?>>>();
private static final Map<Class<?>, Map<String, PropertyDescriptor>>
PROPERTY_DESCRIPTOR_CACHE =
new ConcurrentHashMap<Class<?>, Map<String, PropertyDescriptor>>();
private BeanHelper(){
}
}
Test Code:
public static void main(final String[] args){
class Dummy{
private String foo = "bar";
private String baz = "phleem";
public String getFoo(){
return foo;
}
public void setFoo(final String foo){
this.foo = foo;
}
public String getBaz(){
return baz;
}
public void setBaz(final String baz){
this.baz = baz;
}
}
final Object dummy = new Dummy();
final Map<String, Class<?>> beanProperties =
BeanHelper.describeProperties(dummy);
System.out.println(beanProperties);
for(final String key : beanProperties.keySet()){
System.out.println(MessageFormat.format("{0}:{1}",
key,
BeanHelper.getBeanProperty(dummy, key)));
}
}
Output:
{baz=class java.lang.String, foo=class java.lang.String}
baz:phleem
foo:bar
Look at this: BeanUtils
myUser.setName("Bob");
// can instead be written:
BeanUtils.setProperty(myUser, "name", "Bob");
// and then retrieve:
BeanUtils.getProperty(myUser, "name");
The fields are typically private. So, to access them you have to call
field.setAccessible(true);
BTW, are you sure you really wish to use reflection in this case? Did you probably think about declaring interface? The class (implementation) can be still loaded dynamically.
For example: NameAccessor and AddressAccessor are interfaces.
FirstClass and SecondClass are classes. Let's assume that FirstClass implements NameAccessor and SecondClass implements both interfaces.
Now you can say:
Class clazz = Class.forName("SecondClass");
Object obj = clazz.newInstance();
//......
String name = ((NameAccessor)obj).getName();
String address = ((AddressAccessor)obj).getAddress();
I think (IMHO) that this solution is better than accessing private fields using reflection.

Categories

Resources