15
15
*/
16
16
package org .springframework .data .redis .support .collections ;
17
17
18
+ import java .util .function .Supplier ;
19
+
18
20
import org .springframework .beans .factory .BeanNameAware ;
19
21
import org .springframework .beans .factory .InitializingBean ;
20
22
import org .springframework .beans .factory .SmartFactoryBean ;
21
23
import org .springframework .data .redis .connection .DataType ;
24
+ import org .springframework .data .redis .core .RedisOperations ;
22
25
import org .springframework .data .redis .core .RedisTemplate ;
23
26
import org .springframework .data .util .Lazy ;
24
27
import org .springframework .lang .Nullable ;
27
30
28
31
/**
29
32
* Factory bean that facilitates creation of Redis-based collections. Supports list, set, zset (or sortedSet), map (or
30
- * hash) and properties. Will use the key type if it exists or to create a dedicated collection (Properties vs Map).
31
- * Otherwise uses the provided type (default is list) .
33
+ * hash) and properties. Uses the key and {@link CollectionType} to determine what collection type to use. The factory
34
+ * verifies the key type if a {@link CollectionType} is specified. Defaults to {@link CollectionType#LIST} .
32
35
*
33
36
* @author Costin Leau
34
37
* @author Christoph Strobl
38
+ * @author Mark Paluch
39
+ * @see RedisStore
35
40
*/
36
41
public class RedisCollectionFactoryBean implements SmartFactoryBean <RedisStore >, BeanNameAware , InitializingBean {
37
42
38
43
/**
39
44
* Collection types supported by this factory.
40
45
*
41
46
* @author Costin Leau
47
+ * @author Mark Paluch
42
48
*/
43
49
public enum CollectionType {
44
50
LIST {
45
51
52
+ @ Override
46
53
public DataType dataType () {
47
54
return DataType .LIST ;
48
55
}
49
56
},
50
57
SET {
51
58
59
+ @ Override
52
60
public DataType dataType () {
53
61
return DataType .SET ;
54
62
}
55
63
},
56
64
ZSET {
57
65
66
+ @ Override
58
67
public DataType dataType () {
59
68
return DataType .ZSET ;
60
69
}
61
70
},
62
71
MAP {
63
72
73
+ @ Override
64
74
public DataType dataType () {
65
75
return DataType .HASH ;
66
76
}
67
77
},
68
78
PROPERTIES {
69
79
80
+ @ Override
70
81
public DataType dataType () {
71
82
return DataType .HASH ;
72
83
}
73
84
};
74
85
75
86
abstract DataType dataType ();
87
+
88
+ /**
89
+ * Attempt to find a {@link CollectionType} by {@link DataType}. Defaults to {@link Supplier ifNotFound} when
90
+ * {@code dataType} is {@literal null} or the collection type cannot be determined.
91
+ *
92
+ * @param dataType the {@link DataType} to look up.
93
+ * @param ifNotFound supplier for a default value.
94
+ * @since 3.2
95
+ */
96
+ static CollectionType findCollectionType (@ Nullable DataType dataType , Supplier <CollectionType > ifNotFound ) {
97
+
98
+ for (CollectionType collectionType : values ()) {
99
+ if (collectionType .dataType () == dataType ) {
100
+ return collectionType ;
101
+ }
102
+ }
103
+
104
+ return ifNotFound .get ();
105
+ }
76
106
}
77
107
78
- private @ Nullable Lazy <RedisStore > store ;
79
- private @ Nullable CollectionType type = null ;
108
+ private @ Nullable CollectionType type ;
80
109
private @ Nullable RedisTemplate <String , ?> template ;
81
110
private @ Nullable String key ;
82
111
private @ Nullable String beanName ;
83
112
113
+ private @ Nullable Lazy <RedisStore > store ;
114
+
84
115
@ Override
85
116
public void afterPropertiesSet () {
86
117
@@ -93,46 +124,40 @@ public void afterPropertiesSet() {
93
124
94
125
store = Lazy .of (() -> {
95
126
96
- DataType dt = template .type (key );
127
+ DataType keyType = template .type (key );
97
128
98
129
// can't create store
99
- Assert .isTrue (!DataType .STRING .equals (dt ), "Cannot create store on keys of type 'string '" );
130
+ Assert .isTrue (!DataType .STREAM .equals (keyType ), "Cannot create store on keys of type 'STREAM '" );
100
131
101
- RedisStore tmp = createStore (dt );
132
+ if (this .type == null ) {
133
+ this .type = CollectionType .findCollectionType (keyType , () -> CollectionType .LIST );
134
+ }
102
135
103
- if (tmp == null ) {
104
- if (type == null ) {
105
- type = CollectionType .LIST ;
106
- }
107
- tmp = createStore (type .dataType ());
136
+ if (keyType != null && DataType .NONE != keyType && this .type .dataType () != keyType ) {
137
+ throw new IllegalArgumentException (
138
+ String .format ("Cannot create collection type '%s' for a key containing '%s'" , this .type , keyType ));
108
139
}
109
- return tmp ;
140
+
141
+ return createStore (this .type , key , template );
110
142
});
111
143
}
112
144
113
- @ SuppressWarnings ("unchecked" )
114
- private RedisStore createStore (DataType dt ) {
115
- switch (dt ) {
116
- case LIST :
117
- return RedisList .create (key , template );
118
-
119
- case SET :
120
- return new DefaultRedisSet (key , template );
121
-
122
- case ZSET :
123
- return RedisZSet .create (key , template );
145
+ private RedisStore createStore (CollectionType collectionType , String key , RedisOperations <String , ?> operations ) {
124
146
125
- case HASH :
126
- if ( CollectionType . PROPERTIES . equals ( type )) {
127
- return new RedisProperties (key , template );
128
- }
129
- return new DefaultRedisMap (key , template );
130
- }
131
- return null ;
147
+ return switch ( collectionType ) {
148
+ case LIST -> RedisList . create ( key , operations );
149
+ case SET -> new DefaultRedisSet <> (key , operations );
150
+ case ZSET -> RedisZSet . create ( key , operations );
151
+ case PROPERTIES -> new RedisProperties (key , operations );
152
+ case MAP -> new DefaultRedisMap <>( key , operations );
153
+ } ;
132
154
}
133
155
134
156
@ Override
135
157
public RedisStore getObject () {
158
+
159
+ Assert .state (store != null ,
160
+ "RedisCollectionFactoryBean is not initialized. Ensure to initialize this factory by calling afterPropertiesSet() before obtaining the factory object." );
136
161
return store .get ();
137
162
}
138
163
0 commit comments