public Object toJavaType(Map<String, Object> map, Transaction transaction) {
      try {
        if (isEmbedded()) {
          Class<?>[] types = new Class<?>[names.length];
          Object[] idValues = new Object[names.length];

          for (int i = 0; i < names.length; i++) {
            Object value = map.get(names[i]);

            if (value == null) {
              return null;
            }

            types[i] = value.getClass();
            idValues[i] = value;
          }

          Constructor<?> constructor = getType().getConstructor(types);

          return constructor.newInstance(idValues);
        } else if (isRelation(getType())) {
          Object[] idValues = new Object[names.length];

          for (int i = 0; i < names.length; i++) {
            idValues[i] = map.get(names[i]);
          }

          DatabaseObject associatedObject = transaction.findAssociatedObject(getType(), idValues);

          if (associatedObject == null) {
            associatedObject = (DatabaseObject) getType().newInstance();
            associatedObject.setDatabase(transaction.getDatabase());
            associateStub(associatedObject, idValues);
          }

          return associatedObject;
        }

        return dataTypeConverter.toJavaType(map.get(names[0]), getType());
      } catch (NoSuchMethodException
          | SecurityException
          | IllegalAccessException
          | IllegalArgumentException
          | InvocationTargetException
          | InstantiationException e) {
        throw new RuntimeException(e);
      }
    }
  @Override
  public void invokeAfterLoadStore(T object, Database database) throws DatabaseException {
    if (object instanceof DatabaseObject) {
      ((DatabaseObject) object).setDatabase(database);
    }

    if (afterLoadStore != null) {
      try {
        afterLoadStore.invoke(object, database);
      } catch (DatabaseException e) {
        throw e;
      } catch (Throwable e) {
        throw new RuntimeException(e);
      }
    }
  }