I want to support the feature that combine multiple SqlParamterSource to a one SqlParameterSource. For example, When save a domain object to the database, I want to bind retrieving values from domain object and other object(e.g. login user object) to an SQL using NamedParameterJdbcOperations.

WDYT?

Code sample:

Account newAccount = new Account();
// ...
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcOperations.update(
    "INSERT INTO accounts (name, email, created_at, created_by) " +
    "VALUES(:name, :email, current_timestamp, :operatorId)",
    SqlParameterSource.combine(
        new BeanPropertySqlParameterSource(newAccount), // retrieving 'name' and 'email'
        new BeanPropertySqlParameterSource(operator)), // retrieving 'operatorId'
    keyHolder);
// ...
public interface SqlParameterSource {

  // …

  static SqlParameterSource combine(SqlParameterSource... sources) {
    return new CompositeSqlParameterSource(sources);
  }

  public static class CompositeSqlParameterSource implements SqlParameterSource {
    private final Map<String, SqlParameterSource> cache = new HashMap<>();
    private final SqlParameterSource[] sources;

    private CompositeSqlParameterSource(SqlParameterSource... sources) {
      this.sources = sources;
    }

    @Override
    public boolean hasValue(String paramName) {
      return cache.computeIfAbsent(paramName,
          x -> Stream.of(sources).filter(s -> s.hasValue(paramName)).findFirst().orElse(null)) != null;
    }

    @Override
    public Object getValue(String paramName) {
      return hasValue(paramName) ? cache.get(paramName).getValue(paramName) : null;
    }

    @Override
    public String getTypeName(String paramName) {
      return hasValue(paramName) ? cache.get(paramName).getTypeName(paramName) : null;
    }

    @Override
    public int getSqlType(String paramName) {
      return hasValue(paramName) ? cache.get(paramName).getSqlType(paramName) : TYPE_UNKNOWN;
    }

    @Override
    public String[] getParameterNames() {
      return Stream.of(sources)
          .map(SqlParameterSource::getParameterNames)
          .flatMap(Stream::of).distinct()
          .toArray(String[]::new);
    }
  }

}

Comment From: snicoll

See #24032