17
17
18
18
import com .fasterxml .jackson .databind .JsonNode ;
19
19
import com .fasterxml .jackson .databind .node .ArrayNode ;
20
- import io .serverlessworkflow .impl .ContextAware ;
21
20
import io .serverlessworkflow .impl .TaskContext ;
22
21
import io .serverlessworkflow .impl .WorkflowContext ;
23
22
import io .serverlessworkflow .impl .json .JsonUtils ;
24
- import java .lang .reflect .Field ;
25
- import java .util .ArrayList ;
26
- import java .util .Collection ;
27
- import java .util .HashSet ;
28
- import java .util .Map ;
29
- import java .util .Optional ;
30
- import java .util .concurrent .ConcurrentHashMap ;
31
23
import java .util .function .Supplier ;
32
24
import net .thisptr .jackson .jq .Output ;
33
25
import net .thisptr .jackson .jq .Scope ;
34
26
import net .thisptr .jackson .jq .Version ;
35
27
import net .thisptr .jackson .jq .exception .JsonQueryException ;
36
28
import net .thisptr .jackson .jq .internal .javacc .ExpressionParser ;
37
- import net .thisptr .jackson .jq .internal .tree .FunctionCall ;
38
- import net .thisptr .jackson .jq .internal .tree .StringInterpolation ;
39
- import net .thisptr .jackson .jq .internal .tree .binaryop .BinaryOperatorExpression ;
40
- import org .slf4j .Logger ;
41
- import org .slf4j .LoggerFactory ;
42
29
43
30
public class JQExpression implements Expression {
44
31
45
- private static final Logger logger = LoggerFactory .getLogger (JQExpression .class );
46
- private final Map <Class <? extends net .thisptr .jackson .jq .Expression >, Collection <Field >>
47
- declaredFieldsMap = new ConcurrentHashMap <>();
48
- private final Map <Class <? extends net .thisptr .jackson .jq .Expression >, Collection <Field >>
49
- allFieldsMap = new ConcurrentHashMap <>();
50
-
51
32
private final Supplier <Scope > scope ;
52
33
private final String expr ;
53
34
54
35
private net .thisptr .jackson .jq .Expression internalExpr ;
55
- private static Field rhsField ;
56
-
57
- static {
58
- try {
59
- rhsField = BinaryOperatorExpression .class .getDeclaredField ("rhs" );
60
- rhsField .setAccessible (true );
61
- } catch (ReflectiveOperationException e ) {
62
- logger .warn ("Unexpected exception while resolving rhs field" , e );
63
- }
64
- }
65
36
66
37
public JQExpression (Supplier <Scope > scope , String expr , Version version )
67
38
throws JsonQueryException {
68
39
this .expr = expr ;
69
40
this .scope = scope ;
70
41
this .internalExpr = compile (version );
71
- checkFunctionCall (internalExpr );
72
42
}
73
43
74
44
private net .thisptr .jackson .jq .Expression compile (Version version ) throws JsonQueryException {
75
- net .thisptr .jackson .jq .Expression expression ;
76
- try {
77
- expression = ExpressionParser .compile (expr , version );
78
- } catch (JsonQueryException ex ) {
79
- expression = handleStringInterpolation (version ).orElseThrow (() -> ex );
80
- }
81
- checkFunctionCall (expression );
82
- return expression ;
83
- }
84
-
85
- private Optional <net .thisptr .jackson .jq .Expression > handleStringInterpolation (Version version ) {
86
- if (!expr .startsWith ("\" " )) {
87
- try {
88
- net .thisptr .jackson .jq .Expression expression =
89
- ExpressionParser .compile ("\" " + expr + "\" " , version );
90
- if (expression instanceof StringInterpolation ) {
91
- return Optional .of (expression );
92
- }
93
- } catch (JsonQueryException ex ) {
94
- // ignoring it
95
- }
96
- }
97
- return Optional .empty ();
45
+ return ExpressionParser .compile (expr , version );
98
46
}
99
47
100
48
private interface TypedOutput <T > extends Output {
101
49
T getResult ();
102
50
}
103
51
104
- @ SuppressWarnings ("unchecked" )
105
- private <T > TypedOutput <T > output (Class <T > returnClass ) {
106
- TypedOutput <T > out ;
107
- if (String .class .isAssignableFrom (returnClass )) {
108
- out = (TypedOutput <T >) new StringOutput ();
109
- } else if (Collection .class .isAssignableFrom (returnClass )) {
110
- out = (TypedOutput <T >) new CollectionOutput ();
111
- } else {
112
- out = (TypedOutput <T >) new JsonNodeOutput ();
113
- }
114
- return out ;
115
- }
116
-
117
- private static class StringOutput implements TypedOutput <String > {
118
- StringBuilder sb = new StringBuilder ();
119
-
120
- @ Override
121
- public void emit (JsonNode out ) throws JsonQueryException {
122
- if (sb .length () > 0 ) {
123
- sb .append (' ' );
124
- }
125
- if (!out .isNull () && out .asText () != null ) {
126
- sb .append (out .asText ());
127
- }
128
- }
129
-
130
- @ Override
131
- public String getResult () {
132
- return sb .toString ();
133
- }
134
- }
135
-
136
- private static class CollectionOutput implements TypedOutput <Collection <Object >> {
137
- Collection <Object > result = new ArrayList <>();
138
-
139
- @ SuppressWarnings ("unchecked" )
140
- @ Override
141
- public void emit (JsonNode out ) throws JsonQueryException {
142
- Object obj = JsonUtils .toJavaValue (out );
143
- if (obj instanceof Collection ) result .addAll ((Collection <Object >) obj );
144
- else {
145
- result .add (obj );
146
- }
147
- }
148
-
149
- @ Override
150
- public Collection <Object > getResult () {
151
- return result ;
152
- }
153
- }
154
-
155
52
private static class JsonNodeOutput implements TypedOutput <JsonNode > {
156
53
157
54
private JsonNode result ;
@@ -179,7 +76,7 @@ public JsonNode getResult() {
179
76
180
77
@ Override
181
78
public JsonNode eval (WorkflowContext workflow , TaskContext <?> task , JsonNode node ) {
182
- TypedOutput <JsonNode > output = output ( JsonNode . class );
79
+ TypedOutput <JsonNode > output = new JsonNodeOutput ( );
183
80
try {
184
81
internalExpr .apply (createScope (workflow , task ), node , output );
185
82
return output .getResult ();
@@ -190,74 +87,8 @@ public JsonNode eval(WorkflowContext workflow, TaskContext<?> task, JsonNode nod
190
87
}
191
88
192
89
private Scope createScope (WorkflowContext workflow , TaskContext <?> task ) {
193
- return createScope (scope .get (), task );
194
- }
195
-
196
- private Scope createScope (Scope parentScope , ContextAware context ) {
197
- Scope childScope = Scope .newChildScope (parentScope );
198
- context .variables ().forEach ((k , v ) -> childScope .setValue (k , JsonUtils .fromValue (v )));
90
+ Scope childScope = Scope .newChildScope (scope .get ());
91
+ task .variables ().forEach ((k , v ) -> childScope .setValue (k , JsonUtils .fromValue (v )));
199
92
return childScope ;
200
93
}
201
-
202
- private void checkFunctionCall (net .thisptr .jackson .jq .Expression toCheck )
203
- throws JsonQueryException {
204
- if (toCheck instanceof FunctionCall ) {
205
- toCheck .apply (scope .get (), JsonUtils .mapper ().createObjectNode (), out -> {});
206
- } else if (toCheck instanceof BinaryOperatorExpression ) {
207
- if (rhsField != null ) {
208
- try {
209
- checkFunctionCall ((net .thisptr .jackson .jq .Expression ) rhsField .get (toCheck ));
210
- } catch (ReflectiveOperationException e ) {
211
- logger .warn (
212
- "Ignoring unexpected error {} while accesing field {} for class{} and expression {}" ,
213
- e .getMessage (),
214
- rhsField .getName (),
215
- toCheck .getClass (),
216
- expr );
217
- }
218
- }
219
- } else if (toCheck != null ) {
220
- for (Field f : getAllExprFields (toCheck ))
221
- try {
222
- checkFunctionCall ((net .thisptr .jackson .jq .Expression ) f .get (toCheck ));
223
- } catch (ReflectiveOperationException e ) {
224
- logger .warn (
225
- "Ignoring unexpected error {} while accesing field {} for class{} and expression {}" ,
226
- e .getMessage (),
227
- f .getName (),
228
- toCheck .getClass (),
229
- expr );
230
- }
231
- }
232
- }
233
-
234
- private Collection <Field > getAllExprFields (net .thisptr .jackson .jq .Expression toCheck ) {
235
- return allFieldsMap .computeIfAbsent (toCheck .getClass (), this ::getAllExprFields );
236
- }
237
-
238
- private Collection <Field > getAllExprFields (
239
- Class <? extends net .thisptr .jackson .jq .Expression > clazz ) {
240
- Collection <Field > fields = new HashSet <>();
241
- Class <?> currentClass = clazz ;
242
- do {
243
- fields .addAll (
244
- declaredFieldsMap .computeIfAbsent (
245
- currentClass .asSubclass (net .thisptr .jackson .jq .Expression .class ),
246
- this ::getDeclaredExprFields ));
247
- currentClass = currentClass .getSuperclass ();
248
- } while (net .thisptr .jackson .jq .Expression .class .isAssignableFrom (currentClass ));
249
- return fields ;
250
- }
251
-
252
- private Collection <Field > getDeclaredExprFields (
253
- Class <? extends net .thisptr .jackson .jq .Expression > clazz ) {
254
- Collection <Field > fields = new HashSet <>();
255
- for (Field f : clazz .getDeclaredFields ()) {
256
- if (net .thisptr .jackson .jq .Expression .class .isAssignableFrom (f .getType ())) {
257
- f .setAccessible (true );
258
- fields .add (f );
259
- }
260
- }
261
- return fields ;
262
- }
263
94
}
0 commit comments