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.
22
22
import java .util .List ;
23
23
24
24
import org .springframework .core .GenericTypeResolver ;
25
+ import org .springframework .data .mongodb .core .spel .ConstructorReferenceNode ;
25
26
import org .springframework .data .mongodb .core .spel .ExpressionNode ;
26
27
import org .springframework .data .mongodb .core .spel .ExpressionTransformationContextSupport ;
28
+ import org .springframework .data .mongodb .core .spel .InlineListNode ;
29
+ import org .springframework .data .mongodb .core .spel .InlineMapNode ;
27
30
import org .springframework .data .mongodb .core .spel .LiteralNode ;
28
31
import org .springframework .data .mongodb .core .spel .MethodReferenceNode ;
32
+ import org .springframework .data .mongodb .core .spel .MethodReferenceNode .AggregationMethodReference ;
33
+ import org .springframework .data .mongodb .core .spel .NotOperatorNode ;
29
34
import org .springframework .data .mongodb .core .spel .OperatorNode ;
30
35
import org .springframework .expression .spel .ExpressionState ;
31
36
import org .springframework .expression .spel .SpelNode ;
32
37
import org .springframework .expression .spel .SpelParserConfiguration ;
33
38
import org .springframework .expression .spel .ast .CompoundExpression ;
34
39
import org .springframework .expression .spel .ast .Indexer ;
35
40
import org .springframework .expression .spel .ast .InlineList ;
41
+ import org .springframework .expression .spel .ast .InlineMap ;
42
+ import org .springframework .expression .spel .ast .OperatorNot ;
36
43
import org .springframework .expression .spel .ast .PropertyOrFieldReference ;
37
44
import org .springframework .expression .spel .standard .SpelExpression ;
38
45
import org .springframework .expression .spel .standard .SpelExpressionParser ;
39
46
import org .springframework .expression .spel .support .StandardEvaluationContext ;
40
47
import org .springframework .util .Assert ;
48
+ import org .springframework .util .ClassUtils ;
41
49
import org .springframework .util .NumberUtils ;
42
50
43
51
import com .mongodb .BasicDBList ;
44
52
import com .mongodb .BasicDBObject ;
45
53
import com .mongodb .DBObject ;
54
+ import org .springframework .util .ObjectUtils ;
46
55
47
56
/**
48
57
* Renders the AST of a SpEL expression as a MongoDB Aggregation Framework projection expression.
49
58
*
50
59
* @author Thomas Darimont
60
+ * @author Christoph Strobl
51
61
*/
52
62
class SpelExpressionTransformer implements AggregationExpressionTransformer {
53
63
@@ -69,6 +79,9 @@ public SpelExpressionTransformer() {
69
79
conversions .add (new PropertyOrFieldReferenceNodeConversion (this ));
70
80
conversions .add (new CompoundExpressionNodeConversion (this ));
71
81
conversions .add (new MethodReferenceNodeConversion (this ));
82
+ conversions .add (new NotOperatorrNodeConversion (this ));
83
+ conversions .add (new ConstructorReferenceNodeConversion (this ));
84
+ conversions .add (new ValueRetrievingNodeConversion (this ));
72
85
73
86
this .conversions = Collections .unmodifiableList (conversions );
74
87
}
@@ -131,8 +144,8 @@ private ExpressionNodeConversion<ExpressionNode> lookupConversionFor(ExpressionN
131
144
* @author Thomas Darimont
132
145
* @author Oliver Gierke
133
146
*/
134
- private static abstract class ExpressionNodeConversion <T extends ExpressionNode > implements
135
- AggregationExpressionTransformer {
147
+ private static abstract class ExpressionNodeConversion <T extends ExpressionNode >
148
+ implements AggregationExpressionTransformer {
136
149
137
150
private final AggregationExpressionTransformer transformer ;
138
151
private final Class <? extends ExpressionNode > nodeType ;
@@ -235,8 +248,17 @@ public OperatorNodeConversion(AggregationExpressionTransformer transformer) {
235
248
protected Object convert (AggregationExpressionTransformationContext <OperatorNode > context ) {
236
249
237
250
OperatorNode currentNode = context .getCurrentNode ();
238
-
239
251
DBObject operationObject = createOperationObjectAndAddToPreviousArgumentsIfNecessary (context , currentNode );
252
+
253
+ if (currentNode .isConjunctionOperator ()) {
254
+
255
+ for (ExpressionNode expressionNode : currentNode ) {
256
+ transform (expressionNode , currentNode , operationObject , context );
257
+ }
258
+
259
+ return operationObject ;
260
+ }
261
+
240
262
Object leftResult = transform (currentNode .getLeft (), currentNode , operationObject , context );
241
263
242
264
if (currentNode .isUnaryMinus ()) {
@@ -271,7 +293,8 @@ private DBObject createOperationObjectAndAddToPreviousArgumentsIfNecessary(
271
293
return nextDbObject ;
272
294
}
273
295
274
- private Object convertUnaryMinusOp (ExpressionTransformationContextSupport <OperatorNode > context , Object leftResult ) {
296
+ private Object convertUnaryMinusOp (ExpressionTransformationContextSupport <OperatorNode > context ,
297
+ Object leftResult ) {
275
298
276
299
Object result = leftResult instanceof Number ? leftResult
277
300
: new BasicDBObject ("$multiply" , dbList (-1 , leftResult ));
@@ -289,7 +312,7 @@ private Object convertUnaryMinusOp(ExpressionTransformationContextSupport<Operat
289
312
*/
290
313
@ Override
291
314
protected boolean supports (ExpressionNode node ) {
292
- return node .isMathematicalOperation ();
315
+ return node .isMathematicalOperation () || node . isConjunctionOperator () ;
293
316
}
294
317
}
295
318
@@ -462,13 +485,31 @@ public MethodReferenceNodeConversion(AggregationExpressionTransformer transforme
462
485
protected Object convert (AggregationExpressionTransformationContext <MethodReferenceNode > context ) {
463
486
464
487
MethodReferenceNode node = context .getCurrentNode ();
465
- List < Object > args = new ArrayList < Object > ();
488
+ AggregationMethodReference methodReference = node . getMethodReference ();
466
489
467
- for (ExpressionNode childNode : node ) {
468
- args .add (transform (childNode , context ));
490
+ Object args = null ;
491
+
492
+ if (ObjectUtils .nullSafeEquals (methodReference .getArgumentType (), MethodReferenceNode .AggregationMethodReference .ArgumentType .SINGLE )) {
493
+ args = transform (node .getChild (0 ), context );
494
+ } else if (ObjectUtils .nullSafeEquals (methodReference .getArgumentType (), MethodReferenceNode .AggregationMethodReference .ArgumentType .MAPPED )) {
495
+
496
+ DBObject dbo = new BasicDBObject ();
497
+ for (int i = 0 ; i <methodReference .getArgumentMap ().length ; i ++) {
498
+ dbo .put (methodReference .getArgumentMap ()[i ], transform (node .getChild (i ), context ));
499
+ }
500
+ args = dbo ;
501
+ } else {
502
+
503
+ List <Object > argList = new ArrayList <Object >();
504
+
505
+ for (ExpressionNode childNode : node ) {
506
+ argList .add (transform (childNode , context ));
507
+ }
508
+
509
+ args = dbList (argList .toArray ());
469
510
}
470
511
471
- return context .addToPreviousOrReturn (new BasicDBObject (node .getMethodName (), dbList ( args . toArray ()) ));
512
+ return context .addToPreviousOrReturn (new BasicDBObject (node .getMethodName (), args ));
472
513
}
473
514
}
474
515
@@ -510,4 +551,106 @@ protected boolean supports(ExpressionNode node) {
510
551
return node .isOfType (CompoundExpression .class );
511
552
}
512
553
}
554
+
555
+ /**
556
+ * @author Christoph Strobl
557
+ * @since 1.10
558
+ */
559
+ static class NotOperatorrNodeConversion extends ExpressionNodeConversion <NotOperatorNode > {
560
+
561
+ /**
562
+ * Creates a new {@link ExpressionNodeConversion}.
563
+ *
564
+ * @param transformer must not be {@literal null}.
565
+ */
566
+ public NotOperatorrNodeConversion (AggregationExpressionTransformer transformer ) {
567
+ super (transformer );
568
+ }
569
+
570
+ /*
571
+ * (non-Javadoc)
572
+ * @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
573
+ */
574
+ @ Override
575
+ protected Object convert (AggregationExpressionTransformationContext <NotOperatorNode > context ) {
576
+
577
+ NotOperatorNode node = context .getCurrentNode ();
578
+ List <Object > args = new ArrayList <Object >();
579
+
580
+ for (ExpressionNode childNode : node ) {
581
+ args .add (transform (childNode , context ));
582
+ }
583
+
584
+ return context .addToPreviousOrReturn (new BasicDBObject (node .getMongoOperator (), dbList (args .toArray ())));
585
+ }
586
+
587
+ /*
588
+ * (non-Javadoc)
589
+ * @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
590
+ */
591
+ @ Override
592
+ protected boolean supports (ExpressionNode node ) {
593
+ return node .isOfType (OperatorNot .class );
594
+ }
595
+ }
596
+
597
+ /**
598
+ * @author Christoph Strobl
599
+ * @since 1.10
600
+ */
601
+ static class ConstructorReferenceNodeConversion extends ExpressionNodeConversion <ConstructorReferenceNode > {
602
+
603
+ /**
604
+ * Creates a new {@link ExpressionNodeConversion}.
605
+ *
606
+ * @param transformer must not be {@literal null}.
607
+ */
608
+ public ConstructorReferenceNodeConversion (AggregationExpressionTransformer transformer ) {
609
+ super (transformer );
610
+ }
611
+
612
+ /*
613
+ * (non-Javadoc)
614
+ * @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
615
+ */
616
+ @ Override
617
+ protected Object convert (AggregationExpressionTransformationContext <ConstructorReferenceNode > context ) {
618
+ return context .getCurrentNode ().getValue ();
619
+ }
620
+
621
+ /*
622
+ * (non-Javadoc)
623
+ * @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
624
+ */
625
+ @ Override
626
+ protected boolean supports (ExpressionNode node ) {
627
+ return ClassUtils .isAssignable (ConstructorReferenceNode .class , node .getClass ());
628
+ }
629
+ }
630
+
631
+ /**
632
+ * @author Christoph Strobl
633
+ * @since 1.10
634
+ */
635
+ static class ValueRetrievingNodeConversion extends ExpressionNodeConversion <ExpressionNode > {
636
+
637
+ /**
638
+ * Creates a new {@link ExpressionNodeConversion}.
639
+ *
640
+ * @param transformer must not be {@literal null}.
641
+ */
642
+ public ValueRetrievingNodeConversion (AggregationExpressionTransformer transformer ) {
643
+ super (transformer );
644
+ }
645
+
646
+ @ Override
647
+ protected Object convert (AggregationExpressionTransformationContext <ExpressionNode > context ) {
648
+ return context .getCurrentNode ().getValue ();
649
+ }
650
+
651
+ @ Override
652
+ protected boolean supports (ExpressionNode node ) {
653
+ return ClassUtils .isAssignable (InlineMapNode .class , node .getClass ()) || ClassUtils .isAssignable (InlineListNode .class , node .getClass ());
654
+ }
655
+ }
513
656
}
0 commit comments