36

I have a Java class that has a number of Fields.

I would like to Loop over al lthe fields and do something for the one's that are null.

For example if my class is:

public class ClassWithStuff {
    public int inty;
    public stringy;         
    public Stuff;
    //many more fields
}

In another location, I'd make a ClassWithStuff object and I would like to go though all the fields in the class. Kind of like this:

for (int i = 0; i < ClassWithStuff.getFields().size(); i++) {
      //do stuff with each one
}

Is there any way for me to achieve this?

CodyBugstein
  • 21,984
  • 61
  • 207
  • 363
  • 1
    This smells like a XY problem. What is your initial goal? – fge Jun 13 '13 at 19:41
  • List of Objects is fine too, since I'm just testing if they are null – CodyBugstein Jun 13 '13 at 19:42
  • 2
    @fge What's an XY problem? – CodyBugstein Jun 13 '13 at 19:42
  • 3
    It means you have problem X but are asking about a solution Y whereas there may be a much better way to solve X – fge Jun 13 '13 at 19:43
  • 1
    I don't know whats up with everyone trying to post the same answer slightly differently these days. Does editing an existing valid answer to elaborate hurt so much? Seriously! – MickJ Jun 13 '13 at 19:47
  • @MickJ Sometimes people post the answer at same time or within seconds of eachother, unaware that someone else has posted a similar answer. – CodyBugstein Jun 13 '13 at 19:48
  • Well I can see these answers are couple of minutes apart and SO does a great job at notifying about new answers. Anyway. – MickJ Jun 13 '13 at 19:50
  • Actually found the perfect answer: Its another question: http://stackoverflow.com/questions/7223482/java-how-can-i-with-reflection-check-if-a-field-is-initialized-or-is-default-val – MickJ Jun 13 '13 at 19:58

5 Answers5

37

Use getDeclaredFields on [Class]

ClasWithStuff myStuff = new ClassWithStuff();
Field[] fields = myStuff.getClass().getDeclaredFields();
for(Field f : fields){
   Class t = f.getType();
   Object v = f.get(myStuff);
   if(t == boolean.class && Boolean.FALSE.equals(v)) 
     // found default value
   else if(t.isPrimitive() && ((Number) v).doubleValue() == 0)
     // found default value
   else if(!t.isPrimitive() && v == null)
     // found default value
}

(http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html)

pathe.kiran
  • 2,444
  • 1
  • 21
  • 27
Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69
  • 1
    That null check would not suffice. Please see: http://stackoverflow.com/questions/7223482/java-how-can-i-with-reflection-check-if-a-field-is-initialized-or-is-default-val – MickJ Jun 13 '13 at 19:58
  • @MickJ If he only wants to check if references are null then this ought to do the trick (since primitive fields will be returned as non-null), but if he also wants to check if primitives are initialized (e.g. numbers aren't 0) then this won't suffice – Zim-Zam O'Pootertoot Jun 13 '13 at 20:01
  • That was my assumption based on the int field in his class. By his statement of null I assumed he meant not initialized. But you are right. I might be wrong with my assumption. – MickJ Jun 13 '13 at 20:02
  • @MickJ is correct - I also want to look for default values of `0` – CodyBugstein Jun 13 '13 at 20:09
  • I posted an edit to reflect that but unfortunately it has not been accepted yet. In essence this is what you could do inside the loop based on the other nice SO answer: Class t = field.getType(); Object v = field.get(o); if(t == boolean.class && Boolean.FALSE.equals(v)) // found default value else if(t.isPrimitive() && ((Number) v).doubleValue() == 0) // found default value else if(!t.isPrimitive() && v == null) // found default value – MickJ Jun 13 '13 at 20:10
  • 1
    what is the value of o? – Lou Morda Dec 16 '14 at 20:27
  • 1
    @LouisMorda The object whose fields you're looking up – Zim-Zam O'Pootertoot Dec 16 '14 at 21:49
  • @Zim-Zam O'Pootertoot So, `mystuff`? – Cameron Hudson Apr 13 '19 at 20:51
  • @CameronHudson yes – pathe.kiran Apr 15 '19 at 10:19
10

Yes, with reflection.

Use the Class object to access Field objects with the getFields() method.

Field[] fields = ClassWithStuff.class.getFields();

Then loop over the fields. This works because all fields you have declared are public. If they aren't, then use getDeclaredFields(), which accesses all Fields that are directly declared on the class, public or not.

rgettman
  • 176,041
  • 30
  • 275
  • 357
  • But `ClassWithStuff` doesn't have a `getFields()` method. – CodyBugstein Jun 13 '13 at 19:47
  • `ClassWithStuff.class.getFields()` will give you public declared fields. `ClassWithStuff.class.getDeclaredFields()` will give you all declared fields. – Mike Strobel Jun 13 '13 at 19:51
  • 1
    Silly me, I forgot to add the class literal. I've modified my answer to say "ClassWithStuff _.class_ .getFields()". – rgettman Jun 13 '13 at 19:54
  • Thanks it works! But how do I get the value of the field? I want to check if it's `null` or uninitialized. – CodyBugstein Jun 13 '13 at 19:59
  • See the [field](http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Field.html#get%28java.lang.Object%29) javadoc; use `f.get(obj)` where `f` is a field and `obj` is the object whose fields you want to check – Zim-Zam O'Pootertoot Jun 13 '13 at 20:03
3

What are looking for is called reflection. Reflection lets you look at your own class, or another class to see what it is made of. Java has reflection built in, so you can use it right away. Then you can do stuff like -

for(Field f : ClasWithStuff.getFields()){
    System.out.println(f.getName());//or do other stuff with it
}

You can also use this to get methods, constructors, etc, to do similar and cooler stuff.

David says Reinstate Monica
  • 19,209
  • 22
  • 79
  • 122
1

A Java 8+ solution using the library durian and Stream.

The utility method FieldsAndGetters.fields(Object obj)

Returns a Stream of all public fields and their values for the given object.

This will find the fields of ClassWithStuff since they all are public.

Let's see how to use it with (a little bit modified) ClassWithStuff:

public static class BaseStuff {
    public DayOfWeek dayOfWeek = DayOfWeek.MONDAY;
}

public static class ClassWithStuff extends BaseStuff {
    public int inty = 1;
    public String stringy = "string";
    public Object Stuff = null;
}

Example - Printing the name and value of each field:

public static void main(String[] args) throws Exception {
    ClassWithStuff cws = new ClassWithStuff();
    FieldsAndGetters.fields(cws) 
            .map(field -> field.getKey().getName() + " = " + field.getValue())
            .forEach(System.out::println);
}

The output:

inty = 1
stringy = string
Stuff = null
dayOfWeek = MONDAY

As the ouptut shows even inherited public fields are considered.

LuCio
  • 5,055
  • 2
  • 18
  • 34
0

It is possible to use pojo-analyzers which will also enable to access the getters and setters of the field (without reflection).

@DetailedPojo
public class ClassWithStuff {
    public String someString;
    //many more fields
}
...
ClassWithStuff classWithStuff = new ClassWithStuff("myString");
DetailedClassWithStuff.list.stream()
    .forEach(fieldDetails -> 
            System.out.println(fieldDetails.getFieldValue(classWithStuff)); // "myString"

The library uses annotation processing so there is no reflection involved.

user7551211
  • 649
  • 1
  • 6
  • 25