Browse Source

Updated to spring 3.0.6

Abhinav Sarkar 9 years ago
parent
commit
9fe01a9403

+ 4
- 2
.gitignore View File

@@ -1,2 +1,4 @@
1
-target/*
2
-.pmd
1
+target/*
2
+.pmd
3
+.scala_dependencies
4
+.settings/

+ 4
- 2
pom.xml View File

@@ -19,6 +19,7 @@
19 19
  <properties>
20 20
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21 21
   <scala.version>2.7.7</scala.version>
22
+  <spring.version>3.0.6.RELEASE</spring.version>
22 23
  </properties>
23 24
 
24 25
  <issueManagement>
@@ -189,6 +190,7 @@
189 190
    <groupId>org.scala-lang</groupId>
190 191
    <artifactId>scala-library</artifactId>
191 192
    <version>${scala.version}</version>
193
+   <scope>test</scope>
192 194
   </dependency>
193 195
   <dependency>
194 196
    <groupId>org.scalatest</groupId>
@@ -205,12 +207,12 @@
205 207
   <dependency>
206 208
    <groupId>org.springframework</groupId>
207 209
    <artifactId>spring-core</artifactId>
208
-   <version>3.0.2.RELEASE</version>
210
+   <version>${spring.version}</version>
209 211
   </dependency>
210 212
   <dependency>
211 213
    <groupId>org.springframework</groupId>
212 214
    <artifactId>spring-expression</artifactId>
213
-   <version>3.0.2.RELEASE</version>
215
+   <version>${spring.version}</version>
214 216
   </dependency>
215 217
  </dependencies>
216 218
 

+ 97
- 97
src/main/java/net/abhinavsarkar/spelhelper/ExtensionFunctions.java View File

@@ -1,97 +1,97 @@
1
-/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
- *
3
- * This file is a part of SpelHelper library.
4
- *
5
- * SpelHelper library is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
- * published by the Free Software Foundation, either version 3 of the License,
8
- * or (at your option) any later version.
9
- *
10
- * SpelHelper library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
- * GNU Lesser General Public License for more details.
14
- *
15
- *  You should have received a copy of the GNU Lesser General Public License
16
- *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-package net.abhinavsarkar.spelhelper;
19
-
20
-import static java.util.Collections.unmodifiableList;
21
-import static java.util.Collections.unmodifiableMap;
22
-import static java.util.Collections.unmodifiableSet;
23
-
24
-import java.util.Arrays;
25
-import java.util.HashMap;
26
-import java.util.HashSet;
27
-import java.util.List;
28
-import java.util.Map;
29
-import java.util.Set;
30
-
31
-import org.springframework.util.Assert;
32
-
33
-/**
34
- * Provides some extension functions to create some basic collection types
35
- * inline in SpEL expressions.
36
- * These functions are automatically registered with {@link SpelHelper}.
37
- *
38
- * **See Also:**
39
- * [Spring Docs on extension functions](http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#expressions-ref-functions)
40
- * @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
41
- */
42
-public final class ExtensionFunctions {
43
-
44
-    private ExtensionFunctions() {
45
-    }
46
-
47
-    /**
48
-     * Creates an unmodifiable {@link List} of the arguments provided.
49
-     *
50
-     * Example use: `"#list('one', 'two', 'three')"`
51
-     * @param <T>   Type of the arguments provided.
52
-     * @param args  Arguments to create list of.
53
-     * @return  An unmodifiable list of the arguments provided.
54
-     */
55
-    public static <T> List<T> list(final T... args) {
56
-        return unmodifiableList(Arrays.asList(args));
57
-    }
58
-
59
-    /**
60
-     * Creates an unmodifiable {@link Set} of the arguments provided.
61
-     *
62
-     * Example use: `"#set('one', 'two', 'three')"`
63
-     * @param <T>   Type of the arguments provided.
64
-     * @param args  Arguments to create set of.
65
-     * @return  An unmodifiable set of the arguments provided.
66
-     */
67
-    public static <T> Set<T> set(final T... args) {
68
-        return unmodifiableSet(new HashSet<T>(list(args)));
69
-    }
70
-
71
-    /**
72
-     * Creates an unmodifiable {@link Map} using the {@link List} of keys
73
-     * provided as the first argument and the {@link List} of values provided
74
-     * as the second argument.
75
-     *
76
-     * Example use: `"#map(#list('one', 'two', 'three'), #list(1, 2, 3))"`
77
-     * @param <K>   Type of the keys of the map.
78
-     * @param <V>   Type of the values of map.
79
-     * @param keys  List of the keys.
80
-     * @param values    List of the values.
81
-     * @return  A unmodifiable map created from the key and value lists.
82
-     * @throws  IllegalArgumentException if the number of keys and the number of
83
-     * values is not equal.
84
-     */
85
-    public static <K,V> Map<K,V> map(final List<? extends K> keys,
86
-            final List<? extends V> values) {
87
-        Assert.isTrue(keys.size() == values.size(),
88
-                "There should be equal number of keys and values");
89
-        Map<K,V> map = new HashMap<K,V>();
90
-        int length = keys.size();
91
-        for (int i = 0; i < length; i++) {
92
-            map.put(keys.get(i), values.get(i));
93
-        }
94
-        return unmodifiableMap(map);
95
-    }
96
-
97
-}
1
+/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
+ *
3
+ * This file is a part of SpelHelper library.
4
+ *
5
+ * SpelHelper library is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
+ * published by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * SpelHelper library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU Lesser General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU Lesser General Public License
16
+ *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+package net.abhinavsarkar.spelhelper;
19
+
20
+import static java.util.Collections.unmodifiableList;
21
+import static java.util.Collections.unmodifiableMap;
22
+import static java.util.Collections.unmodifiableSet;
23
+
24
+import java.util.Arrays;
25
+import java.util.HashMap;
26
+import java.util.HashSet;
27
+import java.util.List;
28
+import java.util.Map;
29
+import java.util.Set;
30
+
31
+import org.springframework.util.Assert;
32
+
33
+/**
34
+ * Provides some extension functions to create some basic collection types
35
+ * inline in SpEL expressions.
36
+ * These functions are automatically registered with {@link SpelHelper}.
37
+ *
38
+ * **See Also:**
39
+ * [Spring Docs on extension functions](http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#expressions-ref-functions)
40
+ * @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
41
+ */
42
+public final class ExtensionFunctions {
43
+
44
+    private ExtensionFunctions() {
45
+    }
46
+
47
+    /**
48
+     * Creates an unmodifiable {@link List} of the arguments provided.
49
+     *
50
+     * Example use: `"#list('one', 'two', 'three')"`
51
+     * @param <T>   Type of the arguments provided.
52
+     * @param args  Arguments to create list of.
53
+     * @return  An unmodifiable list of the arguments provided.
54
+     */
55
+    public static <T> List<T> list(final T... args) {
56
+        return unmodifiableList(Arrays.asList(args));
57
+    }
58
+
59
+    /**
60
+     * Creates an unmodifiable {@link Set} of the arguments provided.
61
+     *
62
+     * Example use: `"#set('one', 'two', 'three')"`
63
+     * @param <T>   Type of the arguments provided.
64
+     * @param args  Arguments to create set of.
65
+     * @return  An unmodifiable set of the arguments provided.
66
+     */
67
+    public static <T> Set<T> set(final T... args) {
68
+        return unmodifiableSet(new HashSet<T>(list(args)));
69
+    }
70
+
71
+    /**
72
+     * Creates an unmodifiable {@link Map} using the {@link List} of keys
73
+     * provided as the first argument and the {@link List} of values provided
74
+     * as the second argument.
75
+     *
76
+     * Example use: `"#map(#list('one', 'two', 'three'), #list(1, 2, 3))"`
77
+     * @param <K>   Type of the keys of the map.
78
+     * @param <V>   Type of the values of map.
79
+     * @param keys  List of the keys.
80
+     * @param values    List of the values.
81
+     * @return  A unmodifiable map created from the key and value lists.
82
+     * @throws  IllegalArgumentException if the number of keys and the number of
83
+     * values is not equal.
84
+     */
85
+    public static <K,V> Map<K,V> map(final List<? extends K> keys,
86
+            final List<? extends V> values) {
87
+        Assert.isTrue(keys.size() == values.size(),
88
+                "There should be equal number of keys and values");
89
+        Map<K,V> map = new HashMap<K,V>();
90
+        int length = keys.size();
91
+        for (int i = 0; i < length; i++) {
92
+            map.put(keys.get(i), values.get(i));
93
+        }
94
+        return unmodifiableMap(map);
95
+    }
96
+
97
+}

+ 51
- 47
src/main/java/net/abhinavsarkar/spelhelper/ImplicitConstructorResolver.java View File

@@ -1,48 +1,52 @@
1
-/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
- *
3
- * This file is a part of SpelHelper library.
4
- *
5
- * SpelHelper library is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
- * published by the Free Software Foundation, either version 3 of the License,
8
- * or (at your option) any later version.
9
- *
10
- * SpelHelper library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
- * GNU Lesser General Public License for more details.
14
- *
15
- *  You should have received a copy of the GNU Lesser General Public License
16
- *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-package net.abhinavsarkar.spelhelper;
19
-
20
-import java.lang.reflect.Constructor;
21
-import java.util.Arrays;
22
-
23
-import org.springframework.expression.AccessException;
24
-import org.springframework.expression.ConstructorExecutor;
25
-import org.springframework.expression.ConstructorResolver;
26
-import org.springframework.expression.EvaluationContext;
27
-import org.springframework.expression.spel.support.ReflectiveConstructorResolver;
28
-
29
-final class ImplicitConstructorResolver implements
30
-        ConstructorResolver {
31
-
32
-    private final ReflectiveConstructorResolver delegate = new ReflectiveConstructorResolver();
33
-
34
-    public ConstructorExecutor resolve(final EvaluationContext context,
35
-            final String typeName, final Class<?>[] argumentTypes) throws AccessException {
36
-        try {
37
-            return delegate.resolve(context, typeName, argumentTypes);
38
-        } catch (AccessException ex) {
39
-            Object variable = ((SpelHelper) context.lookupVariable(SpelHelper.CONTEXT_LOOKUP_KEY))
40
-                .lookupImplicitConstructor(typeName + Arrays.toString(argumentTypes));
41
-            if (variable instanceof Constructor<?>) {
42
-                Constructor<?> constructor = (Constructor<?>) variable;
43
-                return delegate.resolve(context, constructor.getDeclaringClass().getName(), argumentTypes);
44
-            }
45
-            return null;
46
-        }
47
-    }
1
+/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
+ *
3
+ * This file is a part of SpelHelper library.
4
+ *
5
+ * SpelHelper library is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
+ * published by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * SpelHelper library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU Lesser General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU Lesser General Public License
16
+ *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+package net.abhinavsarkar.spelhelper;
19
+
20
+import java.lang.reflect.Constructor;
21
+import java.util.List;
22
+
23
+import org.springframework.core.convert.TypeDescriptor;
24
+import org.springframework.expression.AccessException;
25
+import org.springframework.expression.ConstructorExecutor;
26
+import org.springframework.expression.ConstructorResolver;
27
+import org.springframework.expression.EvaluationContext;
28
+import org.springframework.expression.spel.support.ReflectiveConstructorResolver;
29
+
30
+final class ImplicitConstructorResolver implements
31
+        ConstructorResolver {
32
+
33
+    private final ReflectiveConstructorResolver delegate = new ReflectiveConstructorResolver();
34
+
35
+    @Override
36
+    public ConstructorExecutor resolve(
37
+            final EvaluationContext context, final String typeName,
38
+            final List<TypeDescriptor> argumentTypes)
39
+    throws AccessException {
40
+        try {
41
+            return delegate.resolve(context, typeName, argumentTypes);
42
+        } catch (AccessException ex) {
43
+            Object variable = ((SpelHelper) context.lookupVariable(SpelHelper.CONTEXT_LOOKUP_KEY))
44
+                .lookupImplicitConstructor(typeName + argumentTypes.toString());
45
+            if (variable instanceof Constructor<?>) {
46
+                Constructor<?> constructor = (Constructor<?>) variable;
47
+                return delegate.resolve(context, constructor.getDeclaringClass().getName(), argumentTypes);
48
+            }
49
+            return null;
50
+        }
51
+    }
48 52
 }

+ 119
- 112
src/main/java/net/abhinavsarkar/spelhelper/ImplicitMethodResolver.java View File

@@ -1,113 +1,120 @@
1
-/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
- *
3
- * This file is a part of SpelHelper library.
4
- *
5
- * SpelHelper library is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
- * published by the Free Software Foundation, either version 3 of the License,
8
- * or (at your option) any later version.
9
- *
10
- * SpelHelper library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
- * GNU Lesser General Public License for more details.
14
- *
15
- *  You should have received a copy of the GNU Lesser General Public License
16
- *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-package net.abhinavsarkar.spelhelper;
19
-
20
-import java.lang.reflect.Method;
21
-import java.lang.reflect.Modifier;
22
-import java.util.concurrent.ConcurrentHashMap;
23
-
24
-import org.springframework.expression.AccessException;
25
-import org.springframework.expression.EvaluationContext;
26
-import org.springframework.expression.MethodExecutor;
27
-import org.springframework.expression.MethodResolver;
28
-import org.springframework.expression.TypedValue;
29
-import org.springframework.expression.spel.support.ReflectiveMethodResolver;
30
-
31
-final class ImplicitMethodResolver implements MethodResolver {
32
-
33
-    private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
34
-        new ConcurrentHashMap<String, MethodExecutor>();
35
-
36
-    private static final MethodExecutor NULL_ME = new MethodExecutor() {
37
-        public TypedValue execute(final EvaluationContext context, final Object target,
38
-                final Object... arguments) throws AccessException {
39
-            return null;
40
-        }
41
-    };
42
-
43
-    private static final class ImplicitMethodExecutor implements
44
-            MethodExecutor {
45
-        private final MethodExecutor executor;
46
-
47
-        public ImplicitMethodExecutor(final MethodExecutor executor) {
48
-            this.executor = executor;
49
-        }
50
-
51
-        public TypedValue execute(final EvaluationContext context, final Object target,
52
-                final Object... arguments) throws AccessException {
53
-            Object[] modifiedArguments = new Object[arguments.length + 1];
54
-            modifiedArguments[0] = target;
55
-            System.arraycopy(arguments, 0, modifiedArguments, 1, arguments.length);
56
-            return executor.execute(context, null, modifiedArguments);
57
-        }
58
-    }
59
-
60
-    public MethodExecutor resolve(final EvaluationContext context,
61
-            final Object targetObject, final String name, final Class<?>[] argumentTypes)
62
-            throws AccessException {
63
-        if (targetObject == null) {
64
-            return null;
65
-        }
66
-        Class<?> type = targetObject.getClass();
67
-        String cacheKey = type.getName() + "." + name;
68
-        if (CACHE.containsKey(cacheKey)) {
69
-            MethodExecutor executor = CACHE.get(cacheKey);
70
-            return executor == NULL_ME ? null : executor;
71
-        }
72
-
73
-        Method method = lookupMethod(context, type, name);
74
-        if (method != null) {
75
-            int modifiers = method.getModifiers();
76
-            if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) {
77
-                Class<?>[] parameterTypes = method.getParameterTypes();
78
-                Class<?> firstParamType = parameterTypes[0];
79
-                if (parameterTypes.length > 0
80
-                        && firstParamType.isAssignableFrom(type)) {
81
-                    Class<?>[] newArgumentTypes = new Class[argumentTypes.length + 1];
82
-                    newArgumentTypes[0] = firstParamType;
83
-                    System.arraycopy(argumentTypes, 0, newArgumentTypes,
84
-                            1, argumentTypes.length);
85
-                    MethodExecutor executor = new ReflectiveMethodResolver()
86
-                            .resolve(context, method.getDeclaringClass(), name,
87
-                                    newArgumentTypes);
88
-                    MethodExecutor wrappedExecutor = executor == null ? null
89
-                            : new ImplicitMethodExecutor(executor);
90
-                    if (wrappedExecutor == null) {
91
-                        CACHE.putIfAbsent(cacheKey, NULL_ME);
92
-                    }
93
-                    return wrappedExecutor;
94
-                }
95
-            }
96
-        }
97
-        CACHE.putIfAbsent(cacheKey, NULL_ME);
98
-        return null;
99
-    }
100
-
101
-    private static Method lookupMethod(final EvaluationContext context,
102
-            final Class<?> type, final String name) {
103
-        for (Class<?> clazz : InheritenceUtil.getInheritance(type)) {
104
-            Object variable = ((SpelHelper) context.lookupVariable(SpelHelper.CONTEXT_LOOKUP_KEY))
105
-                .lookupImplicitMethod(clazz.getName() + "." + name);
106
-            if (variable instanceof Method) {
107
-                return (Method) variable;
108
-            }
109
-        }
110
-        return null;
111
-    }
112
-
1
+/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
+ *
3
+ * This file is a part of SpelHelper library.
4
+ *
5
+ * SpelHelper library is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
+ * published by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * SpelHelper library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU Lesser General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU Lesser General Public License
16
+ *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+package net.abhinavsarkar.spelhelper;
19
+
20
+import java.lang.reflect.Method;
21
+import java.lang.reflect.Modifier;
22
+import java.util.ArrayList;
23
+import java.util.List;
24
+import java.util.concurrent.ConcurrentHashMap;
25
+
26
+import org.springframework.core.convert.TypeDescriptor;
27
+import org.springframework.expression.AccessException;
28
+import org.springframework.expression.EvaluationContext;
29
+import org.springframework.expression.MethodExecutor;
30
+import org.springframework.expression.MethodResolver;
31
+import org.springframework.expression.TypedValue;
32
+import org.springframework.expression.spel.support.ReflectiveMethodResolver;
33
+
34
+final class ImplicitMethodResolver implements MethodResolver {
35
+
36
+    private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
37
+        new ConcurrentHashMap<String, MethodExecutor>();
38
+
39
+    private final ReflectiveMethodResolver delegate = new ReflectiveMethodResolver();
40
+
41
+    private static final MethodExecutor NULL_ME = new MethodExecutor() {
42
+        public TypedValue execute(final EvaluationContext context, final Object target,
43
+                final Object... arguments) throws AccessException {
44
+            return null;
45
+        }
46
+    };
47
+
48
+    private static final class ImplicitMethodExecutor implements
49
+            MethodExecutor {
50
+        private final MethodExecutor executor;
51
+
52
+        public ImplicitMethodExecutor(final MethodExecutor executor) {
53
+            this.executor = executor;
54
+        }
55
+
56
+        public TypedValue execute(final EvaluationContext context, final Object target,
57
+                final Object... arguments) throws AccessException {
58
+            Object[] modifiedArguments = new Object[arguments.length + 1];
59
+            modifiedArguments[0] = target;
60
+            System.arraycopy(arguments, 0, modifiedArguments, 1, arguments.length);
61
+            return executor.execute(context, null, modifiedArguments);
62
+        }
63
+    }
64
+
65
+    @Override
66
+    public MethodExecutor resolve(
67
+            final EvaluationContext context, final Object targetObject,
68
+            final String name, final List<TypeDescriptor> argumentTypes)
69
+    throws AccessException {
70
+        if (targetObject == null) {
71
+            return null;
72
+        }
73
+        Class<?> type = targetObject.getClass();
74
+        String cacheKey = type.getName() + "." + name;
75
+        if (CACHE.containsKey(cacheKey)) {
76
+            MethodExecutor executor = CACHE.get(cacheKey);
77
+            return executor == NULL_ME ? null : executor;
78
+        }
79
+
80
+        Method method = lookupMethod(context, type, name);
81
+        if (method != null) {
82
+            int modifiers = method.getModifiers();
83
+            if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) {
84
+                Class<?>[] parameterTypes = method.getParameterTypes();
85
+                Class<?> firstParamType = parameterTypes[0];
86
+                if (parameterTypes.length > 0
87
+                        && firstParamType.isAssignableFrom(type)) {
88
+                    List<TypeDescriptor> newArgumentTypes = new ArrayList<TypeDescriptor>();
89
+                    newArgumentTypes.add(TypeDescriptor.valueOf(firstParamType));
90
+                    newArgumentTypes.addAll(argumentTypes);
91
+
92
+                    MethodExecutor executor =
93
+                        delegate.resolve(context, method.getDeclaringClass(),
94
+                                name, newArgumentTypes);
95
+                    MethodExecutor wrappedExecutor = executor == null ? null
96
+                            : new ImplicitMethodExecutor(executor);
97
+                    if (wrappedExecutor == null) {
98
+                        CACHE.putIfAbsent(cacheKey, NULL_ME);
99
+                    }
100
+                    return wrappedExecutor;
101
+                }
102
+            }
103
+        }
104
+        CACHE.putIfAbsent(cacheKey, NULL_ME);
105
+        return null;
106
+    }
107
+
108
+    private static Method lookupMethod(final EvaluationContext context,
109
+            final Class<?> type, final String name) {
110
+        for (Class<?> clazz : InheritenceUtil.getInheritance(type)) {
111
+            Object variable = ((SpelHelper) context.lookupVariable(SpelHelper.CONTEXT_LOOKUP_KEY))
112
+                .lookupImplicitMethod(clazz.getName() + "." + name);
113
+            if (variable instanceof Method) {
114
+                return (Method) variable;
115
+            }
116
+        }
117
+        return null;
118
+    }
119
+
113 120
 }

+ 129
- 129
src/main/java/net/abhinavsarkar/spelhelper/ImplicitMethods.java View File

@@ -1,129 +1,129 @@
1
-/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
- *
3
- * This file is a part of SpelHelper library.
4
- *
5
- * SpelHelper library is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
- * published by the Free Software Foundation, either version 3 of the License,
8
- * or (at your option) any later version.
9
- *
10
- * SpelHelper library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
- * GNU Lesser General Public License for more details.
14
- *
15
- *  You should have received a copy of the GNU Lesser General Public License
16
- *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-package net.abhinavsarkar.spelhelper;
19
-
20
-import static java.util.Collections.unmodifiableList;
21
-import static java.util.Collections.unmodifiableSet;
22
-
23
-import java.util.ArrayList;
24
-import java.util.Collections;
25
-import java.util.HashSet;
26
-import java.util.List;
27
-import java.util.Set;
28
-
29
-/**
30
- * Provides some implicit methods which can be invoked on the instances of
31
- * class of the first parameter of the method inside a SpEL expression.
32
- * @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
33
- */
34
-public final class ImplicitMethods {
35
-
36
-    private ImplicitMethods() {
37
-    }
38
-
39
-    /**
40
-     * Provides implicit method `distinct` on the {@link List} class.
41
-     *
42
-     * Example: `"#list('a','b','a').distinct()" //should return List('a','b')`
43
-     *
44
-     * With implicit property support provided by {@link SpelHelper} this can
45
-     * also be written as:
46
-     *
47
-     * `"#list('a','b','a').distinct" //same output as earlier`
48
-     * @param <T>   Type of the list's elements.
49
-     * @param list  The list to call this method upon.
50
-     * @return  An unmodifiable {@link Set} containing the distinct items of the list.
51
-     */
52
-    public static <T> Set<T> distinct(final List<? extends T> list) {
53
-        return unmodifiableSet(new HashSet<T>(list));
54
-    }
55
-
56
-    /**
57
-     * Provides implicit method `sorted` on the {@link List} class.
58
-     *
59
-     * Example: `"#list('c','b','a').sorted()" //should return List('a','b','c')`
60
-     *
61
-     * With implicit property support provided by {@link SpelHelper} this can
62
-     * also be written as:
63
-     *
64
-     * `"#list('c','b','a').sorted" //same output as earlier`
65
-     * @param <T>   Type of the list's elements.
66
-     * @param list  The list to call this method upon.
67
-     * @return      An unmodifiable {@link List} containing the sorted items
68
-     * of the list.
69
-     * @see Collections#sort(List)
70
-     */
71
-    public static <T extends Comparable<? super T>> List<T> sorted(
72
-            final List<? extends T> list) {
73
-        List<T> temp = new ArrayList<T>(list);
74
-        Collections.sort(temp);
75
-        return unmodifiableList(temp);
76
-    }
77
-
78
-    /**
79
-     * Provides implicit method `reversed` on the {@link List} class.
80
-     *
81
-     * Example: `"#list('c','b','a').reversed()" //should return List('a','b','c')`
82
-     *
83
-     * With implicit property support provided by {@link SpelHelper} this can
84
-     * also be written as:
85
-     *
86
-     * `"#list('c','b','a').reversed" //same output as earlier`
87
-     * @param <T>   Type of the list's elements.
88
-     * @param list  The list to call this method upon.
89
-     * @return      An unmodifiable {@link List} containing the items of the
90
-     * list in reverse order.
91
-     * @see Collections#reverse(List)
92
-     */
93
-    public static <T> List<T> reversed(final List<? extends T> list) {
94
-        List<T> temp = new ArrayList<T>(list);
95
-        Collections.reverse(temp);
96
-        return unmodifiableList(temp);
97
-    }
98
-
99
-    /**
100
-     * Provides implicit method `take` on the {@link List} class.
101
-     *
102
-     * Example: `"#list('c','b','a').take(2)" //should return List('a','b')`
103
-     *
104
-     * @param <T>   Type of the list's elements.
105
-     * @param list  The list to call this method upon.
106
-     * @param n     Number of items to _take_ from the list.
107
-     * @return      An unmodifiable {@link List} containing the first `n` items
108
-     * of the list.
109
-     */
110
-    public static <T> List<T> take(final List<T> list, final int n) {
111
-        return unmodifiableList(list.subList(0, n));
112
-    }
113
-
114
-    /**
115
-     * Provides implicit method `drop` on the {@link List} class.
116
-     *
117
-     * Example: `"#list('c','b','a').drop(2)" //should return List('a')`
118
-     *
119
-     * @param <T>   Type of the list's elements.
120
-     * @param list  The list to call this method upon.
121
-     * @param n     Number of items to _drop_ from the list.
122
-     * @return      An unmodifiable {@link List} containing the items after the
123
-     * first `n` items of the list.
124
-     */
125
-    public static <T> List<T> drop(final List<T> list, final int n) {
126
-        return unmodifiableList(list.subList(n, list.size()));
127
-    }
128
-
129
-}
1
+/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
+ *
3
+ * This file is a part of SpelHelper library.
4
+ *
5
+ * SpelHelper library is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
+ * published by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * SpelHelper library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU Lesser General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU Lesser General Public License
16
+ *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+package net.abhinavsarkar.spelhelper;
19
+
20
+import static java.util.Collections.unmodifiableList;
21
+import static java.util.Collections.unmodifiableSet;
22
+
23
+import java.util.ArrayList;
24
+import java.util.Collections;
25
+import java.util.HashSet;
26
+import java.util.List;
27
+import java.util.Set;
28
+
29
+/**
30
+ * Provides some implicit methods which can be invoked on the instances of
31
+ * class of the first parameter of the method inside a SpEL expression.
32
+ * @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
33
+ */
34
+public final class ImplicitMethods {
35
+
36
+    private ImplicitMethods() {
37
+    }
38
+
39
+    /**
40
+     * Provides implicit method `distinct` on the {@link List} class.
41
+     *
42
+     * Example: `"#list('a','b','a').distinct()" //should return List('a','b')`
43
+     *
44
+     * With implicit property support provided by {@link SpelHelper} this can
45
+     * also be written as:
46
+     *
47
+     * `"#list('a','b','a').distinct" //same output as earlier`
48
+     * @param <T>   Type of the list's elements.
49
+     * @param list  The list to call this method upon.
50
+     * @return  An unmodifiable {@link Set} containing the distinct items of the list.
51
+     */
52
+    public static <T> Set<T> distinct(final List<? extends T> list) {
53
+        return unmodifiableSet(new HashSet<T>(list));
54
+    }
55
+
56
+    /**
57
+     * Provides implicit method `sorted` on the {@link List} class.
58
+     *
59
+     * Example: `"#list('c','b','a').sorted()" //should return List('a','b','c')`
60
+     *
61
+     * With implicit property support provided by {@link SpelHelper} this can
62
+     * also be written as:
63
+     *
64
+     * `"#list('c','b','a').sorted" //same output as earlier`
65
+     * @param <T>   Type of the list's elements.
66
+     * @param list  The list to call this method upon.
67
+     * @return      An unmodifiable {@link List} containing the sorted items
68
+     * of the list.
69
+     * @see Collections#sort(List)
70
+     */
71
+    public static <T extends Comparable<? super T>> List<T> sorted(
72
+            final List<? extends T> list) {
73
+        List<T> temp = new ArrayList<T>(list);
74
+        Collections.sort(temp);
75
+        return unmodifiableList(temp);
76
+    }
77
+
78
+    /**
79
+     * Provides implicit method `reversed` on the {@link List} class.
80
+     *
81
+     * Example: `"#list('c','b','a').reversed()" //should return List('a','b','c')`
82
+     *
83
+     * With implicit property support provided by {@link SpelHelper} this can
84
+     * also be written as:
85
+     *
86
+     * `"#list('c','b','a').reversed" //same output as earlier`
87
+     * @param <T>   Type of the list's elements.
88
+     * @param list  The list to call this method upon.
89
+     * @return      An unmodifiable {@link List} containing the items of the
90
+     * list in reverse order.
91
+     * @see Collections#reverse(List)
92
+     */
93
+    public static <T> List<T> reversed(final List<? extends T> list) {
94
+        List<T> temp = new ArrayList<T>(list);
95
+        Collections.reverse(temp);
96
+        return unmodifiableList(temp);
97
+    }
98
+
99
+    /**
100
+     * Provides implicit method `take` on the {@link List} class.
101
+     *
102
+     * Example: `"#list('c','b','a').take(2)" //should return List('a','b')`
103
+     *
104
+     * @param <T>   Type of the list's elements.
105
+     * @param list  The list to call this method upon.
106
+     * @param n     Number of items to _take_ from the list.
107
+     * @return      An unmodifiable {@link List} containing the first `n` items
108
+     * of the list.
109
+     */
110
+    public static <T> List<T> take(final List<T> list, final int n) {
111
+        return unmodifiableList(list.subList(0, n));
112
+    }
113
+
114
+    /**
115
+     * Provides implicit method `drop` on the {@link List} class.
116
+     *
117
+     * Example: `"#list('c','b','a').drop(2)" //should return List('a')`
118
+     *
119
+     * @param <T>   Type of the list's elements.
120
+     * @param list  The list to call this method upon.
121
+     * @param n     Number of items to _drop_ from the list.
122
+     * @return      An unmodifiable {@link List} containing the items after the
123
+     * first `n` items of the list.
124
+     */
125
+    public static <T> List<T> drop(final List<T> list, final int n) {
126
+        return unmodifiableList(list.subList(n, list.size()));
127
+    }
128
+
129
+}

+ 69
- 66
src/main/java/net/abhinavsarkar/spelhelper/ImplicitPropertyAccessor.java View File

@@ -1,67 +1,70 @@
1
-/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
- *
3
- * This file is a part of SpelHelper library.
4
- *
5
- * SpelHelper library is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
- * published by the Free Software Foundation, either version 3 of the License,
8
- * or (at your option) any later version.
9
- *
10
- * SpelHelper library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
- * GNU Lesser General Public License for more details.
14
- *
15
- *  You should have received a copy of the GNU Lesser General Public License
16
- *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-package net.abhinavsarkar.spelhelper;
19
-
20
-import java.text.MessageFormat;
21
-import java.util.concurrent.ConcurrentHashMap;
22
-
23
-import org.springframework.expression.AccessException;
24
-import org.springframework.expression.EvaluationContext;
25
-import org.springframework.expression.MethodExecutor;
26
-import org.springframework.expression.MethodResolver;
27
-import org.springframework.expression.TypedValue;
28
-import org.springframework.util.Assert;
29
-
30
-final class ImplicitPropertyAccessor extends ReadOnlyGenericPropertyAccessor {
31
-
32
-    private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
33
-        new ConcurrentHashMap<String, MethodExecutor>();
34
-
35
-    public boolean canRead(final EvaluationContext context,
36
-            final Object target, final String name)
37
-            throws AccessException {
38
-        Assert.notNull(target, "target is null");
39
-        String cacheKey = target.getClass().getName() + "." + name;
40
-        if (CACHE.containsKey(cacheKey)) {
41
-            return CACHE.get(cacheKey) != null;
42
-        }
43
-
44
-        for (MethodResolver mr : context.getMethodResolvers()) {
45
-            MethodExecutor me = mr.resolve(context, target, name, new Class[0]);
46
-            if (me != null) {
47
-                CACHE.putIfAbsent(cacheKey, me);
48
-                return true;
49
-            }
50
-        }
51
-
52
-        CACHE.putIfAbsent(cacheKey, null);
53
-        return false;
54
-    }
55
-
56
-    public TypedValue read(final EvaluationContext context,
57
-            final Object target, final String name)
58
-            throws AccessException {
59
-        if (canRead(context, target, name)) {
60
-            String cacheKey = target.getClass().getName() + "." + name;
61
-            return CACHE.get(cacheKey).execute(context, target, new Object[0]);
62
-        }
63
-        throw new AccessException(MessageFormat.format(
64
-                "Cannot read property: {0} of target: {1}", name, target));
65
-    }
66
-
1
+/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
+ *
3
+ * This file is a part of SpelHelper library.
4
+ *
5
+ * SpelHelper library is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
+ * published by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * SpelHelper library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU Lesser General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU Lesser General Public License
16
+ *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+package net.abhinavsarkar.spelhelper;
19
+
20
+import java.text.MessageFormat;
21
+import java.util.Collections;
22
+import java.util.concurrent.ConcurrentHashMap;
23
+
24
+import org.springframework.core.convert.TypeDescriptor;
25
+import org.springframework.expression.AccessException;
26
+import org.springframework.expression.EvaluationContext;
27
+import org.springframework.expression.MethodExecutor;
28
+import org.springframework.expression.MethodResolver;
29
+import org.springframework.expression.TypedValue;
30
+import org.springframework.util.Assert;
31
+
32
+final class ImplicitPropertyAccessor extends ReadOnlyGenericPropertyAccessor {
33
+
34
+    private static final ConcurrentHashMap<String, MethodExecutor> CACHE =
35
+        new ConcurrentHashMap<String, MethodExecutor>();
36
+
37
+    public boolean canRead(final EvaluationContext context,
38
+            final Object target, final String name)
39
+            throws AccessException {
40
+        Assert.notNull(target, "target is null");
41
+        String cacheKey = target.getClass().getName() + "." + name;
42
+        if (CACHE.containsKey(cacheKey)) {
43
+            return CACHE.get(cacheKey) != null;
44
+        }
45
+
46
+        for (MethodResolver mr : context.getMethodResolvers()) {
47
+            MethodExecutor me =
48
+                mr.resolve(context, target, name, Collections.<TypeDescriptor>emptyList());
49
+            if (me != null) {
50
+                CACHE.putIfAbsent(cacheKey, me);
51
+                return true;
52
+            }
53
+        }
54
+
55
+        CACHE.putIfAbsent(cacheKey, null);
56
+        return false;
57
+    }
58
+
59
+    public TypedValue read(final EvaluationContext context,
60
+            final Object target, final String name)
61
+            throws AccessException {
62
+        if (canRead(context, target, name)) {
63
+            String cacheKey = target.getClass().getName() + "." + name;
64
+            return CACHE.get(cacheKey).execute(context, target, new Object[0]);
65
+        }
66
+        throw new AccessException(MessageFormat.format(
67
+                "Cannot read property: {0} of target: {1}", name, target));
68
+    }
69
+
67 70
 }

+ 86
- 86
src/main/java/net/abhinavsarkar/spelhelper/InheritenceUtil.java View File

@@ -1,86 +1,86 @@
1
-/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
- *
3
- * This file is a part of SpelHelper library.
4
- *
5
- * SpelHelper library is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
- * published by the Free Software Foundation, either version 3 of the License,
8
- * or (at your option) any later version.
9
- *
10
- * SpelHelper library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
- * GNU Lesser General Public License for more details.
14
- *
15
- *  You should have received a copy of the GNU Lesser General Public License
16
- *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-package net.abhinavsarkar.spelhelper;
19
-
20
-import java.util.LinkedHashSet;
21
-import java.util.Set;
22
-
23
-final class InheritenceUtil {
24
-
25
-    private InheritenceUtil() {
26
-    }
27
-
28
-    public static Set<Class<?>> getInheritance(final Class<?> clazz) {
29
-        LinkedHashSet<Class<?>> result = new LinkedHashSet<Class<?>>();
30
-        result.add(clazz);
31
-        getInheritance(clazz, result);
32
-        return result;
33
-    }
34
-
35
-    /**
36
-     * Get inheritance of type.
37
-     *
38
-     * @param clazz
39
-     * @param result
40
-     */
41
-    private static void getInheritance(final Class<?> clazz, final Set<Class<?>> result) {
42
-        Class<?> superclass = getSuperclass(clazz);
43
-
44
-        if (superclass != null) {
45
-            result.add(superclass);
46
-            getInheritance(superclass, result);
47
-        }
48
-
49
-        getInterfaceInheritance(clazz, result);
50
-    }
51
-
52
-    /**
53
-     * Get interfaces that the type inherits from.
54
-     *
55
-     * @param clazz
56
-     * @param result
57
-     */
58
-    private static void getInterfaceInheritance(final Class<?> clazz,
59
-            final Set<Class<?>> result) {
60
-        for (Class<?> c : clazz.getInterfaces()) {
61
-            result.add(c);
62
-            getInterfaceInheritance(c, result);
63
-        }
64
-    }
65
-
66
-    /**
67
-     * Get superclass of class.
68
-     *
69
-     * @param clazz
70
-     * @return
71
-     */
72
-    private static Class<?> getSuperclass(final Class<?> clazz) {
73
-        if (clazz == null) {
74
-            return null;
75
-        }
76
-        if (clazz.isArray() && clazz != Object[].class) {
77
-            Class<?> type = clazz.getComponentType();
78
-            while (type.isArray()) {
79
-                type = type.getComponentType();
80
-            }
81
-            return type;
82
-        }
83
-        return clazz.getSuperclass();
84
-    }
85
-
86
-}
1
+/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
+ *
3
+ * This file is a part of SpelHelper library.
4
+ *
5
+ * SpelHelper library is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
+ * published by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * SpelHelper library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU Lesser General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU Lesser General Public License
16
+ *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+package net.abhinavsarkar.spelhelper;
19
+
20
+import java.util.LinkedHashSet;
21
+import java.util.Set;
22
+
23
+final class InheritenceUtil {
24
+
25
+    private InheritenceUtil() {
26
+    }
27
+
28
+    public static Set<Class<?>> getInheritance(final Class<?> clazz) {
29
+        LinkedHashSet<Class<?>> result = new LinkedHashSet<Class<?>>();
30
+        result.add(clazz);
31
+        getInheritance(clazz, result);
32
+        return result;
33
+    }
34
+
35
+    /**
36
+     * Get inheritance of type.
37
+     *
38
+     * @param clazz
39
+     * @param result
40
+     */
41
+    private static void getInheritance(final Class<?> clazz, final Set<Class<?>> result) {
42
+        Class<?> superclass = getSuperclass(clazz);
43
+
44
+        if (superclass != null) {
45
+            result.add(superclass);
46
+            getInheritance(superclass, result);
47
+        }
48
+
49
+        getInterfaceInheritance(clazz, result);
50
+    }
51
+
52
+    /**
53
+     * Get interfaces that the type inherits from.
54
+     *
55
+     * @param clazz
56
+     * @param result
57
+     */
58
+    private static void getInterfaceInheritance(final Class<?> clazz,
59
+            final Set<Class<?>> result) {
60
+        for (Class<?> c : clazz.getInterfaces()) {
61
+            result.add(c);
62
+            getInterfaceInheritance(c, result);
63
+        }
64
+    }
65
+
66
+    /**
67
+     * Get superclass of class.
68
+     *
69
+     * @param clazz
70
+     * @return
71
+     */
72
+    private static Class<?> getSuperclass(final Class<?> clazz) {
73
+        if (clazz == null) {
74
+            return null;
75
+        }
76
+        if (clazz.isArray() && clazz != Object[].class) {
77
+            Class<?> type = clazz.getComponentType();
78
+            while (type.isArray()) {
79
+                type = type.getComponentType();
80
+            }
81
+            return type;
82
+        }
83
+        return clazz.getSuperclass();
84
+    }
85
+
86
+}

+ 44
- 44
src/main/java/net/abhinavsarkar/spelhelper/ReadOnlyGenericPropertyAccessor.java View File

@@ -1,45 +1,45 @@
1
-/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
- *
3
- * This file is a part of SpelHelper library.
4
- *
5
- * SpelHelper library is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
- * published by the Free Software Foundation, either version 3 of the License,
8
- * or (at your option) any later version.
9
- *
10
- * SpelHelper library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
- * GNU Lesser General Public License for more details.
14
- *
15
- *  You should have received a copy of the GNU Lesser General Public License
16
- *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-package net.abhinavsarkar.spelhelper;
19
-
20
-import java.text.MessageFormat;
21
-
22
-import org.springframework.expression.AccessException;
23
-import org.springframework.expression.EvaluationContext;
24
-import org.springframework.expression.PropertyAccessor;
25
-
26
-abstract class ReadOnlyGenericPropertyAccessor implements
27
-        PropertyAccessor {
28
-
29
-    public final boolean canWrite(final EvaluationContext context,
30
-            final Object target, final String name) throws AccessException {
31
-        return false;
32
-    }
33
-
34
-    @SuppressWarnings("rawtypes")
35
-    public final Class[] getSpecificTargetClasses() {
36
-        return null;
37
-    }
38
-
39
-    public final void write(final EvaluationContext context, final Object target,
40
-            final String name, final Object newValue) throws AccessException {
41
-        throw new AccessException(MessageFormat.format(
42
-                "Cannot write property: {0} of target: {1}", name, target));
43
-    }
44
-
1
+/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
+ *
3
+ * This file is a part of SpelHelper library.
4
+ *
5
+ * SpelHelper library is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
+ * published by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * SpelHelper library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU Lesser General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU Lesser General Public License
16
+ *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+package net.abhinavsarkar.spelhelper;
19
+
20
+import java.text.MessageFormat;
21
+
22
+import org.springframework.expression.AccessException;
23
+import org.springframework.expression.EvaluationContext;
24
+import org.springframework.expression.PropertyAccessor;
25
+
26
+abstract class ReadOnlyGenericPropertyAccessor implements
27
+        PropertyAccessor {
28
+
29
+    public final boolean canWrite(final EvaluationContext context,
30
+            final Object target, final String name) throws AccessException {
31
+        return false;
32
+    }
33
+
34
+    @SuppressWarnings("rawtypes")
35
+    public final Class[] getSpecificTargetClasses() {
36
+        return null;
37
+    }
38
+
39
+    public final void write(final EvaluationContext context, final Object target,
40
+            final String name, final Object newValue) throws AccessException {
41
+        throw new AccessException(MessageFormat.format(
42
+                "Cannot write property: {0} of target: {1}", name, target));
43
+    }
44
+
45 45
 }

+ 349
- 349
src/main/java/net/abhinavsarkar/spelhelper/SpelHelper.java View File

@@ -1,349 +1,349 @@
1
-/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
- *
3
- * This file is a part of SpelHelper library.
4
- *
5
- * SpelHelper library is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
- * published by the Free Software Foundation, either version 3 of the License,
8
- * or (at your option) any later version.
9
- *
10
- * SpelHelper library is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
- * GNU Lesser General Public License for more details.
14
- *
15
- *  You should have received a copy of the GNU Lesser General Public License
16
- *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-package net.abhinavsarkar.spelhelper;
19
-
20
-import static java.util.Arrays.asList;
21
-
22
-import java.lang.reflect.Constructor;
23
-import java.lang.reflect.Method;
24
-import java.lang.reflect.Modifier;
25
-import java.util.ArrayList;
26
-import java.util.Arrays;
27
-import java.util.HashSet;
28
-import java.util.List;
29
-import java.util.Map;
30
-import java.util.Set;
31
-import java.util.concurrent.ConcurrentHashMap;
32
-
33
-import org.springframework.expression.ConstructorResolver;
34
-import org.springframework.expression.EvaluationContext;
35
-import org.springframework.expression.Expression;
36
-import org.springframework.expression.ExpressionParser;
37
-import org.springframework.expression.spel.standard.SpelExpressionParser;
38
-import org.springframework.expression.spel.support.StandardEvaluationContext;
39
-import org.springframework.util.Assert;
40
-
41
-/**
42
- * SpelHelper provides additional functionalities to work with
43
- * [Spring Expression Language (SpEL)][1].
44
- *
45
- * The addition functionalities provided are:
46
- *
47
- * 1. Implicit methods
48
- * 2. Implicit properties
49
- * 3. Simplified extension functions
50
- * 4. Simplified constructors
51
- *
52
- * **Implicit Methods**
53
- *
54
- * Implicit methods allow one to registers methods with SpelHelper and attach
55
- * them to particular classes. After that, when that method is called on an
56
- * object of that particular class inside a SpEL expression, SpelHelper
57
- * redirects the method call to the registered method.
58
- *
59
- * Example: {@link ImplicitMethods#sorted(List)} method is automatically
60
- * registered by SpelHelper. The class that the method should be invoked for
61
- * is the type of the first parameter of the method. In this case, the class is
62
- * {@link List}.
63
- *
64
- * So when an expression like `"#list(1,4,2).sorted()"` is evaluated, the
65
- * {@link ImplicitMethods#sorted(List)} method is invoked with the list as its
66
- * first parameter and its return value is used in further evaluation of the
67
- * expression.
68
- *
69
- * See {@link SpelHelper#registerImplicitMethodsFromClass(Class)}.
70
- *
71
- * **Implicit Properties**
72
- *
73
- * Implicit properties allow one to treat no argument methods of an object
74
- * as properties of the object. SpelHelper intercepts the property resolution
75
- * of SpEL and if the property name is same as some no-arg method of the target
76
- * object then it invokes the method on the object and provides its return value
77
- * as the property value for further evaluation of the expression.
78
- *
79
- * Example: Using implicit properties, the example of implicit methods can be
80
- * written as: `"#list(1,4,2).sorted"` - dropping the parens - and it will return
81
- * the same value as the last example.
82
- *
83
- * Implicit property resolution considers both the actual methods of the object
84
- * and the implicit methods registered on the object's class.
85
- *
86
- * **Simplified extension functions**
87
- *
88
- * SpEL [allows][2] to register extension function on the context by providing a
89
- * name and a {@link Method} object. SpelHelper simplifies this by taking a class
90
- * and registering all the `public static` methods of the class which do not
91
- * have a `void` return type. The methods are registered by their simple name.
92
- *
93
- * Example: All the methods of {@link ExtensionFunctions} class are automatically
94
- * registered by SpelHelper. Hence the method {@link ExtensionFunctions#list(Object...)}
95
- * can be called from inside a SpEL expression using the function call syntax:
96
- * `"#list(1,2,3)`".
97
- *
98
- * See {@link SpelHelper#registerFunctionsFromClass(Class)}.
99
- *
100
- * **Simplified constructors**
101
- *
102
- * SpEL [allows][3] calling constructors from inside a SpEL expression using the
103
- * `new` operator. But they have to be called with their full name like:
104
- * `"new org.example.Foo('bar')"`. SpelHelper simplifies this by taking a class
105
- * and registering all its public constructors to the SpEL context by their
106
- * simple name.
107
- *
108
- * Example: After registering the `org.example.Foo` class with SpelHelper, its
109
- * constructor can be called from inside a SpEL expression by: `"new Foo('bar')"`.
110
- *
111
- * See {@link SpelHelper#registerConstructorsFromClass(Class)}.
112
- *
113
- * In addition to all the above functionalities, SpelHelper automatically registers
114
- * some extension functions and implicit methods which are always available in
115
- * the SpEL expressions evaluated through SpelHelper. See {@link ExtensionFunctions}
116
- * and {@link ImplicitMethods} for further details.
117
- *
118
- * [1]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html
119
- * [2]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#expressions-ref-functions
120
- * [3]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e11927
121
- *
122
- * @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
123
- */
124
-public final class SpelHelper {
125
-
126
-    static final String CONTEXT_LOOKUP_KEY = SpelHelper.class.getName();
127
-
128
-    private final ExpressionParser PARSER = new SpelExpressionParser();
129
-    private static final ThreadLocal<EvaluationContext> CURRENT_CONTEXT =
130
-        new ThreadLocal<EvaluationContext>();
131
-
132
-    private final Set<Method> registeredFunctions = new HashSet<Method>();
133
-    private final Map<String,Method> registeredMethods =
134
-        new ConcurrentHashMap<String, Method>();
135
-    private final Map<String,Constructor<?>> registeredConstructors =
136
-        new ConcurrentHashMap<String, Constructor<?>>();
137
-
138
-    /**
139
-     * Creates an instance of SpelHelper.
140
-     */
141
-    public SpelHelper() {
142
-        registerFunctionsFromClass(ExtensionFunctions.class);
143
-        registerImplicitMethodsFromClass(ImplicitMethods.class);
144
-    }
145
-
146
-    /**
147
-     * Registers the public static methods in the class `clazz` as implicit
148
-     * methods for the class of the first parameter of the methods.
149
-     *
150
-     * Only registers the public static methods with non void return type and at
151
-     * least one argument.
152
-     * @see ImplicitMethods
153
-     * @param clazz The class to register the methods from.
154
-     * @return      The current instance of SpelHelper. This is for chaining
155
-     * the methods calls.
156
-     */
157
-    public SpelHelper registerImplicitMethodsFromClass(final Class<?> clazz) {
158
-        for (Method method : filterMethods(clazz)) {
159
-            registeredMethods.put(String.format(
160
-                    "%s.%s", method.getParameterTypes()[0].getName(), method.getName()),
161
-                    method);
162
-        }
163
-        return this;
164
-    }
165
-
166
-    /**
167
-     * Registers the public static methods in the class `clazz` as functions
168
-     * which can be called from SpEL expressions.
169
-     * The functions are registered with the simple name of the methods.
170
-     *
171
-     * Only registers the public static methods with non void return type.
172
-     * @see ExtensionFunctions
173
-     * @param clazz The class to register the functions from.
174
-     * @return      The current instance of SpelHelper. This is for chaining
175
-     * the methods calls.
176
-     */
177
-    public SpelHelper registerFunctionsFromClass(final Class<?> clazz) {
178
-        registeredFunctions.addAll(filterFunctions(clazz));
179
-        return this;
180
-    }
181
-
182
-    /**
183
-     * Registers the public constructors of the class `clazz` so that they
184
-     * can be called by their simple name from SpEL expressions.
185
-     * @param clazz The class to register the constructors from.
186
-     * @return      The current instance of SpelHelper. This is for chaining
187
-     * the methods calls.
188
-     */
189
-    public SpelHelper registerConstructorsFromClass(final Class<?> clazz) {
190
-        for (Constructor<?> constructor : asList(clazz.getConstructors())) {
191
-            registeredConstructors.put(
192
-                    constructor.getDeclaringClass().getSimpleName()
193
-                        + Arrays.toString(constructor.getParameterTypes()),
194
-                    constructor);
195
-        }
196
-        return this;
197
-    }
198
-
199
-    /**
200
-     * Evaluates a SpEL expression `expressionString` in the context
201
-     * of root element `rootElement` and gives back a result of type
202
-     * `desiredType`.
203
-     * @param <T>   The type of the result desired.
204
-     * @param expressionString  The SpEL expression to evaluate.
205
-     * @param rootElement   The root element in context of which the expression
206
-     * is to be evaluated.
207
-     * @param desiredType   The class of the result desired.
208
-     * @return  The result of the evaluation of the expression.
209
-     * @see ExpressionParser#parseExpression(String)
210
-     * @see Expression#getValue(EvaluationContext, Class)
211
-     */
212
-    public <T> T evalExpression(final String expressionString,
213
-            final Object rootElement, final Class<T> desiredType) {
214
-        EvaluationContext evaluationContext = getEvaluationContext(rootElement);
215
-        CURRENT_CONTEXT.set(evaluationContext);
216
-        T value = evalExpression(expressionString, evaluationContext, desiredType);
217
-        CURRENT_CONTEXT.set(null);
218
-        return value;
219
-    }
220
-
221
-    /**
222
-     * Evaluates a SpEL expression `expressionString` in the provided
223
-     * context `evaluationContext` and gives back a result of type
224
-     * `desiredType`.
225
-     * @param <T>   The type of the result desired.
226
-     * @param expressionString  The SpEL expression to evaluate.
227
-     * @param evaluationContext The context in which the expression is to be evaluated.
228
-     * @param desiredType   The class of the result desired.
229
-     * @return  The result of the evaluation of the expression.
230
-     * @see ExpressionParser#parseExpression(String)
231
-     * @see Expression#getValue(EvaluationContext, Class)
232
-     */
233
-    public <T> T evalExpression(final String expressionString,
234
-            final EvaluationContext evaluationContext, final Class<T> desiredType) {
235
-        return PARSER.parseExpression(expressionString)
236
-                    .getValue(evaluationContext, desiredType);
237
-    }
238
-
239
-    /**
240
-     * Evaluates multiple SpEL expressions and returns the result of the last
241
-     * expression.
242
-     * @param <T>   The type of the result desired.
243
-     * @param expressionStrings  The SpEL expressions to evaluate.
244
-     * @param rootElement   The root element in context of which the expressions
245
-     * are to be evaluated.
246
-     * @param desiredType   The class of the result desired.
247
-     * @return  The result of the evaluation of the last expression.
248
-     * @see SpelHelper#evalExpression(String, EvaluationContext, Class)
249
-     * @see SpelHelper#evalExpression(String, Object, Class)
250
-     */
251
-    public <T> T evalExpressions(final String[] expressionStrings,
252
-            final Object rootElement, final Class<T> desiredType) {
253
-        return evalExpressions(
254
-                expressionStrings, getEvaluationContext(rootElement), desiredType);
255
-    }
256
-
257
-    /**
258
-     * Evaluates multiple SpEL expressions and returns the result of the last
259
-     * expression.
260
-     * @param <T>   The type of the result desired.
261
-     * @param expressionStrings  The SpEL expressions to evaluate.
262
-     * @param evaluationContext The context in which the expression is to be evaluated.
263
-     * @param desiredType   The class of the result desired.
264
-     * @return  The result of the evaluation of the last expression.
265
-     * @see SpelHelper#evalExpression(String, EvaluationContext, Class)
266
-     * @see SpelHelper#evalExpression(String, Object, Class)
267
-     */
268
-    public <T> T evalExpressions(final String[] expressionStrings,
269
-            final EvaluationContext evaluationContext, final Class<T> desiredType) {
270
-        int length = expressionStrings.length;
271
-        Assert.isTrue(length > 0,
272
-                "expressionStrings should have length more than 0");
273
-        for (int i = 0; i < length - 1; i++) {
274
-            evalExpression(expressionStrings[i], evaluationContext, Object.class);
275
-        }
276
-        return evalExpression(expressionStrings[length - 1],
277
-                evaluationContext, desiredType);
278
-    }
279
-
280
-    private EvaluationContext getEvaluationContext(final Object rootObject) {
281
-        StandardEvaluationContext newContext = new StandardEvaluationContext(rootObject);
282
-        newContext.getMethodResolvers().add(new ImplicitMethodResolver());
283
-        newContext.getPropertyAccessors().add(new ImplicitPropertyAccessor());
284
-        newContext.setConstructorResolvers(
285
-                asList((ConstructorResolver) new ImplicitConstructorResolver()));
286
-        for (Method method : registeredFunctions) {
287
-            newContext.setVariable(method.getName(), method);
288
-        }
289
-        newContext.setVariable(CONTEXT_LOOKUP_KEY, this);
290
-        return newContext;
291
-    }
292
-
293
-    /**
294
-     * Looks up an implicit method registered with this instance.
295
-     * @param lookup    key to lookup which should be of form:
296
-     * `method.getParameterTypes()[0].getName() + "." + method.getName()`
297
-     * @return  The registered method if found, else null.
298
-     */
299
-    public Method lookupImplicitMethod(final String lookup) {
300
-        Assert.notNull(lookup);
301
-        return registeredMethods.get(lookup);
302
-    }
303
-
304
-    /**
305
-     * Looks up an implicit constructor registered with this instance.
306
-     * @param lookup    key to lookup which should be of form:
307
-     * `constructor.getDeclaringClass().getSimpleName()`
308
-     * `+ Arrays.toString(constructor.getParameterTypes())`
309
-     * @return  The registered constructor if found, else null.
310
-     */
311
-    public Constructor<?> lookupImplicitConstructor(final String lookup) {
312
-        Assert.notNull(lookup);
313
-        return registeredConstructors.get(lookup);
314
-    }
315
-
316
-    /**
317
-     * Returns the current evaluation context. Null if there is no context.
318
-     * @return  The current evaluation context.
319
-     */
320
-    public static EvaluationContext getCurrentContext() {
321
-        return CURRENT_CONTEXT.get();
322
-    }
323
-
324
-    private static List<Method> filterMethods(final Class<?> clazz) {
325
-        List<Method> allowedMethods = new ArrayList<Method>();
326
-        for (Method method : clazz.getMethods()) {
327
-            int modifiers = method.getModifiers();
328
-            if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
329
-                    && !method.getReturnType().equals(Void.TYPE)
330
-                    && method.getParameterTypes().length > 0) {
331
-                allowedMethods.add(method);
332
-            }
333
-        }
334
-        return allowedMethods;
335
-    }
336
-
337
-    private static List<Method> filterFunctions(final Class<?> clazz) {
338
-        List<Method> allowedMethods = new ArrayList<Method>();
339
-        for (Method method : clazz.getMethods()) {
340
-            int modifiers = method.getModifiers();
341
-            if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
342
-                    && !method.getReturnType().equals(Void.TYPE)) {
343
-                allowedMethods.add(method);
344
-            }
345
-        }
346
-        return allowedMethods;
347
-    }
348
-
349
-}
1
+/* Copyright 2010 Abhinav Sarkar <abhinav@abhinavsarkar.net>
2
+ *
3
+ * This file is a part of SpelHelper library.
4
+ *
5
+ * SpelHelper library is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Lesser General Public License (GNU LGPL) as
7
+ * published by the Free Software Foundation, either version 3 of the License,
8
+ * or (at your option) any later version.
9
+ *
10
+ * SpelHelper library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU Lesser General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU Lesser General Public License
16
+ *  along with SpelHelper library.  If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+package net.abhinavsarkar.spelhelper;
19
+
20
+import static java.util.Arrays.asList;
21
+
22
+import java.lang.reflect.Constructor;
23
+import java.lang.reflect.Method;
24
+import java.lang.reflect.Modifier;
25
+import java.util.ArrayList;
26
+import java.util.Arrays;
27
+import java.util.HashSet;
28
+import java.util.List;
29
+import java.util.Map;
30
+import java.util.Set;
31
+import java.util.concurrent.ConcurrentHashMap;
32
+
33
+import org.springframework.expression.ConstructorResolver;
34
+import org.springframework.expression.EvaluationContext;
35
+import org.springframework.expression.Expression;
36
+import org.springframework.expression.ExpressionParser;
37
+import org.springframework.expression.spel.standard.SpelExpressionParser;
38
+import org.springframework.expression.spel.support.StandardEvaluationContext;
39
+import org.springframework.util.Assert;
40
+
41
+/**
42
+ * SpelHelper provides additional functionalities to work with
43
+ * [Spring Expression Language (SpEL)][1].
44
+ *
45
+ * The addition functionalities provided are:
46
+ *
47
+ * 1. Implicit methods
48
+ * 2. Implicit properties
49
+ * 3. Simplified extension functions
50
+ * 4. Simplified constructors
51
+ *
52
+ * **Implicit Methods**
53
+ *
54
+ * Implicit methods allow one to registers methods with SpelHelper and attach
55
+ * them to particular classes. After that, when that method is called on an
56
+ * object of that particular class inside a SpEL expression, SpelHelper
57
+ * redirects the method call to the registered method.
58
+ *
59
+ * Example: {@link ImplicitMethods#sorted(List)} method is automatically
60
+ * registered by SpelHelper. The class that the method should be invoked for
61
+ * is the type of the first parameter of the method. In this case, the class is
62
+ * {@link List}.
63
+ *
64
+ * So when an expression like `"#list(1,4,2).sorted()"` is evaluated, the
65
+ * {@link ImplicitMethods#sorted(List)} method is invoked with the list as its
66
+ * first parameter and its return value is used in further evaluation of the
67
+ * expression.
68
+ *
69
+ * See {@link SpelHelper#registerImplicitMethodsFromClass(Class)}.
70
+ *
71
+ * **Implicit Properties**
72
+ *
73
+ * Implicit properties allow one to treat no argument methods of an object
74
+ * as properties of the object. SpelHelper intercepts the property resolution
75
+ * of SpEL and if the property name is same as some no-arg method of the target
76
+ * object then it invokes the method on the object and provides its return value
77
+ * as the property value for further evaluation of the expression.
78
+ *
79
+ * Example: Using implicit properties, the example of implicit methods can be
80
+ * written as: `"#list(1,4,2).sorted"` - dropping the parens - and it will return
81
+ * the same value as the last example.
82
+ *
83
+ * Implicit property resolution considers both the actual methods of the object
84
+ * and the implicit methods registered on the object's class.
85
+ *
86
+ * **Simplified extension functions**
87
+ *
88
+ * SpEL [allows][2] to register extension function on the context by providing a
89
+ * name and a {@link Method} object. SpelHelper simplifies this by taking a class
90
+ * and registering all the `public static` methods of the class which do not
91
+ * have a `void` return type. The methods are registered by their simple name.
92
+ *
93
+ * Example: All the methods of {@link ExtensionFunctions} class are automatically
94
+ * registered by SpelHelper. Hence the method {@link ExtensionFunctions#list(Object...)}
95
+ * can be called from inside a SpEL expression using the function call syntax:
96
+ * `"#list(1,2,3)`".
97
+ *
98
+ * See {@link SpelHelper#registerFunctionsFromClass(Class)}.
99
+ *
100
+ * **Simplified constructors**
101
+ *
102
+ * SpEL [allows][3] calling constructors from inside a SpEL expression using the
103
+ * `new` operator. But they have to be called with their full name like:
104
+ * `"new org.example.Foo('bar')"`. SpelHelper simplifies this by taking a class
105
+ * and registering all its public constructors to the SpEL context by their
106
+ * simple name.
107
+ *
108
+ * Example: After registering the `org.example.Foo` class with SpelHelper, its
109
+ * constructor can be called from inside a SpEL expression by: `"new Foo('bar')"`.
110
+ *
111
+ * See {@link SpelHelper#registerConstructorsFromClass(Class)}.
112
+ *
113
+ * In addition to all the above functionalities, SpelHelper automatically registers
114
+ * some extension functions and implicit methods which are always available in
115
+ * the SpEL expressions evaluated through SpelHelper. See {@link ExtensionFunctions}
116
+ * and {@link ImplicitMethods} for further details.
117
+ *
118
+ * [1]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html
119
+ * [2]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#expressions-ref-functions
120
+ * [3]: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html#d0e11927
121
+ *
122
+ * @author Abhinav Sarkar _abhinav@abhinavsarkar.net_
123
+ */
124
+public final class SpelHelper {
125
+
126
+    static final String CONTEXT_LOOKUP_KEY = SpelHelper.class.getName();
127
+
128
+    private final ExpressionParser PARSER = new SpelExpressionParser();
129
+    private static final ThreadLocal<EvaluationContext> CURRENT_CONTEXT =
130
+        new ThreadLocal<EvaluationContext>();
131
+
132
+    private final Set<Method> registeredFunctions = new HashSet<Method>();
133
+    private final Map<String,Method> registeredMethods =
134
+        new ConcurrentHashMap<String, Method>();
135
+    private final Map<String,Constructor<?>> registeredConstructors =
136
+        new ConcurrentHashMap<String, Constructor<?>>();
137
+
138
+    /**
139
+     * Creates an instance of SpelHelper.
140
+     */
141
+    public SpelHelper() {
142
+        registerFunctionsFromClass(ExtensionFunctions.class);
143
+        registerImplicitMethodsFromClass(ImplicitMethods.class);
144
+    }
145
+
146
+    /**
147
+     * Registers the public static methods in the class `clazz` as implicit
148
+     * methods for the class of the first parameter of the methods.
149
+     *
150
+     * Only registers the public static methods with non void return type and at
151
+     * least one argument.
152
+     * @see ImplicitMethods
153
+     * @param clazz The class to register the methods from.
154
+     * @return      The current instance of SpelHelper. This is for chaining
155
+     * the methods calls.
156
+     */
157
+    public SpelHelper registerImplicitMethodsFromClass(final Class<?> clazz) {
158
+        for (Method method : filterMethods(clazz)) {
159
+            registeredMethods.put(String.format(
160
+                    "%s.%s", method.getParameterTypes()[0].getName(), method.getName()),
161
+                    method);
162
+        }
163
+        return this;
164
+    }
165
+
166
+    /**
167
+     * Registers the public static methods in the class `clazz` as functions
168
+     * which can be called from SpEL expressions.
169
+     * The functions are registered with the simple name of the methods.
170
+     *
171
+     * Only registers the public static methods with non void return type.
172
+     * @see ExtensionFunctions
173
+     * @param clazz The class to register the functions from.
174
+     * @return      The current instance of SpelHelper. This is for chaining
175
+     * the methods calls.
176
+     */
177
+    public SpelHelper registerFunctionsFromClass(final Class<?> clazz) {
178
+        registeredFunctions.addAll(filterFunctions(clazz));
179
+        return this;
180
+    }
181
+
182
+    /**
183
+     * Registers the public constructors of the class `clazz` so that they
184
+     * can be called by their simple name from SpEL expressions.
185
+     * @param clazz The class to register the constructors from.
186
+     * @return      The current instance of SpelHelper. This is for chaining
187
+     * the methods calls.
188
+     */
189
+    public SpelHelper registerConstructorsFromClass(final Class<?> clazz) {
190
+        for (Constructor<?> constructor : asList(clazz.getConstructors())) {
191
+            registeredConstructors.put(
192
+                    constructor.getDeclaringClass().getSimpleName()
193
+                        + Arrays.toString(constructor.getParameterTypes()),
194
+                    constructor);
195
+        }
196
+        return this;
197
+    }
198
+
199
+    /**
200
+     * Evaluates a SpEL expression `expressionString` in the context
201
+     * of root element `rootElement` and gives back a result of type
202
+     * `desiredType`.
203
+     * @param <T>   The type of the result desired.
204
+     * @param expressionString  The SpEL expression to evaluate.
205
+     * @param rootElement   The root element in context of which the expression
206
+     * is to be evaluated.
207
+     * @param desiredType   The class of the result desired.
208
+     * @return  The result of the evaluation of the expression.
209
+     * @see ExpressionParser#parseExpression(String)
210
+     * @see Expression#getValue(EvaluationContext, Class)
211
+     */
212
+    public <T> T evalExpression(final String expressionString,
213
+            final Object rootElement, final Class<T> desiredType) {
214
+        EvaluationContext evaluationContext = getEvaluationContext(rootElement);
215
+        CURRENT_CONTEXT.set(evaluationContext);
216
+        T value = evalExpression(expressionString, evaluationContext, desiredType);
217
+        CURRENT_CONTEXT.set(null);
218
+        return value;
219
+    }
220
+
221
+    /**
222
+     * Evaluates a SpEL expression `expressionString` in the provided
223
+     * context `evaluationContext` and gives back a result of type
224
+     * `desiredType`.
225
+     * @param <T>   The type of the result desired.
226
+     * @param expressionString  The SpEL expression to evaluate.
227
+     * @param evaluationContext The context in which the expression is to be evaluated.
228
+     * @param desiredType   The class of the result desired.
229
+     * @return  The result of the evaluation of the expression.
230
+     * @see ExpressionParser#parseExpression(String)
231
+     * @see Expression#getValue(EvaluationContext, Class)
232
+     */
233
+    public <T> T evalExpression(final String expressionString,
234
+            final EvaluationContext evaluationContext, final Class<T> desiredType) {
235
+        return PARSER.parseExpression(expressionString)
236
+                    .getValue(evaluationContext, desiredType);
237
+    }
238
+
239
+    /**
240
+     * Evaluates multiple SpEL expressions and returns the result of the last
241
+     * expression.
242
+     * @param <T>   The type of the result desired.
243
+     * @param expressionStrings  The SpEL expressions to evaluate.
244
+     * @param rootElement   The root element in context of which the expressions
245
+     * are to be evaluated.
246
+     * @param desiredType   The class of the result desired.
247
+     * @return  The result of the evaluation of the last expression.
248
+     * @see SpelHelper#evalExpression(String, EvaluationContext, Class)
249
+     * @see SpelHelper#evalExpression(String, Object, Class)
250
+     */
251
+    public <T> T evalExpressions(final String[] expressionStrings,
252
+            final Object rootElement, final Class<T> desiredType) {
253
+        return evalExpressions(
254
+                expressionStrings, getEvaluationContext(rootElement), desiredType);
255
+    }
256
+
257
+    /**
258
+     * Evaluates multiple SpEL expressions and returns the result of the last
259
+     * expression.
260
+     * @param <T>   The type of the result desired.
261
+     * @param expressionStrings  The SpEL expressions to evaluate.
262
+     * @param evaluationContext The context in which the expression is to be evaluated.
263
+     * @param desiredType   The class of the result desired.
264
+     * @return  The result of the evaluation of the last expression.
265
+     * @see SpelHelper#evalExpression(String, EvaluationContext, Class)
266
+     * @see SpelHelper#evalExpression(String, Object, Class)
267
+     */
268
+    public <T> T evalExpressions(final String[] expressionStrings,
269
+            final EvaluationContext evaluationContext, final Class<T> desiredType) {
270
+        int length = expressionStrings.length;
271
+        Assert.isTrue(length > 0,
272
+                "expressionStrings should have length more than 0");
273
+        for (int i = 0; i < length - 1; i++) {
274
+            evalExpression(expressionStrings[i], evaluationContext, Object.class);
275
+        }
276
+        return evalExpression(expressionStrings[length - 1],
277
+                evaluationContext, desiredType);
278
+    }
279
+
280
+    private EvaluationContext getEvaluationContext(final Object rootObject) {
281
+        StandardEvaluationContext newContext = new StandardEvaluationContext(rootObject);
282
+        newContext.getMethodResolvers().add(new ImplicitMethodResolver());
283
+        newContext.getPropertyAccessors().add(new ImplicitPropertyAccessor());
284
+        newContext.setConstructorResolvers(
285
+                asList((ConstructorResolver) new ImplicitConstructorResolver()));
286
+        for (Method method : registeredFunctions) {
287
+            newContext.setVariable(method.getName(), method);
288
+        }
289
+        newContext.setVariable(CONTEXT_LOOKUP_KEY, this);
290
+        return newContext;
291
+    }
292
+
293
+    /**
294
+     * Looks up an implicit method registered with this instance.
295
+     * @param lookup    key to lookup which should be of form:
296
+     * `method.getParameterTypes()[0].getName() + "." + method.getName()`
297
+     * @return  The registered method if found, else null.
298
+     */
299
+    public Method lookupImplicitMethod(final String lookup) {
300
+        Assert.notNull(lookup);
301
+        return registeredMethods.get(lookup);
302
+    }
303
+
304
+    /**
305
+     * Looks up an implicit constructor registered with this instance.
306
+     * @param lookup    key to lookup which should be of form:
307
+     * `constructor.getDeclaringClass().getSimpleName()`
308
+     * `+ Arrays.toString(constructor.getParameterTypes())`
309
+     * @return  The registered constructor if found, else null.
310
+     */
311
+    public Constructor<?> lookupImplicitConstructor(final String lookup) {
312
+        Assert.notNull(lookup);
313
+        return registeredConstructors.get(lookup);
314
+    }
315
+
316
+    /**
317
+     * Returns the current evaluation context. Null if there is no context.
318
+     * @return  The current evaluation context.
319
+     */
320
+    public static EvaluationContext getCurrentContext() {
321
+        return CURRENT_CONTEXT.get();
322
+    }
323
+
324
+    private static List<Method> filterMethods(final Class<?> clazz) {
325
+        List<Method> allowedMethods = new ArrayList<Method>();
326
+        for (Method method : clazz.getMethods()) {
327
+            int modifiers = method.getModifiers();
328
+            if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
329
+                    && !method.getReturnType().equals(Void.TYPE)
330
+                    && method.getParameterTypes().length > 0) {
331
+                allowedMethods.add(method);
332
+            }
333
+        }
334
+        return allowedMethods;
335
+    }
336
+
337
+    private static List<Method> filterFunctions(final Class<?> clazz) {
338
+        List<Method> allowedMethods = new ArrayList<Method>();
339
+        for (Method method : clazz.getMethods()) {
340
+            int modifiers = method.getModifiers();
341
+            if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
342
+                    && !method.getReturnType().equals(Void.TYPE)) {
343
+                allowedMethods.add(method);
344
+            }
345
+        }
346
+        return allowedMethods;
347
+    }
348
+
349
+}

+ 36
- 36
src/test/java/net/abhinavsarkar/spelhelper/Functions.java View File

@@ -1,36 +1,36 @@
1
-package net.abhinavsarkar.spelhelper;
2
-
3
-public final class Functions {
4
-
5
-    public static String test(final String str) {
6
-        return str;
7
-    }
8
-
9
-    static String testNonPublic(final String str) {
10
-        return str;
11
-    }
12
-
13
-    public String testNonStatic(final String str) {
14
-        return str;
15
-    }
16
-
17
-    public static void testVoid(final String str) {
18
-        return;
19
-    }
20
-
21
-    public static String testNoArg() {
22
-        return "a";
23
-    }
24
-
25
-    public static String testContext(final String str) {
26
-        if (SpelHelper.getCurrentContext() == null) {
27
-            throw new AssertionError();
28
-        }
29
-        return str;
30
-    }
31
-
32
-    @Override
33
-    public boolean equals(final Object o) {
34
-        return o instanceof Functions;
35
-    }
36
-}
1
+package net.abhinavsarkar.spelhelper;
2
+
3
+public final class Functions {
4
+
5
+    public static String test(final String str) {
6
+        return str;
7
+    }
8
+
9
+    static String testNonPublic(final String str) {
10
+        return str;
11
+    }
12
+
13
+    public String testNonStatic(final String str) {
14
+        return str;
15
+    }
16
+
17
+    public static void testVoid(final String str) {
18
+        return;
19
+    }
20
+
21
+    public static String testNoArg() {
22
+        return "a";
23
+    }
24
+
25
+    public static String testContext(final String str) {
26
+        if (SpelHelper.getCurrentContext() == null) {
27
+            throw new AssertionError();
28
+        }
29
+        return str;
30
+    }
31
+
32
+    @Override
33
+    public boolean equals(final Object o) {
34
+        return o instanceof Functions;
35
+    }
36
+}

+ 42
- 42
src/test/scala/net/abhinavsarkar/spelhelper/ExtensionFunctionsSpec.scala View File

@@ -1,42 +1,42 @@
1
-package net.abhinavsarkar.spelhelper
2
-
3
-import org.scalatest.junit.JUnitRunner
4
-import org.junit.runner.RunWith
5
-import org.scalatest.FlatSpec
6
-import org.scalatest.junit.ShouldMatchersForJUnit
7
-import java.util.{Set => JSet, HashSet,
8
-  List => JList, ArrayList,
9
-  Map => JMap, HashMap}
10
-import org.springframework.expression.spel.SpelEvaluationException
11
-
12
-@RunWith(classOf[JUnitRunner])
13
-class ExtensionFunctionsSpec extends FlatSpec with ShouldMatchersForJUnit {
14
-
15
-  "Extension Function 'list'" should "return a java.util.List " in {
16
-    val list: JList[String] = new ArrayList
17
-    List("a", "b", "c") foreach { list add _ }
18
-    new SpelHelper().evalExpression("#list('a','b','c')",
19
-      new {}, classOf[JList[String]]) should equal(list)
20
-  }
21
-
22
-  "Extension Function 'set'" should "return a java.util.Set " in {
23
-    val set: JSet[String] = new HashSet
24
-    List("a", "b", "c") foreach { set add _ }
25
-    new SpelHelper().evalExpression("#set('a','b','c')",
26
-      new {}, classOf[JSet[String]]) should equal(set)
27
-  }
28
-
29
-  "Extension Function 'map'" should "return a java.util.Map " in {
30
-    val map: JMap[String,Int] = new HashMap
31
-    List("a", "b", "c").zipWithIndex.foreach { x => map.put(x._1, x._2) }
32
-    new SpelHelper().evalExpression("#map(#list('a','b','c'),#list(0,1,2))",
33
-      new {}, classOf[JMap[String,Int]]) should equal(map)
34
-  }
35
-
36
-  "Extension Function 'map'" should "throw SpelEvaluationException " +
37
-          "if length of key and values lists is not same " in {
38
-    evaluating { new SpelHelper().evalExpression("#map(#list('a','b','c'),#list(1,2))",
39
-      new {}, classOf[JMap[String,Int]]) } should produce [SpelEvaluationException]
40
-  }
41
-
42
-}
1
+package net.abhinavsarkar.spelhelper
2
+
3
+import org.scalatest.junit.JUnitRunner
4
+import org.junit.runner.RunWith
5
+import org.scalatest.FlatSpec
6
+import org.scalatest.junit.ShouldMatchersForJUnit
7
+import java.util.{Set => JSet, HashSet,
8
+  List => JList, ArrayList,
9
+  Map => JMap, HashMap}
10
+import org.springframework.expression.spel.SpelEvaluationException
11
+
12
+@RunWith(classOf[JUnitRunner])
13
+class ExtensionFunctionsSpec extends FlatSpec with ShouldMatchersForJUnit {
14
+
15
+  "Extension Function 'list'" should "return a java.util.List " in {
16
+    val list: JList[String] = new ArrayList
17
+    List("a", "b", "c") foreach { list add _ }
18
+    new SpelHelper().evalExpression("#list('a','b','c')",
19
+      new {}, classOf[JList[String]]) should equal(list)
20
+  }
21
+
22
+  "Extension Function 'set'" should "return a java.util.Set " in {
23
+    val set: JSet[String] = new HashSet
24
+    List("a", "b", "c") foreach { set add _ }
25
+    new SpelHelper().evalExpression("#set('a','b','c')",
26
+      new {}, classOf[JSet[String]]) should equal(set)
27
+  }
28
+
29
+  "Extension Function 'map'" should "return a java.util.Map " in {
30
+    val map: JMap[String,Int] = new HashMap
31
+    List("a", "b", "c").zipWithIndex.foreach { x => map.put(x._1, x._2) }
32
+    new SpelHelper().evalExpression("#map(#list('a','b','c'),#list(0,1,2))",
33
+      new {}, classOf[JMap[String,Int]]) should equal(map)
34
+  }
35
+
36
+  "Extension Function 'map'" should "throw SpelEvaluationException " +
37
+          "if length of key and values lists is not same " in {
38
+    evaluating { new SpelHelper().evalExpression("#map(#list('a','b','c'),#list(1,2))",
39
+      new {}, classOf[JMap[String,Int]]) } should produce [SpelEvaluationException]
40
+  }
41
+
42
+}

+ 52
- 52
src/test/scala/net/abhinavsarkar/spelhelper/ImplicitMethodsSpec.scala View File

@@ -1,52 +1,52 @@
1
-package net.abhinavsarkar.spelhelper
2
-
3
-import org.scalatest.junit.JUnitRunner
4
-import org.junit.runner.RunWith
5
-import org.scalatest.FlatSpec
6
-import org.scalatest.junit.ShouldMatchersForJUnit
7
-import java.util.{HashSet, Set => JSet, List => JList, ArrayList}
8
-
9
-@RunWith(classOf[JUnitRunner])
10
-class ImplicitMethodsSpec extends FlatSpec with ShouldMatchersForJUnit {
11
-
12
-  "Implicit Function 'distinct' on List" should
13
-      "return distinct items in a list " in {
14
-    val set: JSet[String] = new HashSet
15
-    set add "a"; set add "b"
16
-    new SpelHelper().evalExpression("#list('a','b','a').distinct()",
17
-      new {}, classOf[JSet[String]]) should equal(set)
18
-  }
19
-
20
-  "Implicit Function 'sorted' on List" should
21
-      "return a sorted list " in {
22
-    val list: JList[String] = new ArrayList
23
-    List("a", "b", "c") foreach { list add _ }
24
-    new SpelHelper().evalExpression("#list('c','b','a').sorted()",
25
-      new {}, classOf[JList[String]]) should equal(list)
26
-  }
27
-
28
-  "Implicit Function 'reversed' on List" should
29
-      "return a reversed list " in {
30
-    val list: JList[String] = new ArrayList
31
-    List("a", "b", "c") foreach { list add _ }
32
-    new SpelHelper().evalExpression("#list('c','b','a').reversed()",
33
-      new {}, classOf[JList[String]]) should equal(list)
34
-  }
35
-
36
-  "Implicit Function 'take' on List" should
37
-      "return a list containing first n items of a list " in {
38
-    val list: JList[String] = new ArrayList
39
-    List("a", "b", "c") foreach { list add _ }
40
-    new SpelHelper().evalExpression("#list('a','b','c','d').take(3)",
41
-      new {}, classOf[JList[String]]) should equal(list)
42
-  }
43
-
44
-  "Implicit Function 'drop' on List" should
45
-      "return a list containing items after the first n items of a list " in {
46
-    val list: JList[String] = new ArrayList
47
-    List("c", "d") foreach { list add _ }
48
-    new SpelHelper().evalExpression("#list('a','b','c','d').drop(2)",
49
-      new {}, classOf[JList[String]]) should equal(list)
50
-  }
51
-  
52
-}
1
+package net.abhinavsarkar.spelhelper
2
+
3
+import org.scalatest.junit.JUnitRunner
4
+import org.junit.runner.RunWith
5
+import org.scalatest.FlatSpec
6
+import org.scalatest.junit.ShouldMatchersForJUnit
7
+import java.util.{HashSet, Set => JSet, List => JList, ArrayList}
8
+
9
+@RunWith(classOf[JUnitRunner])
10
+class ImplicitMethodsSpec extends FlatSpec with ShouldMatchersForJUnit {
11
+
12
+  "Implicit Function 'distinct' on List" should
13
+      "return distinct items in a list " in {
14
+    val set: JSet[String] = new HashSet
15
+    set add "a"; set add "b"
16
+    new SpelHelper().evalExpression("#list('a','b','a').distinct()",
17
+      new {}, classOf[JSet[String]]) should equal(set)
18
+  }
19
+
20
+  "Implicit Function 'sorted' on List" should
21
+      "return a sorted list " in {
22
+    val list: JList[String] = new ArrayList
23
+    List("a", "b", "c") foreach { list add _ }
24
+    new SpelHelper().evalExpression("#list('c','b','a').sorted()",
25
+      new {}, classOf[JList[String]]) should equal(list)
26
+  }
27
+
28
+  "Implicit Function 'reversed' on List" should
29
+      "return a reversed list " in {
30
+    val list: JList[String] = new ArrayList
31
+    List("a", "b", "c") foreach { list add _ }
32
+    new SpelHelper().evalExpression("#list('c','b','a').reversed()",
33
+      new {}, classOf[JList[String]]) should equal(list)
34
+  }
35
+
36
+  "Implicit Function 'take' on List" should
37
+      "return a list containing first n items of a list " in {
38
+    val list: JList[String] = new ArrayList
39
+    List("a", "b", "c") foreach { list add _ }
40
+    new SpelHelper().evalExpression("#list('a','b','c','d').take(3)",
41
+      new {}, classOf[JList[String]]) should equal(list)
42
+  }
43
+
44
+  "Implicit Function 'drop' on List" should
45
+      "return a list containing items after the first n items of a list " in {
46
+    val list: JList[String] = new ArrayList
47
+    List("c", "d") foreach { list add _ }
48
+    new SpelHelper().evalExpression("#list('a','b','c','d').drop(2)",
49
+      new {}, classOf[JList[String]]) should equal(list)
50
+  }
51
+  
52
+}

+ 103
- 103
src/test/scala/net/abhinavsarkar/spelhelper/SpelHelperSpec.scala View File

@@ -1,103 +1,103 @@
1
-package net.abhinavsarkar.spelhelper
2
-
3
-import org.scalatest.junit.JUnitRunner
4
-import org.junit.runner.RunWith
5
-import org.scalatest.FlatSpec
6
-import org.scalatest.junit.ShouldMatchersForJUnit
7
-import org.springframework.expression.spel.SpelEvaluationException
8
-
9
-@RunWith(classOf[JUnitRunner])
10
-class SpelHelperSpec extends FlatSpec with ShouldMatchersForJUnit {
11
-
12
-  "SpelHelper" should "register and evaluate functions " in {
13
-    new SpelHelper()
14
-      .registerFunctionsFromClass(classOf[Functions])
15
-      .evalExpression(
16
-        "#test('check')", new {}, classOf[String]) should equal ("check")
17
-  }
18
-
19
-  it should "not register non public methods " in {
20
-    val spelHelper = new SpelHelper()
21
-      .registerFunctionsFromClass(classOf[Functions])
22
-    evaluating { spelHelper.evalExpression("#testNonPublic('check')",
23
-      new {}, classOf[String]) } should produce [SpelEvaluationException]
24
-  }
25
-
26
-  it should "not register non static methods " in {
27
-    val spelHelper = new SpelHelper()
28
-      .registerFunctionsFromClass(classOf[Functions])
29
-    evaluating { spelHelper.evalExpression("#testNonStatic('check')",
30
-      new {}, classOf[String]) } should produce [SpelEvaluationException]
31
-  }
32
-
33
-  it should "not register void methods " in {
34
-    val spelHelper = new SpelHelper()
35
-      .registerFunctionsFromClass(classOf[Functions])
36
-    evaluating { spelHelper.evalExpression("#testVoid('check')",
37
-      new {}, classOf[String]) } should produce [SpelEvaluationException]
38
-  }
39
-
40
-  it should "register implicit methods " in {
41
-    new SpelHelper()
42
-      .registerImplicitMethodsFromClass(classOf[Functions])
43
-      .lookupImplicitMethod("java.lang.String.test") should equal(
44
-        classOf[Functions].getMethod("test", classOf[String]))
45
-  }
46
-
47
-  it should "not register methods with no args as implicit methods " in {
48
-    new SpelHelper()
49
-      .registerImplicitMethodsFromClass(classOf[Functions])
50
-      .lookupImplicitMethod("java.lang.String.testNoArg") should be (null);
51
-  }
52
-
53
-  it should "register implicit constructors " in {
54
-    new SpelHelper()
55
-      .registerConstructorsFromClass(classOf[Functions])
56
-      .lookupImplicitConstructor("Functions[]") should equal(
57
-        classOf[Functions].getConstructor())
58
-  }
59
-
60
-  it should "evaluate implicit methods " in {
61
-    new SpelHelper()
62
-      .registerImplicitMethodsFromClass(classOf[Functions])
63
-      .evalExpression(
64
-        "'check'.test()", new {}, classOf[String]) should equal ("check")
65
-  }
66
-
67
-  it should "evaluate implicit constructors " in {
68
-    new SpelHelper()
69
-      .registerConstructorsFromClass(classOf[Functions])
70
-      .evalExpression(
71
-        "new Functions()", new {}, classOf[Functions]) should equal (new Functions)
72
-  }
73
-
74
-  it should "evaluate implicit properties " in {
75
-    new SpelHelper().evalExpression(
76
-      "'abc'.hashCode", new {}, classOf[int]) should equal ("abc".hashCode)
77
-  }
78
-
79
-  it should "evaluate multiple expressions " in {
80
-    new SpelHelper().evalExpressions(
81
-      Array("#s='check'", "#s"), new {}, classOf[String]) should equal ("check")
82
-  }
83
-
84
-  it should "throw IllegalArgumentException when trying to evaluate " +
85
-          "blank multiple expressions " in {
86
-    evaluating { new SpelHelper().evalExpressions(
87
-      Array[String](), new {}, classOf[String]) } should produce [IllegalArgumentException]
88
-  }
89
-
90
-  it should "return evaluation context inside a method called " +
91
-          "from SpEL expression " in {
92
-    new SpelHelper()
93
-      .registerFunctionsFromClass(classOf[Functions])
94
-      .evalExpression(
95
-        "#testContext('check')", new {}, classOf[String]) should equal ("check")
96
-  }
97
-
98
-  it should "not return evaluation context outside a method called " +
99
-          "from SpEL expression " in {
100
-    SpelHelper.getCurrentContext should be (null)
101
-  }
102
-  
103
-}
1
+package net.abhinavsarkar.spelhelper
2
+
3
+import org.scalatest.junit.JUnitRunner
4
+import org.junit.runner.RunWith
5
+import org.scalatest.FlatSpec
6
+import org.scalatest.junit.ShouldMatchersForJUnit
7
+import org.springframework.expression.spel.SpelEvaluationException
8
+
9
+@RunWith(classOf[JUnitRunner])
10
+class SpelHelperSpec extends FlatSpec with ShouldMatchersForJUnit {
11
+
12
+  "SpelHelper" should "register and evaluate functions " in {
13
+    new SpelHelper()
14
+      .registerFunctionsFromClass(classOf[Functions])
15
+      .evalExpression(
16
+        "#test('check')", new {}, classOf[String]) should equal ("check")
17
+  }
18
+
19
+  it should "not register non public methods " in {
20
+    val spelHelper = new SpelHelper()
21
+      .registerFunctionsFromClass(classOf[Functions])
22
+    evaluating { spelHelper.evalExpression("#testNonPublic('check')",
23
+      new {}, classOf[String]) } should produce [SpelEvaluationException]
24
+  }
25
+
26
+  it should "not register non static methods " in {
27
+    val spelHelper = new SpelHelper()
28
+      .registerFunctionsFromClass(classOf[Functions])
29
+    evaluating { spelHelper.evalExpression("#testNonStatic('check')",
30
+      new {}, classOf[String]) } should produce [SpelEvaluationException]
31
+  }
32
+
33
+  it should "not register void methods " in {
34
+    val spelHelper = new SpelHelper()
35
+      .registerFunctionsFromClass(classOf[Functions])
36
+    evaluating { spelHelper.evalExpression("#testVoid('check')",
37
+      new {}, classOf[String]) } should produce [SpelEvaluationException]
38
+  }
39
+
40
+  it should "register implicit methods " in {
41
+    new SpelHelper()
42
+      .registerImplicitMethodsFromClass(classOf[Functions])
43
+      .lookupImplicitMethod("java.lang.String.test") should equal(
44
+        classOf[Functions].getMethod("test", classOf[String]))
45
+  }
46
+
47
+  it should "not register methods with no args as implicit methods " in {
48
+    new SpelHelper()
49
+      .registerImplicitMethodsFromClass(classOf[Functions])
50
+      .lookupImplicitMethod("java.lang.String.testNoArg") should be (null);
51
+  }
52
+
53
+  it should "register implicit constructors " in {
54
+    new SpelHelper()
55
+      .registerConstructorsFromClass(classOf[Functions])
56
+      .lookupImplicitConstructor("Functions[]") should equal(
57
+        classOf[Functions].getConstructor())
58
+  }
59
+
60
+  it should "evaluate implicit methods " in {
61
+    new SpelHelper()
62
+      .registerImplicitMethodsFromClass(classOf[Functions])
63
+      .evalExpression(
64
+        "'check'.test()", new {}, classOf[String]) should equal ("check")
65
+  }
66
+
67
+  it should "evaluate implicit constructors " in {
68
+    new SpelHelper()
69
+      .registerConstructorsFromClass(classOf[Functions])
70
+      .evalExpression(
71
+        "new Functions()", new {}, classOf[Functions]) should equal (new Functions)
72
+  }
73
+
74
+  it should "evaluate implicit properties " in {
75
+    new SpelHelper().evalExpression(
76
+      "'abc'.hashCode", new {}, classOf[int]) should equal ("abc".hashCode)
77
+  }
78
+
79
+  it should "evaluate multiple expressions " in {
80
+    new SpelHelper().evalExpressions(
81
+      Array("#s='check'", "#s"), new {}, classOf[String]) should equal ("check")
82
+  }
83
+
84
+  it should "throw IllegalArgumentException when trying to evaluate " +
85
+          "blank multiple expressions " in {
86
+    evaluating { new SpelHelper().evalExpressions(
87
+      Array[String](), new {}, classOf[String]) } should produce [IllegalArgumentException]
88
+  }
89
+
90
+  it should "return evaluation context inside a method called " +
91
+          "from SpEL expression " in {
92
+    new SpelHelper()
93
+      .registerFunctionsFromClass(classOf[Functions])
94
+      .evalExpression(
95
+        "#testContext('check')", new {}, classOf[String]) should equal ("check")
96
+  }
97
+
98
+  it should "not return evaluation context outside a method called " +
99
+          "from SpEL expression " in {
100
+    SpelHelper.getCurrentContext should be (null)
101
+  }
102
+  
103
+}

Loading…
Cancel
Save