1717
1818import com .fasterxml .jackson .databind .JsonNode ;
1919import com .fasterxml .jackson .databind .node .ArrayNode ;
20- import io .serverlessworkflow .impl .ContextAware ;
2120import io .serverlessworkflow .impl .TaskContext ;
2221import io .serverlessworkflow .impl .WorkflowContext ;
2322import 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 ;
3123import java .util .function .Supplier ;
3224import net .thisptr .jackson .jq .Output ;
3325import net .thisptr .jackson .jq .Scope ;
3426import net .thisptr .jackson .jq .Version ;
3527import net .thisptr .jackson .jq .exception .JsonQueryException ;
3628import 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 ;
4229
4330public class JQExpression implements Expression {
4431
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-
5132 private final Supplier <Scope > scope ;
5233 private final String expr ;
5334
5435 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- }
6536
6637 public JQExpression (Supplier <Scope > scope , String expr , Version version )
6738 throws JsonQueryException {
6839 this .expr = expr ;
6940 this .scope = scope ;
7041 this .internalExpr = compile (version );
71- checkFunctionCall (internalExpr );
7242 }
7343
7444 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 );
9846 }
9947
10048 private interface TypedOutput <T > extends Output {
10149 T getResult ();
10250 }
10351
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-
15552 private static class JsonNodeOutput implements TypedOutput <JsonNode > {
15653
15754 private JsonNode result ;
@@ -179,7 +76,7 @@ public JsonNode getResult() {
17976
18077 @ Override
18178 public JsonNode eval (WorkflowContext workflow , TaskContext <?> task , JsonNode node ) {
182- TypedOutput <JsonNode > output = output ( JsonNode . class );
79+ TypedOutput <JsonNode > output = new JsonNodeOutput ( );
18380 try {
18481 internalExpr .apply (createScope (workflow , task ), node , output );
18582 return output .getResult ();
@@ -190,74 +87,8 @@ public JsonNode eval(WorkflowContext workflow, TaskContext<?> task, JsonNode nod
19087 }
19188
19289 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 )));
19992 return childScope ;
20093 }
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- }
26394}
0 commit comments