1
1
/*
2
- * Copyright 2013-2014 the original author or authors.
2
+ * Copyright 2013-2016 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
26
26
import org .springframework .data .mongodb .core .spel .ExpressionTransformationContextSupport ;
27
27
import org .springframework .data .mongodb .core .spel .LiteralNode ;
28
28
import org .springframework .data .mongodb .core .spel .MethodReferenceNode ;
29
+ import org .springframework .data .mongodb .core .spel .MethodReferenceNode .AggregationMethodReference ;
30
+ import org .springframework .data .mongodb .core .spel .MethodReferenceNode .AggregationMethodReference .ArgumentType ;
31
+ import org .springframework .data .mongodb .core .spel .NotOperatorNode ;
29
32
import org .springframework .data .mongodb .core .spel .OperatorNode ;
30
33
import org .springframework .expression .spel .ExpressionState ;
31
34
import org .springframework .expression .spel .SpelNode ;
32
35
import org .springframework .expression .spel .SpelParserConfiguration ;
33
36
import org .springframework .expression .spel .ast .CompoundExpression ;
37
+ import org .springframework .expression .spel .ast .ConstructorReference ;
34
38
import org .springframework .expression .spel .ast .Indexer ;
35
39
import org .springframework .expression .spel .ast .InlineList ;
40
+ import org .springframework .expression .spel .ast .InlineMap ;
41
+ import org .springframework .expression .spel .ast .OperatorNot ;
36
42
import org .springframework .expression .spel .ast .PropertyOrFieldReference ;
37
43
import org .springframework .expression .spel .standard .SpelExpression ;
38
44
import org .springframework .expression .spel .standard .SpelExpressionParser ;
39
45
import org .springframework .expression .spel .support .StandardEvaluationContext ;
40
46
import org .springframework .util .Assert ;
41
47
import org .springframework .util .NumberUtils ;
48
+ import org .springframework .util .ObjectUtils ;
42
49
43
50
import com .mongodb .BasicDBList ;
44
51
import com .mongodb .BasicDBObject ;
48
55
* Renders the AST of a SpEL expression as a MongoDB Aggregation Framework projection expression.
49
56
*
50
57
* @author Thomas Darimont
58
+ * @author Christoph Strobl
51
59
*/
52
60
class SpelExpressionTransformer implements AggregationExpressionTransformer {
53
61
@@ -69,6 +77,8 @@ public SpelExpressionTransformer() {
69
77
conversions .add (new PropertyOrFieldReferenceNodeConversion (this ));
70
78
conversions .add (new CompoundExpressionNodeConversion (this ));
71
79
conversions .add (new MethodReferenceNodeConversion (this ));
80
+ conversions .add (new NotOperatorNodeConversion (this ));
81
+ conversions .add (new ValueRetrievingNodeConversion (this ));
72
82
73
83
this .conversions = Collections .unmodifiableList (conversions );
74
84
}
@@ -131,8 +141,8 @@ private ExpressionNodeConversion<ExpressionNode> lookupConversionFor(ExpressionN
131
141
* @author Thomas Darimont
132
142
* @author Oliver Gierke
133
143
*/
134
- private static abstract class ExpressionNodeConversion <T extends ExpressionNode > implements
135
- AggregationExpressionTransformer {
144
+ private static abstract class ExpressionNodeConversion <T extends ExpressionNode >
145
+ implements AggregationExpressionTransformer {
136
146
137
147
private final AggregationExpressionTransformer transformer ;
138
148
private final Class <? extends ExpressionNode > nodeType ;
@@ -235,8 +245,17 @@ public OperatorNodeConversion(AggregationExpressionTransformer transformer) {
235
245
protected Object convert (AggregationExpressionTransformationContext <OperatorNode > context ) {
236
246
237
247
OperatorNode currentNode = context .getCurrentNode ();
238
-
239
248
DBObject operationObject = createOperationObjectAndAddToPreviousArgumentsIfNecessary (context , currentNode );
249
+
250
+ if (currentNode .isLogicalOperator ()) {
251
+
252
+ for (ExpressionNode expressionNode : currentNode ) {
253
+ transform (expressionNode , currentNode , operationObject , context );
254
+ }
255
+
256
+ return operationObject ;
257
+ }
258
+
240
259
Object leftResult = transform (currentNode .getLeft (), currentNode , operationObject , context );
241
260
242
261
if (currentNode .isUnaryMinus ()) {
@@ -271,7 +290,8 @@ private DBObject createOperationObjectAndAddToPreviousArgumentsIfNecessary(
271
290
return nextDbObject ;
272
291
}
273
292
274
- private Object convertUnaryMinusOp (ExpressionTransformationContextSupport <OperatorNode > context , Object leftResult ) {
293
+ private Object convertUnaryMinusOp (ExpressionTransformationContextSupport <OperatorNode > context ,
294
+ Object leftResult ) {
275
295
276
296
Object result = leftResult instanceof Number ? leftResult
277
297
: new BasicDBObject ("$multiply" , dbList (-1 , leftResult ));
@@ -289,7 +309,7 @@ private Object convertUnaryMinusOp(ExpressionTransformationContextSupport<Operat
289
309
*/
290
310
@ Override
291
311
protected boolean supports (ExpressionNode node ) {
292
- return node .isMathematicalOperation ();
312
+ return node .isMathematicalOperation () || node . isLogicalOperator () ;
293
313
}
294
314
}
295
315
@@ -462,13 +482,31 @@ public MethodReferenceNodeConversion(AggregationExpressionTransformer transforme
462
482
protected Object convert (AggregationExpressionTransformationContext <MethodReferenceNode > context ) {
463
483
464
484
MethodReferenceNode node = context .getCurrentNode ();
465
- List < Object > args = new ArrayList < Object > ();
485
+ AggregationMethodReference methodReference = node . getMethodReference ();
466
486
467
- for (ExpressionNode childNode : node ) {
468
- args .add (transform (childNode , context ));
487
+ Object args = null ;
488
+
489
+ if (ObjectUtils .nullSafeEquals (methodReference .getArgumentType (), ArgumentType .SINGLE )) {
490
+ args = transform (node .getChild (0 ), context );
491
+ } else if (ObjectUtils .nullSafeEquals (methodReference .getArgumentType (), ArgumentType .MAP )) {
492
+
493
+ DBObject dbo = new BasicDBObject ();
494
+ for (int i = 0 ; i < methodReference .getArgumentMap ().length ; i ++) {
495
+ dbo .put (methodReference .getArgumentMap ()[i ], transform (node .getChild (i ), context ));
496
+ }
497
+ args = dbo ;
498
+ } else {
499
+
500
+ List <Object > argList = new ArrayList <Object >();
501
+
502
+ for (ExpressionNode childNode : node ) {
503
+ argList .add (transform (childNode , context ));
504
+ }
505
+
506
+ args = dbList (argList .toArray ());
469
507
}
470
508
471
- return context .addToPreviousOrReturn (new BasicDBObject (node . getMethodName (), dbList ( args . toArray ()) ));
509
+ return context .addToPreviousOrReturn (new BasicDBObject (methodReference . getMongoOperator (), args ));
472
510
}
473
511
}
474
512
@@ -510,4 +548,81 @@ protected boolean supports(ExpressionNode node) {
510
548
return node .isOfType (CompoundExpression .class );
511
549
}
512
550
}
551
+
552
+ /**
553
+ * @author Christoph Strobl
554
+ * @since 1.10
555
+ */
556
+ static class NotOperatorNodeConversion extends ExpressionNodeConversion <NotOperatorNode > {
557
+
558
+ /**
559
+ * Creates a new {@link ExpressionNodeConversion}.
560
+ *
561
+ * @param transformer must not be {@literal null}.
562
+ */
563
+ public NotOperatorNodeConversion (AggregationExpressionTransformer transformer ) {
564
+ super (transformer );
565
+ }
566
+
567
+ /*
568
+ * (non-Javadoc)
569
+ * @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
570
+ */
571
+ @ Override
572
+ protected Object convert (AggregationExpressionTransformationContext <NotOperatorNode > context ) {
573
+
574
+ NotOperatorNode node = context .getCurrentNode ();
575
+ List <Object > args = new ArrayList <Object >();
576
+
577
+ for (ExpressionNode childNode : node ) {
578
+ args .add (transform (childNode , context ));
579
+ }
580
+
581
+ return context .addToPreviousOrReturn (new BasicDBObject (node .getMongoOperator (), dbList (args .toArray ())));
582
+ }
583
+
584
+ /*
585
+ * (non-Javadoc)
586
+ * @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
587
+ */
588
+ @ Override
589
+ protected boolean supports (ExpressionNode node ) {
590
+ return node .isOfType (OperatorNot .class );
591
+ }
592
+ }
593
+
594
+ /**
595
+ * @author Christoph Strobl
596
+ * @since 1.10
597
+ */
598
+ static class ValueRetrievingNodeConversion extends ExpressionNodeConversion <ExpressionNode > {
599
+
600
+ /**
601
+ * Creates a new {@link ExpressionNodeConversion}.
602
+ *
603
+ * @param transformer must not be {@literal null}.
604
+ */
605
+ public ValueRetrievingNodeConversion (AggregationExpressionTransformer transformer ) {
606
+ super (transformer );
607
+ }
608
+
609
+ /*
610
+ * (non-Javadoc)
611
+ * @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
612
+ */
613
+ @ Override
614
+ protected Object convert (AggregationExpressionTransformationContext <ExpressionNode > context ) {
615
+ return context .getCurrentNode ().getValue ();
616
+ }
617
+
618
+ /*
619
+ * (non-Javadoc)
620
+ * @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
621
+ */
622
+ @ Override
623
+ protected boolean supports (ExpressionNode node ) {
624
+ return node .isOfType (InlineMap .class ) || node .isOfType (InlineList .class )
625
+ || node .isOfType (ConstructorReference .class );
626
+ }
627
+ }
513
628
}
0 commit comments