diff --git a/spring-session-core/src/main/java/org/springframework/session/CreateWithIdSessionRepository.java b/spring-session-core/src/main/java/org/springframework/session/CreateWithIdSessionRepository.java
new file mode 100644
index 000000000..995ee07c0
--- /dev/null
+++ b/spring-session-core/src/main/java/org/springframework/session/CreateWithIdSessionRepository.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.session;
+
+import org.springframework.lang.Nullable;
+
+/**
+ * Extends a basic {@link SessionRepository} to allow creating session with specific id.
+ *
+ * @param the type of Session being managed by this
+ * {@link CreateWithIdSessionRepository}
+ * @author Jakub Maciej
+ */
+public interface CreateWithIdSessionRepository extends SessionRepository {
+
+ /**
+ * Creates a new {@link Session} that is capable of being persisted by this
+ * {@link SessionRepository}.
+ *
+ *
+ * This allows optimizations and customizations in how the {@link Session} is
+ * persisted. For example, the implementation returned might keep track of the changes
+ * ensuring that only the delta needs to be persisted on a save.
+ *
+ * @param id a desired session id, if id is null - it will be generated by underlying
+ * implementation
+ * @return a new {@link Session} that is capable of being persisted by this
+ * {@link SessionRepository}
+ */
+ S createSession(@Nullable String id);
+
+}
diff --git a/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java b/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java
index 46442683e..b01ef2429 100644
--- a/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java
+++ b/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java
@@ -21,6 +21,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import org.apache.commons.logging.Log;
@@ -36,6 +37,7 @@
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.session.CreateWithIdSessionRepository;
import org.springframework.session.DelegatingIndexResolver;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.FlushMode;
@@ -244,10 +246,12 @@
*
* @author Rob Winch
* @author Vedran Pavic
+ * @author Jakub Maciej
* @since 2.2.0
*/
public class RedisIndexedSessionRepository
- implements FindByIndexNameSessionRepository, MessageListener {
+ implements FindByIndexNameSessionRepository,
+ CreateWithIdSessionRepository, MessageListener {
private static final Log logger = LogFactory.getLog(RedisIndexedSessionRepository.class);
@@ -489,7 +493,12 @@ public void deleteById(String sessionId) {
@Override
public RedisSession createSession() {
- MapSession cached = new MapSession();
+ return createSession(null);
+ }
+
+ @Override
+ public RedisSession createSession(final String id) {
+ MapSession cached = Optional.ofNullable(id).map(MapSession::new).orElse(new MapSession());
if (this.defaultMaxInactiveInterval != null) {
cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
}
diff --git a/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java b/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java
index 658c8a456..3c1f555b3 100644
--- a/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java
+++ b/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java
@@ -162,6 +162,19 @@ void createSessionCustomMaxInactiveInterval() {
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(interval));
}
+ @Test
+ void createSessionWithSpecificId() {
+ final String desiredSessionId = "desiredId";
+ Session session = this.redisRepository.createSession(desiredSessionId);
+ assertThat(session.getId()).isEqualTo(desiredSessionId);
+ }
+
+ @Test
+ void createSessionWithIdEqualNull() {
+ Session session = this.redisRepository.createSession(null);
+ assertThat(session.getId()).isNotNull();
+ }
+
@Test
void saveNewSession() {
RedisSession session = this.redisRepository.createSession();
diff --git a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepository.java b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepository.java
index 4de118c64..04bf80b73 100644
--- a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepository.java
+++ b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepository.java
@@ -22,6 +22,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -39,6 +40,7 @@
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.session.CreateWithIdSessionRepository;
import org.springframework.session.DelegatingIndexResolver;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.FlushMode;
@@ -108,10 +110,12 @@
* @author Tommy Ludwig
* @author Mark Anderson
* @author Aleksandar Stojsavljevic
+ * @author Jakub Maciej
* @since 2.2.0
*/
public class HazelcastIndexedSessionRepository
implements FindByIndexNameSessionRepository,
+ CreateWithIdSessionRepository,
EntryAddedListener, EntryEvictedListener,
EntryRemovedListener {
@@ -234,7 +238,12 @@ public void setSaveMode(SaveMode saveMode) {
@Override
public HazelcastSession createSession() {
- MapSession cached = new MapSession();
+ return createSession(null);
+ }
+
+ @Override
+ public HazelcastSession createSession(final String id) {
+ MapSession cached = Optional.ofNullable(id).map(MapSession::new).orElse(new MapSession());
if (this.defaultMaxInactiveInterval != null) {
cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
}
diff --git a/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepositoryTests.java b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepositoryTests.java
index f648bfe58..f7463dc8e 100644
--- a/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepositoryTests.java
+++ b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepositoryTests.java
@@ -115,6 +115,27 @@ void createSessionCustomMaxInactiveInterval() {
verifyZeroInteractions(this.sessions);
}
+ @Test
+ void createSessionWithSpecificId() {
+ verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean());
+
+ final String desiredSessionId = "desiredId";
+ HazelcastSession session = this.repository.createSession(desiredSessionId);
+
+ assertThat(session.getId()).isEqualTo(desiredSessionId);
+ verifyZeroInteractions(this.sessions);
+ }
+
+ @Test
+ void createSessionWithIdEqualNull() {
+ verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean());
+
+ HazelcastSession session = this.repository.createSession(null);
+
+ assertThat(session.getId()).isNotNull();
+ verifyZeroInteractions(this.sessions);
+ }
+
@Test
void saveNewFlushModeOnSave() {
verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean());
diff --git a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcIndexedSessionRepository.java b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcIndexedSessionRepository.java
index ea6f2efd0..41b7eeec1 100644
--- a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcIndexedSessionRepository.java
+++ b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcIndexedSessionRepository.java
@@ -26,6 +26,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
@@ -45,6 +46,7 @@
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.LobHandler;
+import org.springframework.session.CreateWithIdSessionRepository;
import org.springframework.session.DelegatingIndexResolver;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.FlushMode;
@@ -125,10 +127,12 @@
*
* @author Vedran Pavic
* @author Craig Andrews
+ * @author Jakub Maciej
* @since 2.2.0
*/
public class JdbcIndexedSessionRepository
- implements FindByIndexNameSessionRepository {
+ implements FindByIndexNameSessionRepository,
+ CreateWithIdSessionRepository {
/**
* The default name of database table used by Spring Session to store sessions.
@@ -395,7 +399,12 @@ public void setSaveMode(SaveMode saveMode) {
@Override
public JdbcSession createSession() {
- MapSession delegate = new MapSession();
+ return createSession(null);
+ }
+
+ @Override
+ public JdbcSession createSession(final String id) {
+ MapSession delegate = Optional.ofNullable(id).map(MapSession::new).orElse(new MapSession());
if (this.defaultMaxInactiveInterval != null) {
delegate.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval));
}
diff --git a/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/JdbcIndexedSessionRepositoryTests.java b/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/JdbcIndexedSessionRepositoryTests.java
index aed37e535..da3268699 100644
--- a/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/JdbcIndexedSessionRepositoryTests.java
+++ b/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/JdbcIndexedSessionRepositoryTests.java
@@ -267,6 +267,23 @@ void createSessionImmediateFlushMode() {
verifyNoMoreInteractions(this.jdbcOperations);
}
+ @Test
+ void createSessionWithSpecificId() {
+ final String desiredSessionId = "desiredId";
+ JdbcSession session = this.repository.createSession(desiredSessionId);
+ assertThat(session.isNew()).isTrue();
+ assertThat(session.getId()).isEqualTo(desiredSessionId);
+ verifyNoMoreInteractions(this.jdbcOperations);
+ }
+
+ @Test
+ void createSessionWithIdEqualNull() {
+ JdbcSession session = this.repository.createSession(null);
+ assertThat(session.isNew()).isTrue();
+ assertThat(session.getId()).isNotNull();
+ verifyNoMoreInteractions(this.jdbcOperations);
+ }
+
@Test
void saveNewWithoutAttributes() {
JdbcSession session = this.repository.createSession();