public static <C> List<C> fetch(Class<C> cls, DatabaseObject filteredBy) {
    Database database = filteredBy.getDatabase();

    @SuppressWarnings("unchecked")
    AnnotatedRecordMapper<DatabaseObject> parentMapper =
        (AnnotatedRecordMapper<DatabaseObject>) create(filteredBy.getClass());
    AnnotatedRecordMapper<?> mapper = create(cls);

    List<String> relationColumnNames = mapper.getRelationColumnNames(filteredBy.getClass());
    List<String> idColumnNames = parentMapper.getIdColumnNames();
    Map<String, Object> values = parentMapper.extractIds(filteredBy);

    String relationExpression = "";
    Object[] parameters = new Object[relationColumnNames.size()];

    for (int i = 0; i < relationColumnNames.size(); i++) {
      relationExpression += relationColumnNames.get(i) + "=?";
      parameters[i] = values.get(idColumnNames.get(i));

      if (parameters[i] == null) {
        return new ArrayList<>();
      }
    }

    try (Transaction transaction = database.beginReadOnlyTransaction()) {
      transaction.associate(filteredBy);

      return transaction.select(cls, relationExpression, parameters);
    }
  }
  @SuppressWarnings("unchecked")
  public static <T extends DatabaseObject> T fetch(T instance) {
    Database database = instance.getDatabase();
    Object[] ids;

    synchronized (STUBS) {
      ids = STUBS.get(instance);
    }

    if (database == null || ids == null) {
      return instance;
    }

    AnnotatedRecordMapper<? extends Object> mapper = create(instance.getClass());

    String whereClause = "";

    for (String fieldName : mapper.getIdColumnNames()) {
      if (!whereClause.isEmpty()) {
        whereClause += " AND ";
      }
      whereClause += fieldName + "=?";
    }

    try (Transaction transaction = database.beginReadOnlyTransaction()) {
      return (T) transaction.selectUnique(instance.getClass(), whereClause, ids);
    }
  }
    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);
      }
    }