Skip to content

Support adapting both query and parameters in JDBC SessionRepository #2454

Open
@runeflobakk

Description

@runeflobakk

Expected Behavior

Wish for JdbcIndexedSessionRepository:
Customize both the queries and how parameters are set on the PreparedStatement.

Current Behavior

Only the query strings are customizable by their respective setter-method (e.g. setCreateSessionQuery(String)), while populating the PreparedStatement with parameters specified by the query is fixed, e.g. inside JdbcSession.save().

While this certainly enables customizing the queries to use applicable per-database specific features, the queries themselves are implicitly tied to the parameters and their order, and may not offer the desired flexibility to adapt the SQL queries executed by the JdbcIndexedSessionRepository.

Context

I have the need to being able to invalidate/delete a session on-demand, but identified by another key than what is the SESSION_ID. The session identifier typically is assigned by another system to provide SSO, and this SSO system may request my application, which uses Spring Session, to remove a session.

Currently I work around this by using a separate table for this alternative session identifier, with reference to spring_session.session_id, and on session invalidate request, delete the applicable row in this auxillary table, resolve the Spring Session ID, and invoke SessionRepository.deleteById. This works, but I need to also maintain a separate mechanism for TTL and expiry of the rows in my auxillary session table.

It would be nice if I could just include this separate candidate key in the table schema for spring_session, and rely on the expiry mechanism and other mechanisms already present in Spring Session.

Implementation

The idea is to couple the query and how the PreparedStatement is populated, and this would enable me to adapt which and how columns are populated when creating/updating a session. My idea is to put the auxillary session identifier on the jakarta.servlet.http.HttpSession. This will of course store the identifier as a regular attribute in spring_session_attributes (which is all fine), but it also enables me to customize the JdbcIndexedSessionRepository to be aware of this particular session attribute, and include it as a value for the particular column where I want to store it. Of course I would need to adapt any DDL for spring_session to include this column, applicable index, etc. PostgreSqlJdbcIndexedSessionRepositoryAdaptedQueriesITests demonstrates this, where the spring_session table is altered to include a new custom column CANDIDATE_ID, and instead of using the existing setCreateSessionQuery, a new method adaptCreateSessionQuery is proposed to set both the query and customizing the PreparedStatement using a ParameterizedPreparedStatementSetter.

Contribution proposal

I have implemented a proposed solution to this in a fork, which I'd like to suggest as an general approach to support this use-case, and of course also to change according to any feedback if this can be regarded as a candidate for contribution to Spring Session.

The main changes can be seen in JdbcIndexedSessionRepository, where I, as a PoC, have changed the existing private CREATE_SESSION_QUERY and UPDATE_SESSION_QUERY to "bundles" with both the query, and PreparedStaement populating logic, as well as retrofitting their existing use. And the accompanying new methods to configure this using adaptCreateSessionQuery, adaptUpdateSessionQuery.

If this is regarded as an interesting contribution, I will of course make the implementation complete for all the queries, as well as any changes necessary to the code.

Can this proposal be an applicable contribution to Spring Session?
Thank you!

New API

This demonstrates the API I have in mind:

Setting the query string, and an additional parameter without affecting the existing parameters

sessionRepository.adaptCreateSessionQuery(query -> query
    .replaceQuery("INSERT INTO %TABLE_NAME% ( .. ) VALUES (?, ?, ... ?)")
    .setAdditionalParams((ps, session) -> ps.setString(8, session.getAttribute("my_custom_key"))))

Setting both the query string, and how all parameters are set

sessionRepository.adaptCreateSessionQuery(query -> new QueryAndParams(
    "INSERT INTO %TABLE_NAME% ( .. ) VALUES (?, ?, ... ?)",
    (ps, session) -> {
            ps.setString(1, JdbcSession.this.primaryKey);
            // the other "standard" spring_session columns
            ps.setString(8, session.getAttribute("my_custom_key")));
        })
)

Where session being a JdbcSession. This is of course also possible to adapt if it is considered to not fit into existing paradigms of the Spring Session API.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions