Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relation 1:N assumes foreign key is numeric during read conversion #1727

Open
razubuddy opened this issue Jan 28, 2024 · 5 comments
Open

Relation 1:N assumes foreign key is numeric during read conversion #1727

razubuddy opened this issue Jan 28, 2024 · 5 comments
Assignees
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged

Comments

@razubuddy
Copy link

razubuddy commented Jan 28, 2024

I have simple 1:N relation

record Product(@Id String id, String name, Set<Part> parts, @Version Integer version) {}
record Part(@Id Integer id, String name) {}
interface ProductRepository extends CrudRepository<Product, String> {}

Postgres schema looks like:

create table if not exists product (
    id character varying(32) not null primary key,
    name character varying(255) not null,
    version int not null
);

create table if not exists part (
    id integer not null primary key,
    product character varying(32) not null references product(id),
    name character varying(255) not null
);

Test code:

var p1 = repository.save(new Product("P1", "product 1", Set.of(new Part(1, "part 1")), null));
var p2 = repository.save(new Product("P2", "product 2", Set.of(new Part(2, "part 2"), new Part(3, "part 3")), null));
System.out.println(p1);
System.out.println(p2);
System.out.println(repository.findAll());

Writing part works, but while reading from database it assumes foreign key product should be numeric:

org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value [P1]
        at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:182) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter.getPotentiallyConvertedSimpleRead(MappingRelationalConverter.java:665) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter$DefaultConversionContext.convert(MappingRelationalConverter.java:837) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter$ConversionContext.convert(MappingRelationalConverter.java:943) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.core.convert.MappingJdbcConverter$ResolvingConversionContext.convert(MappingJdbcConverter.java:451) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter$DocumentValueProvider.getPropertyValue(MappingRelationalConverter.java:1107) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter$DocumentValueProvider.getPropertyValue(MappingRelationalConverter.java:1066) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.core.convert.MappingJdbcConverter$ResolvingRelationalPropertyValueProvider.potentiallyAppendIdentifier(MappingJdbcConverter.java:342) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.core.convert.MappingJdbcConverter$ResolvingRelationalPropertyValueProvider.<init>(MappingJdbcConverter.java:329) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.core.convert.MappingJdbcConverter.newValueProvider(MappingJdbcConverter.java:299) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter$2.withContext(MappingRelationalConverter.java:498) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter$2.getPropertyValue(MappingRelationalConverter.java:486) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter$2.getPropertyValue(MappingRelationalConverter.java:474) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:71) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter$ConvertingParameterValueProvider.getParameterValue(MappingRelationalConverter.java:1173) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:49) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.extractInvocationArguments(ClassGeneratingEntityInstantiator.java:301) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:273) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:98) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:453) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:348) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:311) ~[spring-data-relational-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.core.convert.MappingJdbcConverter.readAndResolve(MappingJdbcConverter.java:287) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.core.convert.JdbcConverter.readAndResolve(JdbcConverter.java:106) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.core.convert.EntityRowMapper.mapRow(EntityRowMapper.java:82) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:804) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:218) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:230) ~[spring-jdbc-6.1.3.jar:6.1.3]
        at org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy.findAll(DefaultDataAccessStrategy.java:276) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.core.JdbcAggregateTemplate.findAll(JdbcAggregateTemplate.java:341) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findAll(SimpleJdbcRepository.java:89) ~[spring-data-jdbc-3.2.2.jar:3.2.2]
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351) ~[spring-aop-6.1.3.jar:6.1.3]
        at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:277) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.3.jar:6.1.3]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143) ~[spring-data-commons-3.2.2.jar:3.2.2]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.3.jar:6.1.3]
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-6.1.3.jar:6.1.3]
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385) ~[spring-tx-6.1.3.jar:6.1.3]
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-6.1.3.jar:6.1.3]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.3.jar:6.1.3]
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-6.1.3.jar:6.1.3]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.3.jar:6.1.3]
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-6.1.3.jar:6.1.3]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.3.jar:6.1.3]
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:220) ~[spring-aop-6.1.3.jar:6.1.3]
        at com.example.datajdbc.$Proxy61.findAll(Unknown Source) ~[na:na]
        at com.example.datajdbc.DatajdbcApplication.lambda$applicationRunner$0(DatajdbcApplication.java:23) ~[main/:na]
        at org.springframework.boot.SpringApplication.lambda$callRunner$4(SpringApplication.java:786) ~[spring-boot-3.2.2.jar:3.2.2]
        at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:83) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:88) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-3.2.2.jar:3.2.2]
        at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:786) ~[spring-boot-3.2.2.jar:3.2.2]
        at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:774) ~[spring-boot-3.2.2.jar:3.2.2]
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:na]
        at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) ~[na:na]
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
        at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:na]
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:na]
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
        at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
        at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) ~[spring-boot-3.2.2.jar:3.2.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:341) ~[spring-boot-3.2.2.jar:3.2.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[spring-boot-3.2.2.jar:3.2.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-3.2.2.jar:3.2.2]
        at com.example.datajdbc.DatajdbcApplication.main(DatajdbcApplication.java:28) ~[main/:na]
Caused by: java.lang.NumberFormatException: For input string: "P1"
        at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) ~[na:na]
        at java.base/java.lang.Integer.parseInt(Integer.java:662) ~[na:na]
        at java.base/java.lang.Integer.valueOf(Integer.java:989) ~[na:na]
        at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:203) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.core.convert.support.StringToNumberConverterFactory$StringToNumber.convert(StringToNumberConverterFactory.java:64) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.core.convert.support.StringToNumberConverterFactory$StringToNumber.convert(StringToNumberConverterFactory.java:50) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.core.convert.support.GenericConversionService$ConverterFactoryAdapter.convert(GenericConversionService.java:409) ~[spring-core-6.1.3.jar:6.1.3]
        at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41) ~[spring-core-6.1.3.jar:6.1.3]
@razubuddy
Copy link
Author

I attach simple project to reproduce
datajdbc.tar.gz

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 28, 2024
@charliemidtlyng
Copy link

Similar to this, i think:
#1684

@schauder
Copy link
Contributor

schauder commented Jun 7, 2024

Please check if this issue is still present in the lates 3.2.x or 3.3.x releases.
It looks very much like a duplicate of #1684 as @charliemidtlyng pointed out.

@schauder schauder added the status: waiting-for-feedback We need additional information before we can continue label Jun 7, 2024
@charliemidtlyng
Copy link

I think there's still an issue with relations;
A -> B[] -> C -> D[]

C.D[] is always empty on fetch. I'll try to make an integration test the next days.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jun 8, 2024
@charliemidtlyng
Copy link

I think there's still an issue with relations; A -> B[] -> C -> D[]

C.D[] is always empty on fetch. I'll try to make an integration test the next days.

After local testing it looks like #1810 fixes my issue mentioned above.

I'm pretty sure 3.3.x and 3.2.6 fixes this issue reported by @razubuddy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

No branches or pull requests

4 participants