Skip to content
New issue

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

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

Already on GitHub? # to your account

Dynamic projections for interfaces does not work #1813

Closed
mipo256 opened this issue Jun 10, 2024 · 8 comments
Closed

Dynamic projections for interfaces does not work #1813

mipo256 opened this issue Jun 10, 2024 · 8 comments
Labels
status: invalid An issue that we don't feel is valid

Comments

@mipo256
Copy link
Contributor

mipo256 commented Jun 10, 2024

I've created test in the playground repo to demonstrate the issue.

The fact is - currently, the JdbcQueryCreator.complete() fails to build a SELECT clause in case of interfaces to be used in dynamic projections. The stack trace is:

java.lang.IllegalStateException: SELECT does not declare a select list

	at org.springframework.data.relational.core.sql.SelectValidator.doValidate(SelectValidator.java:57)
	at org.springframework.data.relational.core.sql.SelectValidator.validate(SelectValidator.java:49)
	at org.springframework.data.relational.core.sql.DefaultSelectBuilder.build(DefaultSelectBuilder.java:202)
	at org.springframework.data.jdbc.repository.query.JdbcQueryCreator.complete(JdbcQueryCreator.java:182)
	at org.springframework.data.jdbc.repository.query.JdbcQueryCreator.complete(JdbcQueryCreator.java:66)
	at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:95)

That seems to happen only for dynamic projections, interface based projection on their own should be fine.

I think it's going to be great to add a support for this.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 10, 2024
@schauder schauder added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 11, 2024
@ngocnhan-tran1996
Copy link
Contributor

@schauder

This is a feature that will support interface based projection like below code?

interface MyEntityInterfaceProjection {

    String status();

    Long id();
}

@mipo256
Copy link
Contributor Author

mipo256 commented Sep 20, 2024

Not, exactly @ngocnhan-tran1996.

This issue target the dynamic projects more specifically, which can use interface of course as the target type. The interface based projections should work, though, as they are documented. You have any issues?

@ngocnhan-tran1996
Copy link
Contributor

@mipo256

correct me if I miss something.

I take a look your testcase and it doesn't work, but if I add get prefix, it works well.
So I'm confused about this part, this will be a feature that no need get prefix?

From document

The easiest way to limit the result of the queries to only the name attributes is by declaring an interface that exposes accessor methods for the properties to be read, as shown in the following example:

    @Test
    @Disabled // Enable to see what happens
    void whenDynamicProjectsAreInUseViaInterfaces_thenBlast() {
        saveInitialEntity();
        Optional<MyEntityInterfaceProjection> active = myEntityRepository.findProjectionByStatus("active", MyEntityInterfaceProjection.class);

        Assertions.assertThat(active)
            .isPresent()
            .hasValueSatisfying(myEntityProjection -> {
               Assertions.assertThat(myEntityProjection.id() != null && myEntityProjection.status().equalsIgnoreCase("active")).isTrue();
            });
    }

   // more code

    interface MyEntityInterfaceProjection {
        String status();  // add get prefix
        Long id(); // add get prefix
    }

@mipo256
Copy link
Contributor Author

mipo256 commented Sep 21, 2024

Yeah, it does indeed.
I think it would be great to resolve this as well @ngocnhan-tran1996
The error message itself actually is produced by SelectValidator because it just does not have any fields for selection. At the very least, the message should be corrected.

@schauder
Copy link
Contributor

As @ngocnhan-tran1996 correctly pointed out, the exception happens, because the interface doesn't have any getters.
This won't change.

But I took up your suggestion of a more explicit exception with the referenced PR.

schauder added a commit that referenced this issue Sep 24, 2024
@mp911de
Copy link
Member

mp911de commented Sep 24, 2024

I don't think catching an exception is the right approach. Instead, if the list of input properties is empty, then we should select everything. We had similar cases with projections that use @Value without adhering to the beans syntax.

In such a case, we expect that the underlying object is fully materialized so that projections can compute their own values.

@mp911de
Copy link
Member

mp911de commented Sep 25, 2024

FWIW, the same issue exists in JPA. With spring-projects/spring-data-commons#3164, I fixed the ProjectionInformation.isClosed() check. This implicitly fixes ReturnedType.needsCustomConstruction(). Maybe this is already sufficient to address the issue in Spring Data Relational.

@schauder
Copy link
Contributor

When I upgrade the provided example to use 3.4.0-SNAPSHOT the select gets executed as intended, with all columns selected.

The test fails later when the interface methods are used, because nothing is backing them. But that is to be expected.

I therefore close this ticket.

@mp911de mp911de added status: invalid An issue that we don't feel is valid and removed type: enhancement A general enhancement labels Sep 27, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
status: invalid An issue that we don't feel is valid
Projects
None yet
5 participants