View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jexl3.jexl342;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertNull;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.List;
28  import java.util.Optional;
29  import java.util.stream.Stream;
30  
31  import org.apache.commons.jexl3.JexlArithmetic;
32  import org.apache.commons.jexl3.JexlBuilder;
33  import org.apache.commons.jexl3.JexlContext;
34  import org.apache.commons.jexl3.JexlEngine;
35  import org.apache.commons.jexl3.JexlException;
36  import org.apache.commons.jexl3.JexlInfo;
37  import org.apache.commons.jexl3.JexlScript;
38  import org.apache.commons.jexl3.MapContext;
39  import org.apache.commons.jexl3.introspection.JexlUberspect;
40  import org.junit.jupiter.api.Test;
41  
42  class OptionalTest {
43  
44      public static class StreamContext extends MapContext {
45          public Stream map(final Collection<Object> c, final JexlScript s) {
46              final JexlContext context = JexlEngine.getThreadContext();
47              return c.stream().map(a->s.execute(context, a));
48          }
49          public Object reduce(final Stream<Object> stream, final JexlScript script) {
50              final Object reduced = stream.reduce((identity, element)->{
51                  final JexlContext context = JexlEngine.getThreadContext();
52                  return script.execute(context, identity, element);
53              });
54              return reduced instanceof Optional<?>
55                      ? ((Optional<?>) reduced).get()
56                      : reduced;
57          }
58      }
59  
60      public static class Thing {
61          String name;
62          public Optional<String> findName() {
63              return  Optional.ofNullable(name);
64          }
65  
66          public Optional<List<String>> findNames() {
67              if (name == null) {
68                  return Optional.empty();
69              }
70              return Optional.of(Collections.singletonList(name));
71          }
72      }
73  
74      @Test
75      void test342() {
76          final JexlBuilder builder = new JexlBuilder();
77          final JexlUberspect uber = builder.create().getUberspect();
78          final JexlEngine jexl = builder.uberspect(new ReferenceUberspect(uber)).safe(false).create();
79          final JexlInfo info = new JexlInfo("test352", 1, 1);
80          final Thing thing = new Thing();
81          JexlScript script1;
82  
83          script1 = jexl.createScript(info.at(53, 1),"thing.name.length()", "thing");
84          Object result = script1.execute(null, thing);
85          assertNull(result);
86  
87          thing.name = "foo";
88          result = script1.execute(null, thing);
89          assertEquals(3, result);
90  
91          final JexlScript script2 = jexl.createScript(info.at(62, 1), "thing.name.size()", "thing");
92          final JexlException.Method xmethod = assertThrows(JexlException.Method.class, () -> script2.execute(null, thing));
93          assertEquals("size", xmethod.getDetail());
94          assertEquals("test352@62:11 unsolvable function/method 'size'", xmethod.getMessage());
95          final JexlScript script3 = jexl.createScript(info.at(71, 1), "thing.name?.size()", "thing");
96          result = script3.execute(null, thing);
97  
98          thing.name = null;
99          script1 = jexl.createScript(info,"thing.names.size()", "thing");
100         result = script1.execute(null, thing);
101         assertNull(result);
102         thing.name = "froboz";
103         script1 = jexl.createScript(info,"thing.names", "thing");
104         result = script1.execute(null, thing);
105         assertNotNull(result);
106         script1 = jexl.createScript(info,"thing.names.size()", "thing");
107         result = script1.execute(null, thing);
108         assertEquals(1, result);
109     }
110 
111     @Test
112     void testOptionalArgs() {
113         final JexlBuilder builder = new JexlBuilder();
114         final JexlArithmetic jexla = new OptionalArithmetic(true);
115         final JexlUberspect uber = builder.create().getUberspect();
116         final JexlEngine jexl = builder.uberspect(new ReferenceUberspect(uber)).arithmetic(jexla).safe(false).create();
117         final JexlInfo info = new JexlInfo("testStream", 1, 1);
118         final MapContext context = new StreamContext();
119         final String src = "x + x";
120         final JexlScript script = jexl.createScript(src, "x");
121         final Optional<Integer> x = Optional.of(21);
122         final Object result = script.execute(context, x);
123         assertEquals(42, result);
124     }
125 
126     @Test
127     void testStream0() {
128         final String src = "$0.map(x -> x * x).reduce((a, x) -> a + x)";
129         final JexlBuilder builder = new JexlBuilder();
130         final JexlUberspect uber = builder.create().getUberspect();
131         final JexlArithmetic jexla = new OptionalArithmetic(true);
132         final JexlEngine jexl = builder.uberspect(new ReferenceUberspect(uber)).arithmetic(jexla).safe(false).create();
133         final JexlInfo info = new JexlInfo("testStream", 1, 1);
134         final MapContext context = new StreamContext();
135         final JexlScript script = jexl.createScript(src, "$0");
136         final Object result = script.execute(context, Arrays.asList(1, 2, 3));
137         assertEquals(14, result);
138     }
139 
140     @Test
141     void testStream1() {
142         final String src = "$0.map(x -> x * x).reduce((a, x) -> a + x)";
143         final JexlEngine jexl = new JexlBuilder().safe(false).create();
144         final JexlInfo info = new JexlInfo("testStream", 1, 1);
145         final MapContext context = new StreamContext();
146         final JexlScript script = jexl.createScript(src, "$0");
147         final Object result = script.execute(context, Arrays.asList(1, 2d, "3"));
148         assertEquals(14.0d, (double) result , 0.00001d);
149     }
150 }