spring-projects / spring-data-relational

Spring Data Relational. Home of Spring Data JDBC and Spring Data R2DBC.
https://spring.io/projects/spring-data-jdbc
Apache License 2.0
753 stars 345 forks source link

`R2dbcEntityTemplate` fails to instantiate interface using fluent `as(…)` projection #1690

Closed shuaqiu closed 9 months ago

shuaqiu commented 9 months ago

I have define a query as

    public Mono<IMember> findById(final String id) {
        final Query query = Query
            .query(CriteriaBuilder.buildIdQuery(id));
        return entityTemplate.select(MemberBo.class)
            .from(TABLE__MEMBER)
            .as(IMember.class)
            .matching(query)
            .first();
    }

while IMember is the super interface of MemberBo.

The query can correctly run at version 3.1.5 of spring-data-r2dbc, but throws exception after upgrade to version 3.2.0

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.member.api.bean.IMember]: Specified class is an interface
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:137) ~[spring-beans-6.1.1.jar:6.1.1]
    at org.springframework.data.mapping.model.ReflectionEntityInstantiator.instantiateClass(ReflectionEntityInstantiator.java:139) ~[spring-data-commons-3.2.0.jar:3.2.0]
    at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:57) ~[spring-data-commons-3.2.0.jar:3.2.0]
    at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:98) ~[spring-data-commons-3.2.0.jar:3.2.0]
    at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:454) ~[spring-data-relational-3.2.0.jar:3.2.0]
    at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:348) ~[spring-data-relational-3.2.0.jar:3.2.0]
    at org.springframework.data.relational.core.conversion.MappingRelationalConverter.readAggregate(MappingRelationalConverter.java:311) ~[spring-data-relational-3.2.0.jar:3.2.0]
    at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:298) ~[spring-data-relational-3.2.0.jar:3.2.0]
    at org.springframework.data.relational.core.conversion.MappingRelationalConverter.read(MappingRelationalConverter.java:294) ~[spring-data-relational-3.2.0.jar:3.2.0]
    at org.springframework.data.r2dbc.core.R2dbcEntityTemplate.lambda$getRowsFetchSpec$13(R2dbcEntityTemplate.java:795) ~[spring-data-r2dbc-3.2.0.jar:3.2.0]
    at io.r2dbc.proxy.callback.ResultCallbackHandler.lambda$invoke$0(ResultCallbackHandler.java:92) ~[r2dbc-proxy-1.1.2.RELEASE.jar:1.1.2.RELEASE]
    at io.asyncer.r2dbc.mysql.MySqlResult.lambda$map$1(MySqlResult.java:87) ~[r2dbc-mysql-1.0.5.jar:1.0.5]
    at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:179) ~[reactor-core-3.6.0.jar:3.6.0]
    at reactor.core.publisher.FluxHandleFuseable$HandleFuseableConditionalSubscriber.onNext(FluxHandleFuseable.java:505) ~[reactor-core-3.6.0.jar:3.6.0]
    at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.6.0.jar:3.6.0]
mp911de commented 9 months ago

Care to upgrade to Spring Data Relational/R2DBC 3.2.1-SNAPSHOT for both artifacts and retest?

I'm not able to reproduce the issue without further details.

Please provide a minimal yet complete sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

shuaqiu commented 9 months ago

r2dbc-test.zip

I extract a test project. You can run the unit test at MemberRepoTest.java to reproduct the problem.

Care to upgrade to Spring Data Relational/R2DBC 3.2.1-SNAPSHOT for both artifacts and retest?

I'm not able to reproduce the issue without further details.

Please provide a minimal yet complete sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

mp911de commented 9 months ago

Thanks a lot. The difference is that your entity implements the interface and effectively it isn't a projection.

shuaqiu commented 9 months ago

Now I have an another question.

For my use case, I should use .as(IMember.class) method as above, or use .map(Function.identity()) as

    public Mono<IMember> findById(final String id) {
        final Query query = Query
            .query(CriteriaBuilder.buildIdQuery(id));
        return entityTemplate.select(MemberBo.class)
            .from(TABLE__MEMBER)
            .matching(query)
            .first()
            .map(Function.identity());
    }