Skip to content

Adopt to changed Hibernate behavior returning domain types using tuple queries #2815

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

Closed
markusheiden opened this issue Feb 22, 2023 · 3 comments
Assignees
Labels
type: enhancement A general enhancement

Comments

@markusheiden
Copy link

markusheiden commented Feb 22, 2023

Interface-based projections fail: When calling getId() on the objects returned by the query method, null is returned (-> exception below) though in the database there is an ID set. When using the JPA entity as the return type of the repository method, it works.

The code worked with Spring Boot 2.6 and fails since 2.7+.

public interface IdOnly { long getId(); }

@SequenceGenerator(name = "seq_local_account", sequenceName = "seq_local_account", allocationSize = 1)
@Entity
@Table(name = "local_account")
public class LocalAccount {
    @Id
    @Column(name = "id", nullable = false)
    @GeneratedValue(strategy = SEQUENCE, generator = "seq_local_account")
    private long id;

    @ElementCollection
    @Fetch(SUBSELECT)
    @CollectionTable(name = "local_account_downloaded", joinColumns = @JoinColumn(name = "account_id", nullable = false))
    @Column(name = "month", nullable = false)
    private Set<YearMonth> downloaded = new HashSet<>();

    public long getId() {
        return id;
    }
}

public interface LocalAccountRepository extends Repository<LocalAccount, Long> {
    @Query("FROM LocalAccount WHERE :month NOT MEMBER OF downloaded")
    // Using List<LocalAccount> as return type here make it work.
    List<IdOnly> findAllByNotInDownloaded(YearMonth month);
}

@Converter(autoApply = true)
public class YearMonthConverter implements AttributeConverter<YearMonth, Integer> {
    @Override
    public Integer convertToDatabaseColumn(YearMonth entity) {
        return entity.getYear() * 100 + entity.getMonth().getValue();
    }
   @Override
    public YearMonth convertToEntityAttribute(Integer database) {
        return YearMonth.of(database / 100, database % 100);
    }
}

Stacktrace:

Caused by: org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public abstract long com.adsoul.voluminator.crawler.local.IdOnly.getId()
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:232)
	at jdk.proxy4/jdk.proxy4.$Proxy166.getId(Unknown Source)
        ...
@gregturn
Copy link
Contributor

@markusheiden Can you clarify what happens if you switch from long (primitive) to Long (object type)? (Is that a possible option to at least test out on your end?)

@gregturn gregturn added status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Feb 27, 2023
@markusheiden
Copy link
Author

markusheiden commented Mar 1, 2023

If using Longs instead, the IDs returned from IdOnly::getId are always null (though they are set in the database) and thus lead to failures in the subsequent code which expect the IDs to be present.

@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 Mar 1, 2023
@mp911de mp911de added type: enhancement A general enhancement and removed status: feedback-provided Feedback has been provided labels Apr 12, 2023
@mp911de mp911de changed the title Interface-based projections fail Adopt to changed Hibernate behavior returning domain types using tuple queries Apr 12, 2023
@mp911de
Copy link
Member

mp911de commented Apr 12, 2023

Newer Hibernate versions return Tuple and TupleElement with a value of the domain type instead of a map of tuples. This causes our projection infrastructure to use the wrong input and that renders a null value accessing the Id. As this is an adoption to a changed Hibernate feature, we're going to backport this enhancement to the 3.0.x development line.

mp911de added a commit that referenced this issue Apr 12, 2023
…e queries.

We now allow using the domain type when it is returned from a tuple query. This allows projections if the return value is not a Map.

Closes #2815
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants