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]
Related
I want to get all the fields and it's values from an object of type T. Say I have:
public class Start {
public void startMethod(){
Main<GenericType> main = new Main<>();
main.work(new GenericType());
}
}
Then there's class Main, where I want the fields of GenericType:
public class Main<T> {
public void work(T t){
// Is there a way to get t's fields and values?
}
}
First,you need to get Class of T,then through reflection ,you can get all fields.
abstract class A<T> {
Class<T> clazz;
void doGetClass() {
Type genType = this.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
this.clazz = (Class<T>) params[0];
}
}
but you must instantiate the generic type ,like this,instantiate T to String:
class B extends A<String>{
}
then
B b = new B();
b.doGetClass();// b.clazz is String.class
Following #BalwinderSingh's answer I came to this:
public void work(T t){
for(Field f : t.getClass().getDeclaredFields()){
try {
f.setAccessible(true);
String name = f.getName();
Object value = f.get(object);
}catch(Exception e){
e.printStackTrace();
}
}
}
It was simpler than I though at the beginning. Thank you all.
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.
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));
}
}
}
}
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 :-)
I found a way to get inherited members via class.getDeclaredFields();
and acces to private members via class.getFields()
But i'm looking for private inherited fields.
How can i achieve this?
This should demonstrate how to solve it:
import java.lang.reflect.Field;
class Super {
private int i = 5;
}
public class B extends Super {
public static void main(String[] args) throws Exception {
B b = new B();
Field f = b.getClass().getSuperclass().getDeclaredField("i");
f.setAccessible(true);
System.out.println(f.get(b));
}
}
(Or Class.getDeclaredFields for an array of all fields.)
Output:
5
The best approach here is using the Visitor Pattern do find all fields in the class and all super classes and execute a callback action on them.
Implementation
Spring has a nice Utility class ReflectionUtils that does just that: it defines a method to loop over all fields of all super classes with a callback: ReflectionUtils.doWithFields()
Documentation:
Invoke the given callback on all fields in the target class,
going up the class hierarchy to get all declared fields.
Parameters:
- clazz - the target class to analyze
- fc - the callback to invoke for each field
- ff - the filter that determines the fields to apply the callback to
Sample code:
ReflectionUtils.doWithFields(RoleUnresolvedList.class,
new FieldCallback(){
#Override
public void doWith(final Field field) throws IllegalArgumentException,
IllegalAccessException{
System.out.println("Found field " + field + " in type "
+ field.getDeclaringClass());
}
},
new FieldFilter(){
#Override
public boolean matches(final Field field){
final int modifiers = field.getModifiers();
// no static fields please
return !Modifier.isStatic(modifiers);
}
});
Output:
Found field private transient boolean javax.management.relation.RoleUnresolvedList.typeSafe in type class javax.management.relation.RoleUnresolvedList
Found field private transient boolean javax.management.relation.RoleUnresolvedList.tainted in type class javax.management.relation.RoleUnresolvedList
Found field private transient java.lang.Object[] java.util.ArrayList.elementData in type class java.util.ArrayList
Found field private int java.util.ArrayList.size in type class java.util.ArrayList
Found field protected transient int java.util.AbstractList.modCount in type class java.util.AbstractList
This'll do it:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
Collections.addAll(result, i.getDeclaredFields());
i = i.getSuperclass();
}
return result;
}
If you use a code coverage tool like EclEmma, you have to watch out: they add a hidden field to each of your classes. In the case of EclEmma, these fields are marked synthetic, and you can filter them out like this:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
for (Field field : i.getDeclaredFields()) {
if (!field.isSynthetic()) {
result.add(field);
}
}
i = i.getSuperclass();
}
return result;
}
public static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
try {
Field f = tmpClass.getDeclaredField(fieldName);
return f;
} catch (NoSuchFieldException e) {
tmpClass = tmpClass.getSuperclass();
}
} while (tmpClass != null);
throw new RuntimeException("Field '" + fieldName
+ "' not found on class " + clazz);
}
(based on this answer)
In fact i use a complex type hierachy so you solution is not complete.
I need to make a recursive call to get all the private inherited fields.
Here is my solution
/**
* Return the set of fields declared at all level of class hierachy
*/
public static List<Field> getAllFields(Class<?> clazz) {
return getAllFieldsRec(clazz, new ArrayList<>());
}
private static List<Field> getAllFieldsRec(Class<?> clazz, List<Field> list) {
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null) {
getAllFieldsRec(superClazz, list);
}
list.addAll(Arrays.asList(clazz.getDeclaredFields()));
return list;
}
private static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
for ( Field field : tmpClass.getDeclaredFields() ) {
String candidateName = field.getName();
if ( ! candidateName.equals(fieldName) ) {
continue;
}
field.setAccessible(true);
return field;
}
tmpClass = tmpClass.getSuperclass();
} while ( clazz != null );
throw new RuntimeException("Field '" + fieldName +
"' not found on class " + clazz);
}
I needed to add support for inherited fields for blueprints in Model Citizen. I derived this method that is a bit more concise for retrieving a Class' fields + inherited fields.
private List<Field> getAllFields(Class clazz) {
List<Field> fields = new ArrayList<Field>();
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
fields.addAll(getAllFields(superClazz));
}
return fields;
}
Commons Lang has the util method FieldUtils#getAllFieldsList for this.