@Override
  public List<Property> findOrderedFields(
      final Class<?> clazz, boolean returnSettersWhenAvailable) {
    List<Property> fields =
        !dynamicClass
            ? (returnSettersWhenAvailable
                ? orderedSetterFields.get(clazz)
                : orderedFields.get(clazz))
            : null;

    if (fields == null) {
      if (dynamicClass) {
        Introspector.flushFromCaches(clazz);
      }
      PropertyDescriptor[] propertyDescriptors = TypeUtil.getProperties(clazz);
      Converters converters =
          ((ConvertersConfig) GraniteContext.getCurrentInstance().getGraniteConfig())
              .getConverters();

      fields = new ArrayList<Property>();

      List<Property> idVersionFields = new ArrayList<Property>();

      Set<String> allFieldNames = new HashSet<String>();
      for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {

        List<Property> newFields = new ArrayList<Property>();

        // Standard declared fields.
        for (Field field : c.getDeclaredFields()) {
          if (!allFieldNames.contains(field.getName())
              && !Modifier.isTransient(field.getModifiers())
              && !Modifier.isStatic(field.getModifiers())
              && !field.isAnnotationPresent(Exclude.class)
              && !GrailsExternalizer.isIgnored(field)) {

            boolean found = false;
            if (returnSettersWhenAvailable && propertyDescriptors != null) {
              for (PropertyDescriptor pd : propertyDescriptors) {
                if (pd.getName().equals(field.getName()) && pd.getWriteMethod() != null) {
                  if ("id".equals(field.getName()) || "version".equals(field.getName())) {
                    if (c == clazz) {
                      idVersionFields.add(
                          new MethodProperty(
                              converters,
                              field.getName(),
                              pd.getWriteMethod(),
                              pd.getReadMethod()));
                    }
                  } else {
                    newFields.add(
                        new MethodProperty(
                            converters, field.getName(), pd.getWriteMethod(), pd.getReadMethod()));
                  }
                  found = true;
                  break;
                }
              }
            }
            if (!found) {
              if ("id".equals(field.getName()) || "version".equals(field.getName())) {
                idVersionFields.add(new FieldProperty(converters, field));
              } else {
                newFields.add(new FieldProperty(converters, field));
              }
            }
          }
          allFieldNames.add(field.getName());
        }

        // Getter annotated  by @ExternalizedProperty.
        if (propertyDescriptors != null) {
          for (PropertyDescriptor property : propertyDescriptors) {
            Method getter = property.getReadMethod();
            if (getter != null
                && getter.isAnnotationPresent(Include.class)
                && getter.getDeclaringClass().equals(c)
                && !allFieldNames.contains(property.getName())
                && !GrailsExternalizer.isIgnored(property)) {

              newFields.add(new MethodProperty(converters, property.getName(), null, getter));
              allFieldNames.add(property.getName());
            }
          }
        }

        if (isRoot(c)) {
          newFields.addAll(idVersionFields);
        }

        Collections.sort(
            newFields,
            new Comparator<Property>() {
              public int compare(Property o1, Property o2) {
                return o1.getName().compareTo(o2.getName());
              }
            });

        fields.addAll(0, newFields);
      }

      if (!dynamicClass) {
        List<Property> previousFields =
            (returnSettersWhenAvailable ? orderedSetterFields : orderedFields)
                .putIfAbsent(clazz, fields);
        if (previousFields != null) {
          fields = previousFields;
        }
      }
    }

    return fields;
  }