12

I am trying to compare the field values of two different objects in a generic way. I have a function (seen below) that takes in two Objects and then gets the fields and then compares the fields in a loop and adds the fields to a list if they are not the same - is this the proper way to do this?

public void compareFields(Object qa, Object qa4) throws FieldsNotEqualException
{

  Field[] qaFields = qa.getClass().getFields();
  Field[] qa4Fields = qa4.getClass().getFields();

  for(Field f:qaFields) 
  { 

    for(Field f4:qa4Fields)
    {
       if(f4.equals(f))
       {
           found = true;
           break;
       }
       else
       {
           continue;
       }
    }
  }

 if(!found)
 {
    report.add(/*some_formatted_string*/) //some global list 
    throw new FieldsNotEqualException();
 }
}

I was googling and I saw that C# had like a PropertyInfo Class - does Java have anything like that? ALSO, is there a way to do like f.getFieldValue() -I know there is no method like this but maybe there is another way???

Slim
  • 1,708
  • 5
  • 37
  • 60
JonH
  • 501
  • 7
  • 13
  • 25
  • Fields belong to classes, values are held (if not static) in instances. What exactly you are trying to accomplish? – khachik Nov 21 '12 at 15:05
  • Ok I should have been clearer - im passing in two instances of two objects - im trying to compare two data sets (lists of objects) that are being returned by hibernate - but I am passing them in a loop one instance of the object of some class at a time to compare the fields of that instance against some other instance – JonH Nov 21 '12 at 15:07
  • @JohH If you are using Hibernate, this approach might not work - Hibernate modifies the object contents at runtime and I am not sure that reflection will work - it might, but if you experience something funny, it could be Hibernate interfering with the object properties. – Ravi Wallau Nov 21 '12 at 15:13
  • @RaviWallau I think at that point Hibernate is done interfering with those objects...I run a query and then get a List() back from hibernate. If I wanted to do it in a non generic way I could cast each of the instances in the list and then compare the values - but that would be a lot of code that could be done generically. – JonH Nov 21 '12 at 15:19
  • @JohH If you are using IntelliJ you can generate equals() and hashCode() automatically. I tend to like these more than using reflection to compare the data, as with reflection you can't limit the fields that will be compared. – Ravi Wallau Nov 22 '12 at 15:29
  • Off topic - I see you just deleted a question. I hope you didn't let the negativity get to you, it was a valid question and you deserved a reasonable answer. http://stackoverflow.com/questions/13960118/64-bit-pointer-conversion – Mark Ransom Dec 19 '12 at 20:31
  • @MarkRansom I realized that I didn't fully understand the code prior to me asking the question - and once I did understand I figured that the question wasn't a very good question...and since it had gotten so much feedback that it would be best to delete it... – JonH Dec 26 '12 at 16:35

3 Answers3

17

You might check out org.apache.commons.lang.builder.EqualsBuilder which will save you a lot of this hassle if you're wanting to do a field by field comparison.

org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(Object, Object)

If you're wanting to compare fields yourself, check out java.lang.Class.getDeclaredFields() which will give you all the fields including non-public fields.

To compare the value of the fields use f.get(qa).equals(f.get(qa4)) Currently, you are actually comparing the field instances and not the values.

tjg184
  • 4,508
  • 1
  • 27
  • 54
  • how does getDeclaredFields() help when i need to compare the values? – JonH Nov 21 '12 at 15:13
  • @JonH I updated my answer slightly. The main point is that you really should consider a common library for doing this comparision. Hope this helps. – tjg184 Nov 21 '12 at 15:19
  • Ok - I believe this is working - but I have a quick question - so o`f.get(qa)` will get field "some_name"'s value - so I dont have to worry about field ordering or making sure it is comparing the same field right? – JonH Nov 21 '12 at 15:45
  • Assuming these are the same class type, the field order will be the same. – tjg184 Nov 21 '12 at 15:48
3

Libraries like commons-beanutils can help you if you want to compare bean properties (values returned by getters) instead of comparing field values.

However, if you want to stick with plain reflection, you should:

  1. Use Class.getDeclaredFields() instead of Class.getFields(), as the latter only returns the public fields.
  2. Since fields only depend on their class, you should cache the result and keep the fields in a static / instance variable rather than invoking getDeclaredFields() for each comparison.
  3. Once you have an object of that class (say o), in order to get the value of some field f for that particular object, you need to call: f.get(o).
Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
0

// If you want to have some fields, not all field then use this.

  public boolean compareObject(Object object) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException 
{

 String[] compareFields = { "fieldx", "fieldy","fieldz", "field15",
        "field19"}; // list of all we need 
for(String s : compareFields) {
Field field = DcrAttribute.class.getDeclaredField(s); // get a list of all fields for this class
    field.setAccessible(true);
    if(!field.get(this).equals(field.get(object))){  //if values are not equal          
    return true;    
    }       

    }

    return false;
}