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.assertNotNull;
21
22 import java.io.IOException;
23 import java.net.URL;
24 import java.net.URLClassLoader;
25 import java.nio.charset.StandardCharsets;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.util.Comparator;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.stream.Stream;
32
33 import javax.tools.JavaCompiler;
34 import javax.tools.ToolProvider;
35
36 import org.junit.jupiter.api.Assumptions;
37 import org.junit.jupiter.api.Test;
38
39
40
41
42
43
44
45 public class RecordPropertyAccessTest extends JexlTestCase {
46
47 public RecordPropertyAccessTest() {
48 super("RecordPropertyAccessTest");
49 }
50
51 private static Class<?> compileRecord(final String name, final String source) throws IOException,
52 ClassNotFoundException {
53 final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
54 Assumptions.assumeTrue(compiler != null, "no system Java compiler available");
55 final Path dir = Files.createTempDirectory("jexl-record-test");
56 try {
57 final Path javaFile = dir.resolve(name + ".java");
58 Files.write(javaFile, source.getBytes(StandardCharsets.UTF_8));
59 final int rc = compiler.run(null, null, null, "-d", dir.toString(), javaFile.toString());
60 assertEquals(0, rc, "failed to compile test record");
61 try (URLClassLoader loader = new URLClassLoader(new URL[] {dir.toUri().toURL()})) {
62 return Class.forName("org.apache.commons.jexl3." + name, true, loader);
63 }
64 } finally {
65 deleteRecursively(dir);
66 }
67 }
68
69 private static void deleteRecursively(final Path dir) throws IOException {
70 try (Stream<Path> paths = Files.walk(dir)) {
71 paths.sorted(Comparator.reverseOrder()).forEach(p -> p.toFile().delete());
72 }
73 }
74
75 @Test
76 void testRecordComponentIsReadableAsProperty() throws Exception {
77 Assumptions.assumeTrue(featureVersion() >= 16, "records require Java 16+");
78 final Class<?> pointClass = compileRecord("JexlRecordPoint",
79 "package org.apache.commons.jexl3; public record JexlRecordPoint(int x, int y) {}"
80 );
81 final Object point = pointClass.getConstructor(int.class, int.class).newInstance(1, 2);
82 final Map<String, Object> vars = new HashMap<>();
83 vars.put("point", point);
84 final JexlContext ctx = new MapContext(vars);
85
86 assertEquals(1, JEXL.createExpression("point.x").evaluate(ctx));
87 assertEquals(2, JEXL.createExpression("point.y").evaluate(ctx));
88 }
89
90 @Test
91 void testRecordAccessorOverrideStillWins() throws Exception {
92 Assumptions.assumeTrue(featureVersion() >= 16, "records require Java 16+");
93
94
95 final Class<?> pointClass = compileRecord(
96 "JexlRecordNamedPoint",
97 "package org.apache.commons.jexl3; "
98 + "public record JexlRecordNamedPoint(String name) { "
99 + "public String getName() { return name() + \"!\"; } }"
100 );
101 final Object point = pointClass.getConstructor(String.class).newInstance("origin");
102 final Map<String, Object> vars = new HashMap<>();
103 vars.put("point", point);
104 final JexlContext ctx = new MapContext(vars);
105
106 assertNotNull(JEXL.createExpression("point.name").evaluate(ctx));
107 assertEquals("origin!", JEXL.createExpression("point.name").evaluate(ctx));
108 }
109 }