/**
  * Performs a deep comparison (using reflection) of two objects to determine whether they are
  * different.
  *
  * <p>If the object is a Question then the answer is treated specially because the original value
  * of the answer from our point of view is the value provided by the client in an Answer fact. If
  * no such fact exists then the value on the question itself is used. Scenarios are:
  *
  * <ul>
  *   <li>Question which client has just answered - the new object is different if the answer is
  *       not the value provided by the client. i.e. if the rules have changed it to something else
  *       e.g. converting text to upper case.
  *   <li>Another question - the new object is different if the answer is not the value on the
  *       original object.
  * </ul>
  *
  * @param originalObject
  * @param newObject
  * @return
  */
 private boolean different(TohuObject originalObject, TohuObject newObject) {
   if (!originalObject.equals(newObject)) {
     return true;
   }
   // special handling for Question answers
   if (originalObject instanceof Question) {
     Question originalQuestion = (Question) originalObject;
     String originalAnswer;
     if (clientAnswers != null && clientAnswers.containsKey(originalQuestion.getId())) {
       // original answer is the one provided by the client
       originalAnswer = clientAnswers.get(originalQuestion.getId());
     } else {
       // original answer not provided by client so is contained in the original question
       originalAnswer =
           originalQuestion.getAnswer() == null ? null : originalQuestion.getAnswer().toString();
     }
     Question newQuestion = (Question) newObject;
     String newAnswer =
         newQuestion.getAnswer() == null ? null : newQuestion.getAnswer().toString();
     if (originalAnswer == null ? newAnswer != null : !originalAnswer.equals(newAnswer)) {
       return true;
     }
   }
   Class<?> clazz = originalObject.getClass();
   do {
     // compare all non-static non-transient fields
     for (Field field : clazz.getDeclaredFields()) {
       int modifiers = field.getModifiers();
       if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
         boolean answerField = field.isAnnotationPresent(Question.AnswerField.class);
         // answer fields are skipped because we have checked this already
         if (!answerField) {
           field.setAccessible(true);
           try {
             Object originalValue = field.get(originalObject);
             Object newValue = field.get(newObject);
             if (originalValue == null ? newValue != null : !originalValue.equals(newValue)) {
               return true;
             }
           } catch (IllegalArgumentException e) {
             throw new RuntimeException(e);
           } catch (IllegalAccessException e) {
             throw new RuntimeException(e);
           }
         }
       }
     }
     clazz = clazz.getSuperclass();
   } while (clazz != null);
   return false;
 }