Description
When using Persistable
with a record class in an R2DBC Data Repository, I found that the record does not work properly with the @Transient
annotation.
Here is a sample code:
@Table("sample")
@Builder
public record SampleRecord(
@Id
UUID id,
@Transient
boolean isNew
) implements Persistable<UUID> {
@Override
public UUID getId() {
return id;
}
@Override
public boolean isNew() {
return isNew;
}
}
public interface SampleRecordRepository extends R2dbcRepository<SampleRecord, UUID> {
}
And the test code:
@SpringBootTest
class Simpler2dbcPersistableExampleApplicationTests {
@Autowired
SampleRecordRepository sampleRecordRepository;
@Test
void recordTest() {
UUID sampleId = UUID.randomUUID();
SampleRecord sample = SampleRecord.builder()
.id(sampleId)
.isNew(true)
.build();
sampleRecordRepository.save(sample)
.then(sampleRecordRepository.findById(sampleId))
.block();
}
}
Running this test produces the following error:
No property isNew found on entity class com.sem.simpler2dbcpersistableexample.Sample to bind constructor parameter to
org.springframework.data.mapping.MappingException: No property isNew found on entity class com.sem.simpler2dbcpersistableexample.Sample to bind constructor parameter to
at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:69)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter$ConvertingParameterValueProvider.getParameterValue(MappingRelationalConverter.java:1244)
at org.springframework.data.mapping.model.ValueExpressionParameterValueProvider.getParameterValue(ValueExpressionParameterValueProvider.java:56)
at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.extractInvocationArguments(ClassGeneratingEntityInstantiator.java:301)
at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:273)
at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:98)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:462)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:357)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:320)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:307)
at org.springframework.data.relational.core.conversion.MappingRelationalConverter.project(MappingRelationalConverter.java:197)
at
...
After debugging the issue, I found that when creating the entity without using the default constructor, no additional actions are performed, such as injecting null values or default values, into fields annotated with @Transient
.
Therefore, this issue does not occur only with records, but also with classes that only have a constructor that takes a field annotated with @Transient
as an argument.
The issue can be reproduced at https://github.com/seminchoi/r2dbc-transient-issue
If this is supported, I believe it could be useful with compact constructor of Record.
So, I was wondering if this behavior is intentional or if not, there are any plans to support it.
Additionally, I would like to know if I can contribute to fixing this issue. If so, could you provide me with some guidance on which packages or classes I should check and modify?