1

In my project I have the following entity which can be successfully saved in Postgres:

public class Aggregate {

  @Id
  private UUID id;

  private JsonNode data;

  // getters and setters omitted
}

When I try to save the same entity in SQLite I get the following exception:

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [java.util.UUID]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322) ~[spring-core-5.3.5.jar:5.3.5]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-5.3.5.jar:5.3.5]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175) ~[spring-core-5.3.5.jar:5.3.5]
    at org.springframework.data.mapping.model.ConvertingPropertyAccessor.convertIfNecessary(ConvertingPropertyAccessor.java:120) ~[spring-data-commons-2.4.6.jar:2.4.6]
    at org.springframework.data.mapping.model.ConvertingPropertyAccessor.setProperty(ConvertingPropertyAccessor.java:63) ~[spring-data-commons-2.4.6.jar:2.4.6]
    at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.setIdAndCascadingProperties(JdbcAggregateChangeExecutionContext.java:337) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
    at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.populateIdsIfNecessary(JdbcAggregateChangeExecutionContext.java:305) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
    at org.springframework.data.jdbc.core.AggregateChangeExecutor.execute(AggregateChangeExecutor.java:52) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
    at org.springframework.data.jdbc.core.JdbcAggregateTemplate.store(JdbcAggregateTemplate.java:339) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
    at org.springframework.data.jdbc.core.JdbcAggregateTemplate.save(JdbcAggregateTemplate.java:149) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
    at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.save(SimpleJdbcRepository.java:60) ~[spring-data-jdbc-2.1.6.jar:2.1.6]

Table definition for SQLite:

create table aggregate
(
    id   text primary key,
    data text not null
);

For some reason Spring Data JDBC tries to set an id of type integer in the aggregate although it's a) of another type and b) already there. I experimented with a different IdGenerator, using without rowid in the table definiton but nothing changed.

I'm using Spring Data JDBC 2.1.6 and xerial/sqlite-jdbc 3.34.0.

How can I fix this?


Update to answer Jens Schauder's question: I forgot to mention the callback that sets the UUID appropriately. I also have two converters to translate between JsonNode and PGobject (not shown here).

@Component
public class AggregateCallback implements BeforeConvertCallback<Aggregate> {

  @Override
  public Aggregate onBeforeConvert(final Aggregate aggregate) {
    if (aggregate.getId() == null) {
      aggregate.setId(UUID.randomUUID());
    }
    return aggregate;
  }
}

Regardless of the database the AggregateCallback is called, but with SQLite the exception is thrown after the execution of the callback.

tamm0r
  • 179
  • 1
  • 2
  • 12
  • How are you setting the UUID? What do you mean by `IdGenerator`? That is not a concept known in Spring Data JDBC. As posted this shouldn't work with Postgres or any other database since there is nothing generating the id and Spring Data JDBC checks that the id is set after a save operation. – Jens Schauder Mar 23 '21 at 12:42
  • @JensSchauder, I added the relevant parts to my question. With `IdGenerator` I meant an IdGenerator that returns true in my custom dialect. – tamm0r Mar 23 '21 at 15:05
  • Which version are you running? This might be fixed in 2.2 M5 (2021.0.0) by https://github.com/spring-projects/spring-data-jdbc/pull/939 If not, do you have a simple github repository, I can look at? – Jens Schauder Mar 23 '21 at 15:23
  • 1
    I'm currently at 2.1.6 and will try said version. If the problem persists I'll prepare a demonstrator. – tamm0r Mar 23 '21 at 16:07
  • So, as i understood, your problem is when you get the record from database it try to assign an integer value to your UUID right? – Montaser Sobaih Mar 23 '21 at 16:18
  • @MontaserSobaih, no it's when I try to save the record. The callback which properly fills the UUID is called as expected, but afterwards Spring Data JDBC still tries to set an integer-based id value (it always tries to set the value `1` which then leads to the exception). You can see it in the stacktrace... `populateIdsIfNecessary()`... `setIdAndCascadingProperties`... – tamm0r Mar 23 '21 at 19:08

2 Answers2

1

Switching to Spring Data 2021.0.0-M5 as suggested by Jens Schauder in the comments solved the problem!

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
tamm0r
  • 179
  • 1
  • 2
  • 12
1

As @tammOr answered using a release after Spring Data 2021.0.0-M5 fixes the problem. Here is the explanation why and how.

When Spring Data JDBC saves the aggregate it does the following in the old version:

  1. It determines if the aggregate is new. There are various ways how it might do that, but the case that applies here is to check the id, if it is empty (null for object types or 0 for numeric primitives.

  2. Since the id is null it decides the aggregate is new and an INSERT is necessary. Before performing that it triggers some events which @tammOr uses to set the id.

  3. It then performs the Insert

  4. Since the default strategy is to generate the id in the database, it tries to obtain the generated id from the JDBC driver after the insert. For some reason the SQLite driver actually returns a value for that, of type Integer.

  5. Spring Data JDBC then tries to convert that to an UUID and fails.

With the later version Spring Data JDBC realises it already has an ID in step 4 and does not ask the driver for a generated one, and skips step 5, so everything is happy.

This is the pull request that solved the problem: https://github.com/spring-projects/spring-data-jdbc/pull/939

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348