非Hibernate环境下如何将List<String>存入PostgreSQL的JSONB字段?
Since you're using Spring Data Reactive (R2DBC) without Hibernate, the @Type annotation won't work here. The error occurs because R2DBC doesn't automatically know how to convert a List<String> to PostgreSQL's jsonb type—it's defaulting to treating it as a primitive array (hence the smallint[] mismatch). Here's how to fix this:
Step 1: Create Custom Converters
You need two converters: one to serialize your List<String> to a JSON object, and another to deserialize the JSON back to a List<String>. We'll use Jackson's ObjectMapper for this (most Spring Boot projects include this by default, but add it to your dependencies if missing).
List to Json Converter
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.WritingConverter; import io.r2dbc.postgresql.codec.Json; import java.util.List; @WritingConverter public class ListToJsonConverter implements Converter<List<String>, Json> { private final ObjectMapper objectMapper; public ListToJsonConverter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public Json convert(List<String> source) { try { return Json.of(objectMapper.writeValueAsString(source)); } catch (JsonProcessingException e) { throw new IllegalArgumentException("Failed to convert List<String> to JSON", e); } } }
Json to List Converter
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.ReadingConverter; import io.r2dbc.postgresql.codec.Json; import java.util.List; @ReadingConverter public class JsonToListConverter implements Converter<Json, List<String>> { private final ObjectMapper objectMapper; public JsonToListConverter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public List<String> convert(Json source) { try { return objectMapper.readValue(source.asString(), new TypeReference<List<String>>() {}); } catch (Exception e) { throw new IllegalArgumentException("Failed to convert JSON to List<String>", e); } } }
Step 2: Register the Converters
Register your custom converters with the R2DBC configuration. Create a configuration class to handle this:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; import io.r2dbc.spi.ConnectionFactory; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Arrays; @Configuration public class R2dbcConfig extends AbstractR2dbcConfiguration { private final ObjectMapper objectMapper; public R2dbcConfig(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public ConnectionFactory connectionFactory() { // Add your existing PostgreSQL ConnectionFactory setup here // Example: return new PostgresConnectionFactory(PostgresConnectionConfiguration.builder()...build()); } @Override protected R2dbcCustomConversions r2dbcCustomConversions() { return new R2dbcCustomConversions( R2dbcCustomConversions.STORE_CONVERTERS, Arrays.asList( new ListToJsonConverter(objectMapper), new JsonToListConverter(objectMapper) ) ); } }
If you don't want to extend AbstractR2dbcConfiguration, you can register the conversions as a standalone bean:
@Bean public R2dbcCustomConversions r2dbcCustomConversions(ObjectMapper objectMapper) { return new R2dbcCustomConversions( R2dbcCustomConversions.STORE_CONVERTERS, Arrays.asList( new ListToJsonConverter(objectMapper), new JsonToListConverter(objectMapper) ) ); }
Step 3: Explicitly Define Column Type (Optional)
To make your entity class clearer, explicitly specify the column type for the colors field:
public class Tool implements Persistable<UUID> { @Id @Column("tool_id") private UUID id; @Column("tool_name") private String name; @Column(value = "tool_colors", columnDefinition = "jsonb") private List<String> colors; // Add getters, setters, and Persistable interface implementations here }
Step 4: Test the Setup
Now when you call toolRepository.save(tool), R2DBC will use your custom converters to serialize the List<String> to a JSONB-compatible value, resolving the type mismatch error.
内容的提问来源于stack exchange,提问作者lgean

