spring-projects / spring-data-r2dbc

Provide support to increase developer productivity in Java when using Reactive Relational Database Connectivity. Uses familiar Spring concepts such as a DatabaseClient for core API usage and lightweight repository style data access.
Apache License 2.0
708 stars 132 forks source link

Custom converter is not used for conversion in `QueryMapper` if value implements `Iterable` #819

Closed saymeales closed 1 year ago

saymeales commented 1 year ago

org.springframework.data:spring-data-r2dbc -> 1.5.5

I use com.fasterxml.jackson.databind.JsonNode for json values in my entities, and there is JsonNode to io.r2dbc.postgresql.codec.Json Reading/Writing converters registered in my DataAccessStrategy.

But when I want to use JsonNode as the value for update (data is instance of JsonNode), I`m get an exception:

return r2dbcTemplate.update(Entity.class)
                .matching(query(where("id").is(id).and("key").is(key)))
                .apply(Update.update("data",data)
                        .set("updated", OffsetDateTime.now()));

java.lang.IllegalArgumentException: Cannot encode parameter of type java.util.ArrayList ([[], []])
    at io.r2dbc.postgresql.codec.DefaultCodecs.encodeParameterValue(DefaultCodecs.java:276)

As I can find out, this happens because JsonNode implements Iterable and there is following code in QueryMapper#convertValue:

if (value instanceof Iterable) {
  List<Object> mapped = new ArrayList<>();
  for (Object o : (Iterable<?>) value) {
    mapped.add(convertValue(o, typeInformation.getActualType() != null ? typeInformation.getRequiredActualType()
                : ClassTypeInformation.OBJECT));
  }
  return mapped;
}

if (value.getClass().isArray()
    && (ClassTypeInformation.OBJECT.equals(typeInformation) || typeInformation.isCollectionLike())) {
  return value;
}

return this.converter.writeValue(value, typeInformation);
mp911de commented 1 year ago

That's fixed now.