docs: private static <T> T processJsonObjectBackIntoDataModelInstance(JsonObject json, Class<? extends T> typeOfObject, Verification verify) throws IOException, BadVersionException {
          Set<Map.Entry<String, JsonValue>> jsonSet = json.entrySet();
  
          // Make a new instance and make sure we know how to process it
          T targetObject = null;
          try {
              targetObject = typeOfObject.newInstance();
          } catch (InstantiationException e) {
              throw new IllegalStateException("Data Model Error: unable to instantiate data model element " + typeOfObject.getName(), e);
          } catch (IllegalAccessException e) {
              throw new IllegalStateException("Data Model Error: unable to instantiate data model element " + typeOfObject.getName(), e);
          }
  
          if (verify.equals(Verification.VERIFY) && targetObject instanceof VersionableContent) {
              String version = null;
              try {
                  version = json.getString(((VersionableContent) targetObject).nameOfVersionAttribute(), null);
              } catch (NullPointerException e) {
                  // Ignore
              }
              if (version != null) {
                  ((VersionableContent) targetObject).validate(version);
              }
          }
  
          for (Map.Entry<String, JsonValue> keyEntry : jsonSet) {
              String keyString = keyEntry.getKey();
              JsonValue value = keyEntry.getValue();
  
              if (value == null || value.getValueType().equals(ValueType.NULL))
                  continue;
  
              //When calling toString() on a JsonString the value is returned in quotation marks, so we need to call getString() on JsonString to avoid this
              String valueString = null;
              if (value.getValueType().equals(ValueType.STRING)) {
                  valueString = ((JsonString) value).getString();
              } else {
                  valueString = value.toString();
              }
  
              //values in the JsonValue can be; JsonObject, JsonArray, or simple data.
              //each is handled with an instanceof block.
  
              if (value instanceof JsonObject) {
                  //easy one, just find out the type for the new child, instantiate it, populate it, and set it.
                  ClassAndMethod fieldType = getClassForFieldName(keyString, targetObject.getClass());
                  if (fieldType != null) {
                      if (HasBreakingChanges.class.isAssignableFrom(fieldType.cls)) {
                          // It's something with a breaking change so see if we have a matching "2" element
                          JsonObject incompatibleFields = json.getJsonObject(keyString + "2");
                          if (incompatibleFields != null) {
                              JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder();
                              Set<Map.Entry<String, JsonValue>> valueSet = ((JsonObject) value).entrySet();
                              for (Map.Entry<String, JsonValue> entry : valueSet) {
                                  jsonObjectBuilder.add(entry.getKey(), entry.getValue());
                              }
                              Set<Map.Entry<String, JsonValue>> incompatibleFieldsSet = incompatibleFields.entrySet();
                              for (Map.Entry<String, JsonValue> entry : incompatibleFieldsSet) {
                                  jsonObjectBuilder.add(entry.getKey(), entry.getValue());
                              }
                              value = jsonObjectBuilder.build();
                          }
                      }
                      Object newChild = processJsonObjectBackIntoDataModelInstance((JsonObject) value, fieldType.cls, verify);
                      invokeSetter(fieldType.m, targetObject, newChild);
                  }
              } else if (value instanceof JsonArray) {
                  //slightly more tricky, we must determine the type for the collection to hold the data, instantiate a collection
                  //then process each element in the array into the collection, and set that into the targetObject.
                  ClassAndMethod fieldType = getClassForFieldName(keyString, targetObject.getClass());
                  if (fieldType != null) {
                      if (fieldType.cls.equals(Collection.class) ||
                          fieldType.cls.equals(List.class)) {
  
                          List<Object> newList = new ArrayList<Object>();
  
                          //this entry in the json object was an array we need to look at the targetObject to determine type information.
                          ClassAndMethod listElementType = getClassForCollectionOfFieldName(keyString, targetObject.getClass());
  
                          if (listElementType == null) {
                              throw new IllegalStateException("Data Model Error: unable to deserialize a JSON array into a field with no generic information. " + keyString);
                          }
  
                          // Process the nested array and tell it to throw any bad version exceptions as this is a nested array so if this is a get single by ID we may want to throw it
                          processJsonArray((JsonArray) value, newList, listElementType.cls, verify, ListVersionHandling.THROW_EXCEPTION);
  
                          invokeSetter(fieldType.m, targetObject, newList);
                      } else {
                          throw new IllegalStateException("Data Model Error: unable to deserialize a JSON array into a field that is not of type List/Collection " + keyString);
                      }
                  }
              } else {
                  //this entry in the json object was a normal value, if it's not an enum, it's easy, if it's an enum.. well..
                  ClassAndMethod fieldType = getClassForFieldName(keyString, targetObject.getClass());
                  if (fieldType != null) {
                      if (fieldType.cls.isEnum()) {
                          //enums are kind of tricky.. cannot set the value directly, must build the correct enum instance.
                          //approach 1.. uppercase value, and look for matching enum.
                          Object o = null;
                          if (keyString.indexOf(' ') == -1) {
                              try {
                                  Field enumInstance = fieldType.cls.getField(valueString.toUpperCase());
                                  if (enumInstance != null) {
                                      o = enumInstance.get(null);
                                  }
                              } catch (NoSuchFieldException e) {
                                  //handled later
                              } catch (SecurityException e) {
                                  //handled later
                              } catch (IllegalArgumentException e) {
                                  //handled later
                              } catch (IllegalAccessException e) {
                                  //handled later
                              }
                          }
                          if (o == null) {
                              //approach 2.. look for a method on enum taking string..
                              for (Method m : fieldType.cls.getMethods()) {
                                  if (Modifier.isStatic(m.getModifiers()) &&
                                      m.getParameterTypes().length == 1 &&
                                      m.getParameterTypes()[0].equals(String.class)) {
                                      //enums have a valueOf method.. which may work.. but if not..
                                      //there may be another method to use yet.
                                      if ("valueOf".equals(m.getName())) {
                                          try {
                                              o = m.invoke(null, valueString);
                                          } catch (IllegalArgumentException e) {
                                              //ignore.. maybe another method will work?
                                          } catch (InvocationTargetException e) {
                                              //ignore.. maybe another method will work?
                                          } catch (IllegalAccessException e) {
                                              //ignore.. maybe another method will work?
                                          }
                                      } else {
                                          try {
                                              o = m.invoke(null, valueString);
                                          } catch (IllegalAccessException e) {
                                              throw new IllegalStateException("Data Model Error: unable to invoke setter " + fieldType.m.getName() + " for data model element "
                                                                              + fieldType.cls.getName() + " on " + targetObject.getClass().getName(), e);
                                          } catch (IllegalArgumentException e) {
                                              throw new IllegalStateException("Data Model Error: unable to invoke setter " + fieldType.m.getName() + " for data model element "
                                                                              + fieldType.cls.getName() + " on " + targetObject.getClass().getName(), e);
                                          } catch (InvocationTargetException e) {
                                              throw new IllegalStateException("Data Model Error: unable to invoke setter " + fieldType.m.getName() + " for data model element "
                                                                              + fieldType.cls.getName() + " on " + targetObject.getClass().getName(), e);
                                          }
                                      }
                                      if (o != null)
                                          break;
                                  }
                              }
                          }
                          if (o == null) {
                              throw new IllegalStateException("Data Model Error: unable to handle Enum value of " + value + " for enum " + fieldType.cls.getName());
                          }
                          invokeSetter(fieldType.m, targetObject, o);
                      } else if (fieldType.cls.isPrimitive()) {
                          //primitives need more careful handling..
                          //all primitives in the current data model are numbers..
                          String type = fieldType.cls.getName();
                          if ("int".equals(type)) {
                              JsonNumber n = (JsonNumber) value;
                              invokeSetter(fieldType.m, targetObject, n.intValue());
                          } else if ("byte".equals(type)) {
                              JsonNumber n = (JsonNumber) value;
                              invokeSetter(fieldType.m, targetObject, (byte) n.intValue());
                          } else if ("short".equals(type)) {
                              JsonNumber n = (JsonNumber) value;
                              invokeSetter(fieldType.m, targetObject, (short) n.intValue());
                          } else if ("long".equals(type)) {
                              JsonNumber n = (JsonNumber) value;
                              invokeSetter(fieldType.m, targetObject, n.longValue());
                          } else if ("boolean".equals(type)) {
                              Boolean b = Boolean.valueOf(valueString);
                              invokeSetter(fieldType.m, targetObject, b);
                          } else {
                              throw new IllegalStateException("Data Model Error: unsupported primitive type used " + type + " in setter " + fieldType.m.getName());
                          }
  
                      } else if (fieldType.cls.equals(Calendar.class)) {
                          try {
                              Date d = getDateFormat().parse(valueString);
                              Calendar c = Calendar.getInstance();
                              c.setTime(d);
                              invokeSetter(fieldType.m, targetObject, c);
                          } catch (ParseException e) {
                              throw new IllegalStateException("JSON Error: date was not correctly formatted, got " + value, e);
                          }
                      } else if (fieldType.cls.equals(Date.class)) {
                          try {
                              Date d = getDateFormat().parse(valueString);
                              invokeSetter(fieldType.m, targetObject, d);
                          } catch (ParseException e) {
                              throw new IllegalStateException("JSON Error: date was not correctly formatted, got " + value, e);
                          }
                      } else if (fieldType.cls.equals(Locale.class)) {
                          Locale l = RepositoryCommonUtils.localeForString(valueString);
                          invokeSetter(fieldType.m, targetObject, l);
                      } else if (fieldType.cls.equals(String.class)) {
                          invokeSetter(fieldType.m, targetObject, valueString);
                      } else {
                          throw new IllegalArgumentException("Data Model Error: unable to invoke setter for data model element "
                                                             + fieldType.m.getName() + " on "
                                                             + targetObject.getClass().getName());
                      }
                  }
              }
          }
          return targetObject;
      }