Closed
Description
Hello,
I have an issue when attempting to persist a record.
The following is fine:
@Table("cat")
public record Cat(
@Id @Column("id") Long id,
@Column("name") String name) {
// Instead of using a constructor uses a factory method.
public static Cat of(String name) {
// The 'id' is auto-generated by the DB and populated on insert.
return new Cat(null, name);
}
}
But when I use another constructor instead of a factory method I get an exception. The code:
@Table("dog")
public record Dog(
@Id @Column("id") Long id,
@Column("name") String name) {
/**
* Convenience constructor which sets the id to null with the expectation that it will
* be populated when the entity is inserted into the DB (since it is an auto-incremented column).
*/
public Dog(String name) {
this(null, name);
}
}
Test which fails that I would except to pass:
@SpringBootTest
public class DogTest {
private static final Logger log = LoggerFactory.getLogger(DogTest.class);
@Autowired
private JdbcAggregateTemplate jdbcAggregateTemplate;
// THIS TEST FAILS CURRENTLY.
@Test
void animal_insertingIntoDb_succeeds() {
/* Given: A dog. */
var fido = new Dog("Fido");
/* When: We try to insert it in to the DB */
var insertedFido = jdbcAggregateTemplate.insert(fido);
/* Then: It should populate the ID field */
assertThat(insertedFido.id()).isNotNull();
}
}
And the exception:
Cannot set property id because no setter, wither or copy constructor exists for class com.example.demo.persistence.Dog!
java.lang.IllegalStateException: Cannot set property id because no setter, wither or copy constructor exists for class com.example.demo.persistence.Dog!
at org.springframework.data.mapping.model.InstantiationAwarePropertyAccessor.setProperty(InstantiationAwarePropertyAccessor.java:113)
at org.springframework.data.mapping.model.ConvertingPropertyAccessor.setProperty(ConvertingPropertyAccessor.java:64)
at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.setIdAndCascadingProperties(JdbcAggregateChangeExecutionContext.java:337)
at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.populateIdsIfNecessary(JdbcAggregateChangeExecutionContext.java:305)
at org.springframework.data.jdbc.core.AggregateChangeExecutor.execute(AggregateChangeExecutor.java:52)
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.store(JdbcAggregateTemplate.java:339)
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.insert(JdbcAggregateTemplate.java:167)
at com.example.demo.persistence.DogTest.animal_insertingIntoDb_succeeds(DogTest.java:26)
Attached is a repo you can run to reproduce the problem: spring-data-jdbc-records-bug.zip
Am I doing something wrong here (missing annotation/etc.) I would expect the framework to be able to pick up the correct constructor for the record but it currently does not.