2
  • edit - Here I gave a specific obj. as an example but I'm asking for any obj. I am given *

I'm looking for a way to get all public attributes in the class and all subclasses of an object (name of the attribute and its value). Let say we have a People object:

i

mport java.util.ArrayList;

    public class People {
        public ArrayList<Person> ppl= new ArrayList<Person>();
        int count=2;
        public People() {
            ppl.add(new Person(55, "Daddy", "Long Legs"));
            ppl.add(new Person(20, "Jhon", "Snow"));
        }
        public class Person{
            public int age;
            public Name name;
            public Person(int age, String first, String last){
                this.name = new Name(first, last);
                this.age = age;
            }
            public class Name{
                String first;
                String last;
                public Name(String first, String last) {
                    this.first = first;
                    this.last = last;
                }
            }
        }

    }

I saw a reference here (I can't comment on there bc I don't have enough points): Java reflection get sub class variable values / get object instance from member field

and tried to implement it also but then my output is

ppl [People$Person@4aa298b7, People$Person@7d4991ad]

whereas I need it needs to go into each Person and extract its variables(and their values). I searched for a information that could help me but I couldn't find anything..any advice?

xYaelx
  • 144
  • 1
  • 1
  • 11

5 Answers5

1

code a toString() method

What you are getting People$Person@4aa298b7 is the Object.toString representation....

getClass().getName() + '@' + Integer.toHexString(hashCode())

IMHO You need to override the toString() method in both classes: Person and Name.

For example:

public class Name{
    String first;
    String last;
    public Name(String first, String last) {
        this.first = first;
        this.last = last;
    }

    @Override
    public String toString() {
        return this.first + " " + this.last;
    }
} 

get fields and values based on known Person class

If this does not fit, you can get fields names and values using reflection like this:

public static void main(String[] args) throws IllegalAccessException
{
    People pe = new People();
    Field[] allFields = People.Person.class.getDeclaredFields();

    for (Field field : allFields)
    {
      for (People.Person p : pe.ppl)
        System.out.println("Name: " + field.getName() + ". Value: " + field.get(p));
    }
}

OUTPUT:

Name: age. Value: 55
Name: age. Value: 20
Name: name. Value: Daddy Long Legs
Name: name. Value: Jhon Snow
Name: this$0. Value: People@677327b6
Name: this$0. Value: People@677327b6

NOTE: if you don't want this 2 final values representing the People with ugly results you can:

  • Split Person and Name and make them 2 independent classes
  • Make a toString() method in People class

dynamically get fields from inner classes

If you want to dynamically get fields from inner classes:

public static void main(String[] args) throws IllegalAccessException
{
    Class[] allClasses = People.class.getClasses();

    for (Class clazz : allClasses) {
      Field[] allFields = clazz.getFields();
      for (Field field : allFields) {
        String className = clazz.getName();
        String fieldName = field.getName();
        System.out.println("Class name: " + className + " - Field name: " + fieldName + ".");
      }
    }
}

OUTPUT:

Class name: People$Name - Field name: first.
Class name: People$Name - Field name: last.
Class name: People$Person - Field name: age.
Class name: People$Person - Field name: name.

But not sure how you can get values from inside the ArrayList<Person>....

Community
  • 1
  • 1
Jordi Castilla
  • 26,609
  • 8
  • 70
  • 109
  • this is not what OP was asking for – Sharon Ben Asher Feb 13 '18 at 11:00
  • @SharonBenAsher OP is searching for reflection, but reflection is explained in linked question... so IMHO I think it is what OP needs.... Maybe my assumption is wrong... lets OP tell us `:)` – Jordi Castilla Feb 13 '18 at 11:03
  • @SharonBenAsher maybe what you think OP needs is the update in my answer? – Jordi Castilla Feb 13 '18 at 13:21
  • 1
    what I think OP meant was to dynamically get field values from all inner classes of any given class, not to have hard coded `People.Person`. For example, in the question, there is `People.Person.Name` inner class that you did not introspect – Sharon Ben Asher Feb 13 '18 at 13:45
  • you'rw right about the toString method but here is only an example..I can't know if there's a toString method in the given object (or can I?). I gave here an example with People and Person object but I don't really know the object type. It should be general for any object I get...In you dynamically solution you also didn't manage to get the variables value. Do you have any thought why get method doesn't return it? (and thanks a lot!) – xYaelx Feb 13 '18 at 21:40
  • about `toString()` method, yes, you can get all methods in the class thus you can check if it exists. About how to get values from attributes as said in the answer I'm not sure how you can do it, you need an instance of the object and in your case is inside an `ArrayList`.... – Jordi Castilla Feb 14 '18 at 09:37
1
public People() {
        ppl.add(new Person(55, "Daddy", "Long Legs"));
        ppl.add(new Person(20, "Jhon", "Snow"));

        for (Person person : ppl) {
            System.out.println(person.name.last);
            System.out.println(person.name.first);
            System.out.println(person.age);
        }

        System.out.println("Size of list: " + ppl.size());
    }

Example without toString() method.

Black_Buster
  • 102
  • 5
  • thanks but People was just an example..I need to list all the variable names and values for any kind of objects :| – xYaelx Feb 13 '18 at 21:48
1

I believe the closest you can get is related to this question java: get all variable names in a class .

Using Field[] fields = YourClassName.class.getFields(); returns all class fields as java.lang.reflect.Field.

You can check if field is public using Field.getModifiers() and Modifier.isPublic(Modifier).

You can get the field value using Object Field.get().

Hope that helps.

vontman
  • 11
  • 3
1

I Agree with @Jordi Castilla , you need to override toString method properly to get correct output.

For Example :

import java.util.ArrayList;
class People {

    public ArrayList<Person> ppl= new ArrayList<Person>();
    int count=2;
    public People() {
        ppl.add(new Person(55, "Daddy", "Long Legs"));
        ppl.add(new Person(20, "Jhon", "Snow"));
    }

    @Override
    public String toString() {
        return "{ Count: "+this.count + " , People:" + this.ppl+" }";
    }

    public class Person{
        public int age;
        public Name name;
        public Person(int age, String first, String last){
            this.name = new Name(first, last);
            this.age = age;
        }


        @Override
        public String toString() {
            return "{ Name: "+this.name + " , Age:" + this.age+" }";
        }

        public class Name{
            String first;
            String last;
            public Name(String first, String last) {
                this.first = first;
                this.last = last;
            }

            @Override
            public String toString() {
                return "{ FirstName: "+this.first + ", LastName: " + this.last+ " }";
            }
        }
    }


  public static void main(String[] args) {
    People ppl = new People();
    System.out.println("OUTPUT => "+ ppl.toString());

  }
}


//Output

OUTPUT => { 
    Count: 2 , 
    People:[
        { Name: { FirstName: Daddy, LastName: Long Legs } , Age:55 }, 
        { Name: { FirstName: Jhon, LastName: Snow } , Age:20 }
    ] 
}
Mahendra Kapadne
  • 426
  • 1
  • 3
  • 10
  • notice that your code just prints the values of the variable and not their names...(for example, the original name of the variable is "age" but it isn't printed in your output) – xYaelx Feb 14 '18 at 12:55
  • I think printing “age” instead of “Age” is just matter of changing toString method implementation for Person object. If you have any other purpose for it then please explain it. – Mahendra Kapadne Feb 14 '18 at 13:06
  • of course. my intention was that your method doesn't actually get the variable name as it was defined...oh wait- you just printed the values here..I am attaching my solution so far. Maybe you'll have an idea how to print the internal list variable names – xYaelx Feb 14 '18 at 13:28
1

here is a recursive method I did (after I added a toString method to Name class). Here it is. However, it is still doesn't prints the variable names inside the ppl list:

private static String getAllFields(Object obj){
    Class<?> objClass = obj.getClass();
    StringBuilder res = new StringBuilder();
    Field[] fields = objClass.getFields();
    res.append(objClass+"\n");

    for(Field field : fields) {
        Class<?> type = field.getType();
        String name = field.getName();
        res.append(" name: "+name+ " ");

        try {
            Object value = field.get(obj);
            res.append("value: "+value+ "\n");
            if (!type.isPrimitive() && !name.contains("java.lang"))
            {
                res.append(getAllFields(value));
            }
        } catch (IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    return res.toString();
}

here is the output: class People name: ppl value: [Daddy Long Legs 55 , Jhon Snow 20 ] class java.util.ArrayList name: count value: 2

notice that there isn't the Person class name there in the output or the names of the variable names of the variables there. I don't really understand why

xYaelx
  • 144
  • 1
  • 1
  • 11