25
25
import org .springframework .data .mapping .model .SimpleTypeHolder ;
26
26
import org .springframework .data .relational .core .mapping .Embedded .OnEmpty ;
27
27
import org .springframework .data .relational .core .sql .SqlIdentifier ;
28
+ import org .springframework .data .spel .EvaluationContextProvider ;
28
29
import org .springframework .data .util .Lazy ;
29
30
import org .springframework .data .util .Optionals ;
31
+ import org .springframework .expression .Expression ;
32
+ import org .springframework .expression .ParserContext ;
33
+ import org .springframework .expression .common .LiteralExpression ;
34
+ import org .springframework .expression .spel .standard .SpelExpressionParser ;
35
+ import org .springframework .lang .Nullable ;
30
36
import org .springframework .util .Assert ;
31
37
import org .springframework .util .StringUtils ;
32
38
33
39
/**
34
- * Meta data about a property to be used by repository implementations .
40
+ * SQL-specific {@link org.springframework. data.mapping.PersistentProperty} implementation .
35
41
*
36
42
* @author Jens Schauder
37
43
* @author Greg Turnquist
42
48
public class BasicRelationalPersistentProperty extends AnnotationBasedPersistentProperty <RelationalPersistentProperty >
43
49
implements RelationalPersistentProperty {
44
50
51
+ private static final SpelExpressionParser PARSER = new SpelExpressionParser ();
52
+
45
53
private final Lazy <SqlIdentifier > columnName ;
54
+ private final @ Nullable Expression columnNameExpression ;
46
55
private final Lazy <Optional <SqlIdentifier >> collectionIdColumnName ;
47
56
private final Lazy <SqlIdentifier > collectionKeyColumnName ;
48
- private final Lazy < Boolean > isEmbedded ;
49
- private final Lazy < String > embeddedPrefix ;
57
+ private final boolean isEmbedded ;
58
+ private final String embeddedPrefix ;
50
59
private final NamingStrategy namingStrategy ;
51
60
private boolean forceQuote = true ;
52
- private SpelExpressionProcessor spelExpressionProcessor = new SpelExpressionProcessor ( );
61
+ private ExpressionEvaluator spelExpressionProcessor = new ExpressionEvaluator ( EvaluationContextProvider . DEFAULT );
53
62
54
63
/**
55
64
* Creates a new {@link BasicRelationalPersistentProperty}.
@@ -84,19 +93,26 @@ public BasicRelationalPersistentProperty(Property property, PersistentEntity<?,
84
93
85
94
Assert .notNull (namingStrategy , "NamingStrategy must not be null" );
86
95
87
- this .isEmbedded = Lazy . of (() -> Optional . ofNullable ( findAnnotation ( Embedded .class )). isPresent () );
96
+ this .isEmbedded = isAnnotationPresent ( Embedded .class );
88
97
89
- this .embeddedPrefix = Lazy . of (() -> Optional .ofNullable (findAnnotation (Embedded .class )) //
98
+ this .embeddedPrefix = Optional .ofNullable (findAnnotation (Embedded .class )) //
90
99
.map (Embedded ::prefix ) //
91
- .orElse ("" )) ;
100
+ .orElse ("" );
92
101
93
- this .columnName = Lazy .of (() -> Optional .ofNullable (findAnnotation (Column .class )) //
94
- .map (Column ::value ) //
95
- .map (spelExpressionProcessor ::applySpelExpression ) //
96
- .filter (StringUtils ::hasText ) //
97
- .map (this ::createSqlIdentifier ) //
98
- .orElseGet (() -> createDerivedSqlIdentifier (namingStrategy .getColumnName (this ))));
102
+ if (isAnnotationPresent (Column .class )) {
103
+
104
+ Column column = getRequiredAnnotation (Column .class );
105
+
106
+ columnName = Lazy .of (() -> StringUtils .hasText (column .value ()) ? createSqlIdentifier (column .value ())
107
+ : createDerivedSqlIdentifier (namingStrategy .getColumnName (this )));
108
+ columnNameExpression = detectExpression (column .value ());
99
109
110
+ } else {
111
+ columnName = Lazy .of (() -> createDerivedSqlIdentifier (namingStrategy .getColumnName (this )));
112
+ columnNameExpression = null ;
113
+ }
114
+
115
+ // TODO: support expressions for MappedCollection
100
116
this .collectionIdColumnName = Lazy .of (() -> Optionals
101
117
.toStream (Optional .ofNullable (findAnnotation (MappedCollection .class )) //
102
118
.map (MappedCollection ::idColumn ), //
@@ -112,14 +128,29 @@ public BasicRelationalPersistentProperty(Property property, PersistentEntity<?,
112
128
.map (this ::createSqlIdentifier ) //
113
129
.orElseGet (() -> createDerivedSqlIdentifier (namingStrategy .getKeyColumn (this ))));
114
130
}
115
- public SpelExpressionProcessor getSpelExpressionProcessor () {
116
- return spelExpressionProcessor ;
117
- }
118
131
119
- public void setSpelExpressionProcessor (SpelExpressionProcessor spelExpressionProcessor ) {
132
+ void setSpelExpressionProcessor (ExpressionEvaluator spelExpressionProcessor ) {
120
133
this .spelExpressionProcessor = spelExpressionProcessor ;
121
134
}
122
135
136
+ /**
137
+ * Returns a SpEL {@link Expression} if the given {@link String} is actually an expression that does not evaluate to a
138
+ * {@link LiteralExpression} (indicating that no subsequent evaluation is necessary).
139
+ *
140
+ * @param potentialExpression can be {@literal null}
141
+ * @return can be {@literal null}.
142
+ */
143
+ @ Nullable
144
+ private static Expression detectExpression (@ Nullable String potentialExpression ) {
145
+
146
+ if (!StringUtils .hasText (potentialExpression )) {
147
+ return null ;
148
+ }
149
+
150
+ Expression expression = PARSER .parseExpression (potentialExpression , ParserContext .TEMPLATE_EXPRESSION );
151
+ return expression instanceof LiteralExpression ? null : expression ;
152
+ }
153
+
123
154
private SqlIdentifier createSqlIdentifier (String name ) {
124
155
return isForceQuote () ? SqlIdentifier .quoted (name ) : SqlIdentifier .unquoted (name );
125
156
}
@@ -148,7 +179,12 @@ public boolean isEntity() {
148
179
149
180
@ Override
150
181
public SqlIdentifier getColumnName () {
151
- return columnName .get ();
182
+
183
+ if (columnNameExpression == null ) {
184
+ return columnName .get ();
185
+ }
186
+
187
+ return createSqlIdentifier (spelExpressionProcessor .evaluate (columnNameExpression ));
152
188
}
153
189
154
190
@ Override
@@ -193,12 +229,12 @@ public boolean isOrdered() {
193
229
194
230
@ Override
195
231
public boolean isEmbedded () {
196
- return isEmbedded . get () ;
232
+ return isEmbedded ;
197
233
}
198
234
199
235
@ Override
200
236
public String getEmbeddedPrefix () {
201
- return isEmbedded () ? embeddedPrefix . get () : null ;
237
+ return isEmbedded () ? embeddedPrefix : null ;
202
238
}
203
239
204
240
@ Override
0 commit comments