View | Details | Raw Unified | Return to bug 49554
Collapse All | Expand All

(-)pom.xml (-1 / +10 lines)
Lines 120-125 Link Here
120
  </dependencies> 
120
  </dependencies> 
121
121
122
  <build>
122
  <build>
123
      <resources>
124
          <resource>
125
              <directory>src/main/java</directory>
126
              <includes>
127
                  <include>**/*.properties</include>
128
              </includes>
129
          </resource>
130
      </resources>
123
    <plugins>
131
    <plugins>
124
      <plugin>
132
      <plugin>
125
        <groupId>org.apache.maven.plugins</groupId>
133
        <groupId>org.apache.maven.plugins</groupId>
Lines 137-143 Link Here
137
          <includes>
145
          <includes>
138
            <include>org/apache/taglibs/standard/lang/jstl/test/StaticFunctionTests.java</include>
146
            <include>org/apache/taglibs/standard/lang/jstl/test/StaticFunctionTests.java</include>
139
            <include>org/apache/taglibs/standard/TestVersion.java</include>
147
            <include>org/apache/taglibs/standard/TestVersion.java</include>
140
            <include>org/apache/taglibs/standard/tag/**/Test*.java</include>
148
            <include>org/apache/taglibs/standard/functions/TestFunctions.java</include>
149
            <include>org/apache/taglibs/standard/tag/common/core/TestSetSupport.java</include>
141
          </includes>
150
          </includes>
142
          <excludes>
151
          <excludes>
143
            <!-- Old tests -->
152
            <!-- Old tests -->
(-)src/test/java/org/apache/taglibs/standard/functions/TestFunctions.java (+114 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.taglibs.standard.functions;
18
19
import org.apache.taglibs.standard.resources.Resources;
20
import org.junit.Assert;
21
import org.junit.Test;
22
23
import javax.servlet.jsp.JspTagException;
24
import java.util.Arrays;
25
import java.util.Collections;
26
27
import static org.apache.taglibs.standard.functions.Functions.*;
28
/**
29
 */
30
public class TestFunctions {
31
32
    @Test
33
    public void testSubstring() {
34
        Assert.assertEquals("el", substring("Hello", 1, 3));
35
        Assert.assertEquals("", substring("Hello", 10, 0));
36
        Assert.assertEquals("He", substring("Hello", -1, 2));
37
        Assert.assertEquals("Hello", substring("Hello", -4, -1));
38
        Assert.assertEquals("ello", substring("Hello", 1, -1));
39
        Assert.assertEquals("ello", substring("Hello", 1, 10));
40
        Assert.assertEquals("", substring("Hello", 3, 1));
41
        Assert.assertEquals("", substring("Hello", 10, 6));
42
        Assert.assertEquals("Hello", substring("Hello", -1, -4));
43
    }
44
45
    @Test
46
    public void testSubstringAfter() {
47
        Assert.assertEquals("lo", substringAfter("Hello", "el"));
48
        Assert.assertEquals("", substringAfter("", "el"));
49
        Assert.assertEquals("Hello", substringAfter("Hello", ""));
50
        Assert.assertEquals("", substringAfter("", "lx"));
51
        Assert.assertEquals("lo All", substringAfter("Hello All", "l"));
52
    }
53
54
    @Test
55
    public void testSubstringBefore() {
56
        Assert.assertEquals("H", substringBefore("Hello", "el"));
57
        Assert.assertEquals("", substringBefore("", "el"));
58
        Assert.assertEquals("", substringBefore("Hello", ""));
59
        Assert.assertEquals("", substringBefore("", "lx"));
60
        Assert.assertEquals("He", substringBefore("Hello All", "l"));
61
    }
62
63
    @Test
64
    public void testReplace() {
65
        Assert.assertEquals("Hxxlo", replace("Hello", "el", "xx"));
66
        Assert.assertEquals("Hexxxxo", replace("Hello", "l", "xx"));
67
        Assert.assertEquals("", replace("", "l", "xx"));
68
        Assert.assertEquals("Heo", replace("Hello", "l", ""));
69
        Assert.assertEquals("Hello", replace("Hello", "", "xx"));
70
        Assert.assertEquals("Hellllo", replace("Hello", "l", "ll"));
71
        Assert.assertEquals("Hello", replace("Hello", "x", "ll"));
72
    }
73
74
    @Test
75
    public void testSplit() {
76
        Assert.assertArrayEquals(new String[]{"a", "b", "c"}, split("a:b:c", ":"));
77
        Assert.assertArrayEquals(new String[]{"a", "b", "c"}, split("a:b/c", ":/"));
78
        Assert.assertArrayEquals(new String[]{"a", "b", "c"}, split("a:b/c", "/:"));
79
        Assert.assertArrayEquals(new String[]{"a", "b"}, split("a:b:", ":"));
80
        Assert.assertArrayEquals(new String[]{"a:b:c"}, split("a:b:c", "x"));
81
        Assert.assertArrayEquals(new String[]{""}, split("", ""));
82
        Assert.assertArrayEquals(new String[]{""}, split("", ":"));
83
        Assert.assertArrayEquals(new String[]{"Hello"}, split("Hello", ""));
84
    }
85
86
    @Test
87
    public void testJoin() {
88
        Assert.assertEquals("a:b:c", join(new String[]{"a", "b", "c"}, ":"));
89
        Assert.assertEquals("abc", join(new String[]{"a", "b", "c"}, ""));
90
        Assert.assertEquals("axxbxxc", join(new String[]{"a", "b", "c"}, "xx"));
91
        Assert.assertEquals("", join(null, ""));
92
        Assert.assertEquals("", join(new String[]{}, ":"));
93
        Assert.assertEquals("a:null:c", join(new String[]{"a", null, "c"}, ":"));
94
        Assert.assertEquals("a", join(new String[]{"a"}, ":"));
95
        Assert.assertEquals("null", join(new String[]{null}, ":"));
96
    }
97
98
    @Test
99
    public void testLength() throws Exception {
100
        Assert.assertEquals(0, length(null));
101
        Assert.assertEquals(0, length(""));
102
        Assert.assertEquals(3, length(new int[]{1,2,3}));
103
        Assert.assertEquals(3, length(Arrays.asList(1,2,3)));
104
        Assert.assertEquals(3, length(Arrays.asList(1,2,3).iterator()));
105
        Assert.assertEquals(3, length(Collections.enumeration(Arrays.asList(1,2,3))));
106
        Assert.assertEquals(1, length(Collections.singletonMap("Hello", "World")));
107
        try {
108
            length(3);
109
            Assert.fail();
110
        } catch (JspTagException e) {
111
            Assert.assertEquals(Resources.getMessage("PARAM_BAD_VALUE"), e.getMessage());
112
        }
113
    }
114
}
(-)src/main/java/org/apache/taglibs/standard/functions/Functions.java (-102 / +210 lines)
Lines 30-36 Link Here
30
import org.apache.taglibs.standard.tag.common.core.Util;
30
import org.apache.taglibs.standard.tag.common.core.Util;
31
31
32
/**
32
/**
33
 * <p>JSTL Functions</p>
33
 * Static functions that extend the Expression Language with standardized behaviour
34
 * commonly used by page authors.
35
 *
36
 * <strong>Implementation Note:</strong> When passing a String parameter, section
37
 * 1.18.2 of the EL specification requires the container to coerce a null value to an
38
 * empty string. These implementation assume such behaviour and do not check for null
39
 * parameters. Passing a null will generally trigger a NullPointerException.
34
 * 
40
 * 
35
 * @author Pierre Delisle
41
 * @author Pierre Delisle
36
 */
42
 */
Lines 41-54 Link Here
41
    // String capitalization
47
    // String capitalization
42
48
43
    /**
49
    /**
44
     * Converts all of the characters of the input string to upper case.
50
     * Converts all of the characters of the input string to upper case according to the
51
     * semantics of method <code>String#toUpperCase()</code>.
52
     *
53
     * @param input the input string on which the transformation to upper case is applied
54
     * @return the input string transformed to upper case
45
     */
55
     */
46
    public static String toUpperCase(String input) {
56
    public static String toUpperCase(String input) {
47
        return input.toUpperCase();
57
        return input.toUpperCase();
48
    }
58
    }
49
59
50
    /**
60
    /**
51
     * Converts all of the characters of the input string to lower case.
61
     * Converts all of the characters of the input string to lower case according to the
62
     * semantics of method <code>String#toLowerCase()</code>.
63
     *
64
     * @param input the input string on which the transformation to lower case is applied
65
     * @return the input string transformed to lower case
52
     */
66
     */
53
    public static String toLowerCase(String input) {
67
    public static String toLowerCase(String input) {
54
        return input.toLowerCase();
68
        return input.toLowerCase();
Lines 56-107 Link Here
56
    
70
    
57
    //*********************************************************************
71
    //*********************************************************************
58
    // Substring processing
72
    // Substring processing
59
    
73
74
    /**
75
     * Returns the index (0-based) withing a string of the first occurrence of a specified
76
     * substring according to the semantics of the method <code>String#indexOf()</code>.
77
     *
78
     * If <code>substring</code> is empty, this matches the beginning of the string and the
79
     * value returned is 0.
80
     *
81
     * @param input the input string on which the function is applied
82
     * @param substring the substring to search for in the input string
83
     * @return the 0-based index of the first matching substring, or -1 if it does not occur
84
     */
60
    public static int indexOf(String input, String substring) {
85
    public static int indexOf(String input, String substring) {
61
        if (input == null) input = "";
62
        if (substring == null) substring = "";
63
        return input.indexOf(substring);
86
        return input.indexOf(substring);
64
    }    
87
    }
65
88
89
    /**
90
     * Tests if a string contains the specified substring.
91
     *
92
     * @param input the input string on which the function is applied
93
     * @param substring the substring tested for
94
     * @return true if the character sequence represented by the substring
95
     * exists in the string
96
     */
66
    public static boolean contains(String input, String substring) {
97
    public static boolean contains(String input, String substring) {
67
        return indexOf(input, substring) != -1;
98
        return input.contains(substring);
68
    }    
99
    }    
69
100
101
    /**
102
     * Tests if a string contains the specified substring in a case insensitive way.
103
     * Equivalent to <code>fn:contains(fn:toUpperCase(string), fn:toUpperCase(substring))</code>.
104
     *
105
     * @param input the input string on which the function is applied
106
     * @param substring the substring tested for
107
     * @return true if the character sequence represented by the substring
108
     * exists in the string
109
     */
70
    public static boolean containsIgnoreCase(String input, String substring) {
110
    public static boolean containsIgnoreCase(String input, String substring) {
71
        if (input == null) input = "";
111
        return contains(input.toUpperCase(), substring.toUpperCase());
72
        if (substring == null) substring = "";        
112
    }
73
        String inputUC = input.toUpperCase();
74
        String substringUC = substring.toUpperCase();
75
        return indexOf(inputUC, substringUC) != -1;
76
    }    
77
113
78
    public static boolean startsWith(String input, String substring) {
114
    /**
79
        if (input == null) input = "";
115
     * Tests if a string starts with the specified prefix according to the semantics
80
        if (substring == null) substring = "";
116
     * of <code>String#startsWith()</code>.
81
        return input.startsWith(substring);
117
     *
118
     * @param input the input string on which the function is applied
119
     * @param prefix the prefix to be matched
120
     * @return true if the input string starts with the prefix
121
     */
122
    public static boolean startsWith(String input, String prefix) {
123
        return input.startsWith(prefix);
82
    }    
124
    }    
83
        
125
        
84
    public static boolean endsWith(String input, String substring) {
126
    /**
85
        if (input == null) input = "";
127
     * Tests if a string ends with the specified suffix according to the semantics
86
        if (substring == null) substring = "";
128
     * of <code>String#endsWith()</code>.
87
        return input.endsWith(substring);
129
     *
88
    }  
130
     * @param input the input string on which the function is applied
89
    
131
     * @param suffix the suffix to be matched
132
     * @return true if the input string ends with the suffix
133
     */
134
    public static boolean endsWith(String input, String suffix) {
135
        return input.endsWith(suffix);
136
    }
137
138
    /**
139
     * Returns a subset of a string according to the semantics of <code>String#substring()</code>
140
     * with additional semantics as follows:
141
     * <ul>
142
     * <li>if <code>beginIndex < 0</code> its value is adjusted to 0</li>
143
     * <li>if <code>endIndex < 0 or greater than the string length</code>,
144
     * its value is adjusted to the length of the string</li>
145
     * <li>if <code>endIndex < beginIndex</code>, an empty string is returned</li>
146
     * </ul>
147
     *
148
     * @param input the input string on which the substring function is applied
149
     * @param beginIndex the beginning index (0-based), inclusive
150
     * @param endIndex the end index (0-based), exclusive
151
     * @return a subset of string
152
     */
90
    public static String substring(String input, int beginIndex, int endIndex) {
153
    public static String substring(String input, int beginIndex, int endIndex) {
91
        if (input == null) input = "";
92
        if (beginIndex >= input.length()) return "";
93
        if (beginIndex < 0) beginIndex = 0;
154
        if (beginIndex < 0) beginIndex = 0;
94
        if (endIndex < 0 || endIndex > input.length()) endIndex = input.length();
155
        if (endIndex < 0 || endIndex > input.length()) endIndex = input.length();
95
        if (endIndex < beginIndex) return "";
156
        if (endIndex < beginIndex) return "";
96
        return input.substring(beginIndex, endIndex);
157
        return input.substring(beginIndex, endIndex);
97
    }    
158
    }
98
    
159
160
    /**
161
     * Returns a subset of a string following the first occurrence of a specific substring.
162
     *
163
     * If the substring is empty, it matches the beginning of the input string and the
164
     * entire input string is returned. If the substring does not occur, an empty string is returned.
165
     *
166
     * @param input the input string on which the substring function is applied
167
     * @param substring the substring that delimits the beginning of the subset
168
     * of the input string to be returned
169
     * @return a substring of the input string that starts at the first character after the specified substring
170
     */
99
    public static String substringAfter(String input, String substring) {
171
    public static String substringAfter(String input, String substring) {
100
        if (input == null) input = "";
101
        if (input.length() == 0) return "";
102
        if (substring == null) substring = "";
103
        if (substring.length() == 0) return input;
104
        
105
        int index = input.indexOf(substring);
172
        int index = input.indexOf(substring);
106
        if (index == -1) {
173
        if (index == -1) {
107
            return "";
174
            return "";
Lines 110-121 Link Here
110
        }
177
        }
111
    }    
178
    }    
112
        
179
        
180
    /**
181
     * Returns a subset of a string immediately before the first occurrence of a specific substring.
182
     *
183
     * If the substring is empty, it matches the beginning of the input string and an empty string is returned.
184
     * If the substring does not occur, an empty string is returned.
185
     *
186
     * @param input the input string on which the substring function is applied
187
     * @param substring the substring that delimits the beginning of the subset
188
     * of the input string to be returned
189
     * @return a substring of the input string that starts at the first character after the specified substring
190
     */
113
    public static String substringBefore(String input, String substring) {
191
    public static String substringBefore(String input, String substring) {
114
        if (input == null) input = "";
115
        if (input.length() == 0) return "";
116
        if (substring == null) substring = "";
117
        if (substring.length() == 0) return "";
118
119
        int index = input.indexOf(substring);
192
        int index = input.indexOf(substring);
120
        if (index == -1) {
193
        if (index == -1) {
121
            return "";
194
            return "";
Lines 126-200 Link Here
126
199
127
    //*********************************************************************
200
    //*********************************************************************
128
    // Character replacement
201
    // Character replacement
129
    
202
203
    /**
204
     * Escapes characters that could be interpreted as XML markup as defined by the <code>&lt;c:out&gt; action.
205
     *
206
     * @param input the string to escape
207
     * @return escaped string
208
     */
130
    public static String escapeXml(String input) {
209
    public static String escapeXml(String input) {
131
        if (input == null) return "";
132
        return Util.escapeXml(input);
210
        return Util.escapeXml(input);
133
    }
211
    }
134
    
212
213
    /**
214
     * removes whitespace from both ends of a string according to the semantics of <code>String#trim()</code>.
215
     *
216
     * @param input the input string to be trimmed
217
     * @return the trimmed string
218
     */
135
    public static String trim(String input) {
219
    public static String trim(String input) {
136
        if (input == null) return "";
137
        return input.trim();
220
        return input.trim();
138
    }    
221
    }
139
222
140
    public static String replace(
223
    /**
141
    String input, 
224
     * Returns a string resulting from replacing all occurrences of a "before" substring with an "after" substring.
142
    String substringBefore,
225
     * The string is processed once and not reprocessed for further replacements.
143
    String substringAfter) 
226
     *
227
     * @param input the string on which the replacement is to be applied
228
     * @param before the substring to replace
229
     * @param after the replacement substring
230
     * @return a string with before replaced with after
231
     */
232
    public static String replace(String input, String before, String after)
144
    {
233
    {
145
        if (input == null) input = "";
234
        if (before.length() == 0) {
146
        if (input.length() == 0) return "";
235
            return input;
147
        if (substringBefore == null) substringBefore = "";
148
        if (substringBefore.length() == 0) return input;
149
                
150
        StringBuffer buf = new StringBuffer(input.length());
151
        int startIndex = 0;
152
        int index;
153
        while ((index = input.indexOf(substringBefore, startIndex)) != -1) {
154
            buf.append(input.substring(startIndex, index)).append(substringAfter);
155
            startIndex = index + substringBefore.length();
156
        }
236
        }
157
        return buf.append(input.substring(startIndex)).toString();
237
        return input.replace(before, after);
158
    }
238
    }
159
    
239
160
    public static String[] split(
240
    /**
161
    String input, 
241
     * Splits a string into an array of substrings according to the semantics of <code>StringTokenizer</code>.
162
    String delimiters) 
242
     * If the input string is empty, a single element array containing an empty string is returned.
243
     * If the delimiters are empty, a single element array containing the input string is returned.
244
     *
245
     * @param input the string to split
246
     * @param delimiters characters used to split the string
247
     * @return an array of strings
248
     */
249
    public static String[] split(String input, String delimiters)
163
    {
250
    {
164
        String[] array;
251
        if (input.length() == 0 || delimiters.length() == 0) {
165
        if (input == null) input = "";
252
            return new String[] { input };
166
        if (input.length() == 0) {
167
            array = new String[1];
168
            array[0] = "";
169
            return array;
170
        }
253
        }
171
        
172
        if (delimiters == null) delimiters = "";
173
254
174
        StringTokenizer tok = new StringTokenizer(input, delimiters);
255
        StringTokenizer tok = new StringTokenizer(input, delimiters);
175
        int count = tok.countTokens();
256
        String[] array = new String[tok.countTokens()];
176
        array = new String[count];
177
        int i = 0;
257
        int i = 0;
178
        while (tok.hasMoreTokens()) {
258
        while (tok.hasMoreTokens()) {
179
            array[i++] = tok.nextToken();
259
            array[i++] = tok.nextToken();
180
        }
260
        }
181
        return array;
261
        return array;
182
    }        
262
    }
183
        
263
264
    /**
265
     * Joins all elements of an array into a string.
266
     *
267
     * <strong>Implementation Note</strong>: The specification does not define what happens when
268
     * elements in the array are null. For compatibility with previous implementations, the string
269
     * "null" is used although EL conventions would suggest an empty string might be better.
270
     *
271
     * @param array an array of strings to be joined
272
     * @param separator used to separate the joined strings
273
     * @return all array elements joined into one string with the specified separator
274
     */
275
    public static String join(String[] array, String separator) {
276
        if (array == null || array.length == 0) {
277
            return "";
278
        }
279
        if (array.length == 1) {
280
            return array[0] == null ? "null" : array[0];
281
        }
282
283
        StringBuilder buf = new StringBuilder();
284
        buf.append(array[0]);
285
        for (int i = 1; i < array.length; i++) {
286
            buf.append(separator).append(array[i]);
287
        }
288
        return buf.toString();
289
    }
290
184
    //*********************************************************************
291
    //*********************************************************************
185
    // Collections processing
292
    // Collections processing
186
    
293
294
    /**
295
     * Returns the number of items in a collection or the number of characters in a string.
296
     * The collection can be of any type supported for the <code>items</code> attribute of
297
     * the <code>&lt;c:forEach&gt;</code> action.
298
     *
299
     * @param obj the collection or string whose length should be computed
300
     * @return the length of the collection or string; 0 if obj is null
301
     * @throws JspTagException if the type is not valid
302
     */
187
    public static int length(Object obj) throws JspTagException {
303
    public static int length(Object obj) throws JspTagException {
188
        if (obj == null) return 0;  
304
        if (obj == null) {
305
            return 0;
306
        }
189
        
307
        
190
        if (obj instanceof String) return ((String)obj).length();
308
        if (obj instanceof String) {
191
        if (obj instanceof Collection) return ((Collection)obj).size();
309
            return ((String) obj).length();
192
        if (obj instanceof Map) return ((Map)obj).size();
310
        }
193
        
311
        if (obj instanceof Collection) {
194
        int count = 0;
312
            return ((Collection) obj).size();
313
        }
314
        if (obj instanceof Map) {
315
            return ((Map) obj).size();
316
        }
195
        if (obj instanceof Iterator) {
317
        if (obj instanceof Iterator) {
318
            int count = 0;
196
            Iterator iter = (Iterator)obj;
319
            Iterator iter = (Iterator)obj;
197
            count = 0;
198
            while (iter.hasNext()) {
320
            while (iter.hasNext()) {
199
                count++;
321
                count++;
200
                iter.next();
322
                iter.next();
Lines 203-232 Link Here
203
        }            
325
        }            
204
        if (obj instanceof Enumeration) {
326
        if (obj instanceof Enumeration) {
205
            Enumeration enum_ = (Enumeration)obj;
327
            Enumeration enum_ = (Enumeration)obj;
206
            count = 0;
328
            int count = 0;
207
            while (enum_.hasMoreElements()) {
329
            while (enum_.hasMoreElements()) {
208
                count++;
330
                count++;
209
                enum_.nextElement();
331
                enum_.nextElement();
210
            }
332
            }
211
            return count;
333
            return count;
212
        }
334
        }
213
        try {
335
        if (obj.getClass().isArray()) {
214
            count = Array.getLength(obj);
336
            return Array.getLength(obj);
215
            return count;
337
        }
216
        } catch (IllegalArgumentException ex) {}
338
        throw new JspTagException(Resources.getMessage("PARAM_BAD_VALUE"));
217
        throw new JspTagException(Resources.getMessage("PARAM_BAD_VALUE"));        
218
    }      
339
    }      
219
220
    public static String join(String[] array, String separator) {
221
        if (array == null) return "";         
222
        if (separator == null) separator = "";
223
        
224
        StringBuffer buf = new StringBuffer();
225
        for (int i=0; i<array.length; i++) {
226
            buf.append(array[i]);
227
            if (i < array.length-1) buf.append(separator);
228
        }
229
        
230
        return buf.toString();
231
    }
232
}
340
}

Return to bug 49554