1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNull;
21 import static org.junit.jupiter.api.Assertions.assertThrows;
22
23 import java.math.BigInteger;
24 import java.util.Map;
25 import java.util.TreeMap;
26
27 import org.junit.jupiter.api.Test;
28
29
30
31
32
33 @SuppressWarnings({"UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
34 class AntishCallTest extends JexlTestCase {
35
36
37
38
39 public class CallSupportArithmetic extends JexlArithmetic {
40 public CallSupportArithmetic(final boolean strict) {
41 super(strict);
42 }
43
44 public Object call(final Class<?> clazz, final Object... args) {
45 return callConstructor(null, clazz, args);
46 }
47
48 public Object call(final ClassReference clazz, final Object... args) {
49 return callConstructor(null, clazz, args);
50 }
51 }
52
53
54
55
56 public static class CallSupportContext extends MapContext {
57 private JexlEngine engine;
58 CallSupportContext(final Map<String, Object> map) {
59 super(map);
60 }
61
62 public Object call(final Class<?> clazz, final Object... args) {
63 return callConstructor(engine, clazz, args);
64 }
65
66 public Object call(final ClassReference clazz, final Object... args) {
67 return callConstructor(engine, clazz, args);
68 }
69
70 CallSupportContext engine(final JexlEngine j) {
71 engine = j;
72 return this;
73 }
74
75 @Override public Object get(final String str) {
76 if (!super.has(str)) {
77 try {
78 return CallSupportContext.class.getClassLoader().loadClass(str);
79 } catch (final Exception xany) {
80 return null;
81 }
82 }
83 return super.get(str);
84 }
85
86 @Override public boolean has(final String str) {
87 if (!super.has(str)){
88 try {
89 return CallSupportContext.class.getClassLoader().loadClass(str) != null;
90 } catch (final Exception xany) {
91 return false;
92 }
93 }
94 return true;
95 }
96 }
97
98
99
100
101 public static class ClassReference {
102 final Class<?> clazz;
103 ClassReference(final Class<?> c) {
104 this.clazz = c;
105 }
106 }
107 public static Object callConstructor(final JexlEngine engine, final Class<?> clazz, final Object... args) {
108 if (clazz == null || clazz.isPrimitive() || clazz.isInterface()
109 || clazz.isMemberClass() || clazz.isAnnotation() || clazz.isArray()) {
110 throw new ArithmeticException("not a constructible object");
111 }
112 JexlEngine jexl = engine;
113 if (jexl == null) {
114 jexl = JexlEngine.getThreadEngine();
115 if (jexl == null) {
116 throw new ArithmeticException("no engine to solve constructor");
117 }
118 }
119 return jexl.newInstance(clazz, args);
120 }
121
122
123
124
125
126
127
128
129 public static Object callConstructor(final JexlEngine engine, final ClassReference ref, final Object... args) {
130 return callConstructor(engine, ref.clazz, args);
131 }
132
133 public AntishCallTest() {
134 super("AntishCallTest");
135 }
136
137 void runTestCall(final JexlEngine jexl, final JexlContext jc) throws Exception {
138 final JexlScript check1 = jexl.createScript("var x = java.math.BigInteger; x('1234')");
139 final JexlScript check2 = jexl.createScript("java.math.BigInteger('4321')");
140
141 final Object o1 = check1.execute(jc);
142 assertEquals(new java.math.BigInteger("1234"), o1, "Result is not 1234");
143
144 final Object o2 = check2.execute(jc);
145 assertEquals(new java.math.BigInteger("4321"), o2, "Result is not 4321");
146 }
147
148 @Test
149 void testAntishArithmetic() throws Exception {
150 final CallSupportArithmetic ja = new CallSupportArithmetic(true);
151 final JexlEngine jexl = new JexlBuilder().cache(512).arithmetic(ja).create();
152 final Map<String, Object> lmap = new TreeMap<>();
153 final JexlContext jc = new MapContext(lmap);
154 lmap.put("java.math.BigInteger", java.math.BigInteger.class);
155 runTestCall(jexl, jc);
156 lmap.put("java.math.BigInteger", new ClassReference(BigInteger.class));
157 runTestCall(jexl, jc);
158 lmap.remove("java.math.BigInteger");
159 assertThrows(JexlException.class, () -> runTestCall(jexl, jc));
160 }
161
162 @Test
163 void testAntishContextVar() throws Exception {
164 final Map<String,Object> lmap = new TreeMap<>();
165 final JexlContext jc = new CallSupportContext(lmap).engine(JEXL);
166 runTestCall(JEXL, jc);
167 lmap.put("java.math.BigInteger", new ClassReference(BigInteger.class));
168 runTestCall(JEXL, jc);
169 lmap.remove("java.math.BigInteger");
170 runTestCall(JEXL, jc);
171 }
172
173
174 @Test
175 void testSafeAnt() throws Exception {
176 final JexlEvalContext ctxt = new JexlEvalContext();
177 final JexlOptions options = ctxt.getEngineOptions();
178 ctxt.set("x.y.z", 42);
179 JexlScript script;
180 Object result;
181
182 final JexlScript script0 = JEXL.createScript("x.y.z");
183 result = script0.execute(ctxt);
184 assertEquals(42, result);
185 assertEquals(42, ctxt.get("x.y.z"));
186
187 options.setAntish(false);
188 assertThrows(JexlException.class, () -> script0.execute(ctxt), "antish var shall not be resolved");
189 options.setAntish(true);
190
191 script = JEXL.createScript("x?.y?.z");
192 result = script.execute(ctxt);
193 assertNull(result);
194
195 final JexlScript script1 = JEXL.createScript("x?.y?.z = 3");
196 assertThrows(JexlException.class, () -> script1.execute(ctxt), "not antish assign");
197
198 final JexlScript script2 = JEXL.createScript("x.y?.z");
199 assertThrows(JexlException.class, () -> script2.execute(ctxt), "x not defined");
200
201 final JexlScript script3 = JEXL.createScript("x.y?.z = 3");
202 assertThrows(JexlException.class, () -> script3.execute(ctxt), "x not defined");
203
204 final JexlScript script4 = JEXL.createScript("x.`'y'`.z = 3");
205 assertThrows(JexlException.class, () -> script4.execute(ctxt), "x not defined");
206 }
207
208 }