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

(-)impl/src/test/java/org/apache/taglibs/standard/tag/common/core/TestSetSupport.java (+242 lines)
Lines 16-44 Link Here
16
 */
16
 */
17
package org.apache.taglibs.standard.tag.common.core;
17
package org.apache.taglibs.standard.tag.common.core;
18
18
19
import org.apache.taglibs.standard.resources.Resources;
20
import org.junit.After;
19
import org.junit.Assert;
21
import org.junit.Assert;
20
import org.junit.Before;
22
import org.junit.Before;
21
import org.junit.Test;
23
import org.junit.Test;
22
24
23
import javax.el.ELContext;
25
import javax.el.ELContext;
26
import javax.el.ExpressionFactory;
24
import javax.el.ValueExpression;
27
import javax.el.ValueExpression;
25
import javax.el.VariableMapper;
28
import javax.el.VariableMapper;
29
import javax.servlet.jsp.JspApplicationContext;
26
import javax.servlet.jsp.JspException;
30
import javax.servlet.jsp.JspException;
31
import javax.servlet.jsp.JspFactory;
32
import javax.servlet.jsp.JspTagException;
27
import javax.servlet.jsp.PageContext;
33
import javax.servlet.jsp.PageContext;
28
import javax.servlet.jsp.tagext.BodyContent;
34
import javax.servlet.jsp.tagext.BodyContent;
29
35
36
import java.util.Map;
37
30
import static org.easymock.EasyMock.createMock;
38
import static org.easymock.EasyMock.createMock;
31
import static org.easymock.EasyMock.expect;
39
import static org.easymock.EasyMock.expect;
32
import static org.easymock.EasyMock.replay;
40
import static org.easymock.EasyMock.replay;
33
import static org.easymock.EasyMock.verify;
41
import static org.easymock.EasyMock.verify;
34
42
35
public class TestSetSupport {
43
public class TestSetSupport {
44
    private static String PROPERTY = "property";
36
    private static String VALUE = "Hello";
45
    private static String VALUE = "Hello";
37
    private static final String VAR = "x";
46
    private static final String VAR = "x";
38
47
39
    private PageContext pageContext;
48
    private PageContext pageContext;
40
    private ELContext elContext;
49
    private ELContext elContext;
41
    private VariableMapper vm;
50
    private VariableMapper vm;
51
    private Bean bean;
52
42
    private SetSupport tag;
53
    private SetSupport tag;
43
54
44
    @Before
55
    @Before
Lines 48-59 Link Here
48
        vm = createMock(VariableMapper.class);
59
        vm = createMock(VariableMapper.class);
49
60
50
        expect(pageContext.getELContext()).andStubReturn(elContext);
61
        expect(pageContext.getELContext()).andStubReturn(elContext);
62
        expect(pageContext.getServletContext()).andStubReturn(null);
51
        expect(elContext.getVariableMapper()).andStubReturn(vm);
63
        expect(elContext.getVariableMapper()).andStubReturn(vm);
52
64
65
        bean = new Bean();
66
53
        tag = new SetSupport();
67
        tag = new SetSupport();
54
        tag.setPageContext(pageContext);
68
        tag.setPageContext(pageContext);
69
70
        ExpressionFactory expressionFactory = createMock(ExpressionFactory.class);
71
        JspApplicationContext applicationContext = createMock(JspApplicationContext.class);
72
        JspFactory jspFactory = createMock(JspFactory.class);
73
        expect(expressionFactory.coerceToType(VALUE, String.class)).andStubReturn(VALUE);
74
        expect(expressionFactory.coerceToType(null, String.class)).andStubReturn(null);
75
        expect(applicationContext.getExpressionFactory()).andStubReturn(expressionFactory);
76
        expect(jspFactory.getJspApplicationContext(null)).andStubReturn(applicationContext);
77
        replay(jspFactory, applicationContext, expressionFactory);
78
        JspFactory.setDefaultFactory(jspFactory);
55
    }
79
    }
56
80
81
    @After
82
    public void teardown() {
83
        JspFactory.setDefaultFactory(null);
84
    }
85
86
    @Test
87
    public void testSyntax1WithNoScope() throws JspException {
88
        tag.setVar(VAR);
89
        tag.valueSpecified = true;
90
        tag.value = VALUE;
91
92
        // verify mapper is checked but that no action is taken
93
        expect(vm.resolveVariable(VAR)).andReturn(null);
94
        pageContext.setAttribute(VAR, VALUE, PageContext.PAGE_SCOPE);
95
        replay(pageContext, elContext, vm);
96
        tag.doEndTag();
97
        verify(pageContext, elContext, vm);
98
    }
99
100
    @Test
101
    public void testSyntax1WithNullScope() throws JspException {
102
        tag.setVar(VAR);
103
        tag.setScope(null);
104
        tag.valueSpecified = true;
105
        tag.value = VALUE;
106
107
        // verify mapper is checked but that no action is taken
108
        expect(vm.resolveVariable(VAR)).andReturn(null);
109
        pageContext.setAttribute(VAR, VALUE, PageContext.PAGE_SCOPE);
110
        replay(pageContext, elContext, vm);
111
        tag.doEndTag();
112
        verify(pageContext, elContext, vm);
113
    }
114
115
    @Test
116
    public void testSyntax1WithPageScope() throws JspException {
117
        tag.setVar(VAR);
118
        tag.setScope("page");
119
        tag.valueSpecified = true;
120
        tag.value = VALUE;
121
122
        // verify mapper is checked but that no action is taken
123
        expect(vm.resolveVariable(VAR)).andReturn(null);
124
        pageContext.setAttribute(VAR, VALUE, PageContext.PAGE_SCOPE);
125
        replay(pageContext, elContext, vm);
126
        tag.doEndTag();
127
        verify(pageContext, elContext, vm);
128
    }
129
130
    @Test
131
    public void testSyntax1WithNonPageScope() throws JspException {
132
        tag.setVar(VAR);
133
        tag.setScope("request");
134
        tag.valueSpecified = true;
135
        tag.value = VALUE;
136
137
        // verify mapper is not checked
138
        pageContext.setAttribute(VAR, VALUE, PageContext.REQUEST_SCOPE);
139
        replay(pageContext, elContext, vm);
140
        tag.doEndTag();
141
        verify(pageContext, elContext, vm);
142
    }
143
144
    @Test
145
    public void testSyntax1WithNullValueAndNoScope() throws JspException {
146
        tag.setVar(VAR);
147
        tag.valueSpecified = true;
148
        tag.value = null;
149
150
        // verify mapper is checked but that no action is taken
151
        expect(vm.resolveVariable(VAR)).andReturn(null);
152
        pageContext.removeAttribute(VAR);
153
        replay(pageContext, elContext, vm);
154
        tag.doEndTag();
155
        verify(pageContext, elContext, vm);
156
    }
157
158
    @Test
159
    public void testSyntax1WithNullValueAndNonPageScope() throws JspException {
160
        tag.setVar(VAR);
161
        tag.setScope("request");
162
        tag.valueSpecified = true;
163
        tag.value = null;
164
165
        // verify mapper is checked but that no action is taken
166
        expect(vm.resolveVariable(VAR)).andReturn(null);
167
        pageContext.removeAttribute(VAR, PageContext.REQUEST_SCOPE);
168
        replay(pageContext, elContext, vm);
169
        tag.doEndTag();
170
        verify(pageContext, elContext, vm);
171
    }
172
173
    @Test
174
    public void testSyntax3WithMap() throws JspException {
175
        @SuppressWarnings("unchecked")
176
        Map<String, Object> target = createMock(Map.class);
177
        tag.target = target;
178
        tag.property = PROPERTY;
179
        tag.valueSpecified = true;
180
        tag.value = VALUE;
181
        
182
        expect(target.put(PROPERTY, VALUE)).andStubReturn(null);
183
        replay(target);
184
        tag.doEndTag();
185
        verify(target);
186
    }
187
188
    @Test
189
    public void testSyntax3WithMapWhenPropertyIsNull() throws JspException {
190
        @SuppressWarnings("unchecked")
191
        Map<String, Object> target = createMock(Map.class);
192
        tag.target = target;
193
        tag.property = null;
194
        tag.valueSpecified = true;
195
        tag.value = VALUE;
196
197
        expect(target.put(null, VALUE)).andStubReturn(null);
198
        replay(target);
199
        tag.doEndTag();
200
        verify(target);
201
    }
202
203
    @Test
204
    public void testSyntax3WithMapWhenValueIsNull() throws JspException {
205
        @SuppressWarnings("unchecked")
206
        Map<String, Object> target = createMock(Map.class);
207
        tag.target = target;
208
        tag.property = PROPERTY;
209
        tag.valueSpecified = true;
210
        tag.value = null;
211
212
        expect(target.remove(PROPERTY)).andStubReturn(null);
213
        replay(target);
214
        tag.doEndTag();
215
        verify(target);
216
    }
217
218
    @Test
219
    public void testSyntax3WithBean() throws JspException {
220
        tag.target = bean;
221
        tag.property = PROPERTY;
222
        tag.valueSpecified = true;
223
        tag.value = VALUE;
224
225
        tag.doEndTag();
226
        Assert.assertEquals(VALUE, bean.getProperty());
227
    }
228
229
    @Test
230
    public void testSyntax3WithBeanAndNullValue() throws JspException {
231
        tag.target = bean;
232
        tag.property = PROPERTY;
233
        tag.valueSpecified = true;
234
        tag.value = null;
235
236
        tag.doEndTag();
237
        Assert.assertNull(bean.getProperty());
238
    }
239
240
    @Test
241
    public void testSyntax3WithBeanAndUndefinedProperty() throws JspException {
242
        tag.target = bean;
243
        tag.property = "undefined";
244
        tag.valueSpecified = true;
245
        tag.value = VALUE;
246
247
        try {
248
            tag.doEndTag();
249
        } catch (JspTagException e) {
250
            Assert.assertEquals(e.getMessage(), Resources.getMessage("SET_INVALID_PROPERTY", "undefined"));
251
        }
252
    }
253
254
    @Test
255
    public void testSyntax3WithBeanAndReadOnlyProperty() throws JspException {
256
        tag.target = bean;
257
        tag.property = "readOnly";
258
        tag.valueSpecified = true;
259
        tag.value = VALUE;
260
261
        try {
262
            tag.doEndTag();
263
        } catch (JspException e) {
264
            Assert.assertEquals(e.getMessage(), Resources.getMessage("SET_NO_SETTER_METHOD", "readOnly"));
265
        }
266
    }
267
268
    @Test
269
    public void testSyntax3WhenTargetIsNull() throws JspException {
270
        tag.target = null;
271
        tag.property = PROPERTY;
272
        tag.valueSpecified = true;
273
        tag.value = VALUE;
274
275
        try {
276
            tag.doEndTag();
277
            Assert.fail();
278
        } catch (JspTagException e) {
279
            Assert.assertEquals(e.getMessage(), Resources.getMessage("SET_INVALID_TARGET"));
280
        }
281
    }
282
57
    /**
283
    /**
58
     * Verify Bug 49526 when there is no existing variable mapping.
284
     * Verify Bug 49526 when there is no existing variable mapping.
59
     *
285
     *
Lines 151-154 Link Here
151
        expect(bodyContent.getString()).andStubReturn(null);
377
        expect(bodyContent.getString()).andStubReturn(null);
152
        Assert.assertEquals("", tag.getResult());
378
        Assert.assertEquals("", tag.getResult());
153
    }
379
    }
380
381
    public static class Bean {
382
        private String property;
383
384
        public String getProperty() {
385
            return property;
386
        }
387
388
        public void setProperty(String property) {
389
            this.property = property;
390
        }
391
392
        public boolean isReadOnly() {
393
            return true;
394
        }
395
    }
154
}
396
}
(-)impl/src/main/java/org/apache/taglibs/standard/resources/Resources.properties (+3 lines)
Lines 77-82 Link Here
77
SET_INVALID_TARGET=\
77
SET_INVALID_TARGET=\
78
    Attempt to set the property of an invalid object in &lt;set&gt;.
78
    Attempt to set the property of an invalid object in &lt;set&gt;.
79
79
80
SET_BAD_DEFERRED_SCOPE=\
81
    Invalid scope for ValueExpression in &lt;set&gt;. "page" scope is required but was "{0}"
82
80
SET_NO_VALUE=\
83
SET_NO_VALUE=\
81
    Need either non-whitespace body or "value" attribute in &lt;set&gt;
84
    Need either non-whitespace body or "value" attribute in &lt;set&gt;
82
85
(-)impl/src/main/java/org/apache/taglibs/standard/tag/common/core/SetSupport.java (-93 / +129 lines)
Lines 61-68 Link Here
61
    protected Object target;            // tag attribute
61
    protected Object target;            // tag attribute
62
    protected String property;          // tag attribute
62
    protected String property;          // tag attribute
63
    private String var;                 // tag attribute
63
    private String var;                 // tag attribute
64
    private int scope;                  // tag attribute
64
    private String scope;               // tag attribute
65
    private boolean scopeSpecified;     // status
66
65
67
    //*********************************************************************
66
    //*********************************************************************
68
    // Construction and initialization
67
    // Construction and initialization
Lines 79-87 Link Here
79
78
80
    // resets local state
79
    // resets local state
81
    private void init() {
80
    private void init() {
82
        value = target = property = var = null;
81
        value = target = property = var = scope = null;
83
        scopeSpecified = valueSpecified = false;
82
        valueSpecified = false;
84
        scope = PageContext.PAGE_SCOPE;
85
    }
83
    }
86
84
87
    // Releases any resources we may have (or inherit)
85
    // Releases any resources we may have (or inherit)
Lines 101-192 Link Here
101
99
102
        // decide what to do with the result
100
        // decide what to do with the result
103
        if (var != null) {
101
        if (var != null) {
104
102
            exportToVariable(result);
105
            /*
103
        } else if (target == null) {
106
             * Store the result, letting an IllegalArgumentException
104
            // can happen if target evaluates to null
107
             * propagate back if the scope is invalid (e.g., if an attempt
105
            throw new JspTagException(Resources.getMessage("SET_INVALID_TARGET"));
108
             * is made to store something in the session without any
106
        } else if (target instanceof Map) {
109
             * HttpSession existing).
107
            exportToMapProperty(result);
110
             */
111
            ELContext myELContext = pageContext.getELContext();
112
            VariableMapper vm = myELContext.getVariableMapper();
113
            if (result != null) {
114
                //check for instanceof valueExpression
115
                if (result instanceof ValueExpression) {
116
                    if (scope!=PageContext.PAGE_SCOPE) {
117
                        throw new JspException("Incorrect scope for ValueExpression.  PageScope is required.");
118
                    }
119
                    //set variable in var Mapper
120
                    vm.setVariable(var, (ValueExpression)result);
121
                } else {
122
                    // make sure to remove it from the VariableMapper if we will be setting into page scope 
123
                    if (scope == PageContext.PAGE_SCOPE && vm.resolveVariable(var) != null) {
124
                        vm.setVariable(var, null);
125
                    }
126
                    pageContext.setAttribute(var, result, scope);
127
                }
128
            } else {
129
                //make sure to remove it from the Var mapper
130
                if (vm.resolveVariable(var)!=null) {
131
                    vm.setVariable(var, null);
132
                }
133
                if (scopeSpecified)
134
                    pageContext.removeAttribute(var, scope);
135
                else
136
                    pageContext.removeAttribute(var);
137
            }
138
139
        } else if (target != null) {
140
141
            // save the result to target.property
142
            if (target instanceof Map) {
143
                // ... treating it as a Map entry
144
                if (result == null)
145
                    ((Map)target).remove(property);
146
                else
147
                    ((Map)target).put(property, result);
148
            } else {
149
                // ... treating it as a bean property
150
                try {
151
                    PropertyDescriptor pd[] = Introspector.getBeanInfo(target.getClass()).getPropertyDescriptors();
152
                    boolean succeeded = false;
153
                    for (int i = 0; i < pd.length; i++) {
154
                        if (pd[i].getName().equals(property)) {
155
                            Method m = pd[i].getWriteMethod();
156
                            if (m == null) {
157
                                throw new JspException(Resources.getMessage("SET_NO_SETTER_METHOD", property));
158
                            }
159
                            if (result != null) {  
160
                                try {
161
                                    m.invoke(target, new Object[] { convertToExpectedType(result, m.getParameterTypes()[0]) });
162
                                } catch (ELException ex) {
163
                                    throw new JspTagException(ex);
164
                                }
165
                            } else {
166
                                m.invoke(target, new Object[] { null });
167
                            }
168
                            succeeded = true;
169
                        }
170
                    }
171
                    if (!succeeded) {
172
                        throw new JspTagException(Resources.getMessage("SET_INVALID_PROPERTY", property));
173
                    }
174
                } catch (IllegalAccessException ex) {
175
                    throw new JspException(ex);
176
                } catch (IntrospectionException ex) {
177
                    throw new JspException(ex);
178
                } catch (InvocationTargetException ex) {
179
                    throw new JspException(ex);
180
                }
181
            }
182
        } else {
108
        } else {
183
            // should't ever occur because of validation in TLV and setters
109
            exportToBeanProperty(result);
184
            throw new JspTagException();
185
        }
110
        }
186
111
187
        return EVAL_PAGE;
112
        return EVAL_PAGE;
188
    }
113
    }
189
    
114
190
    Object getResult() {
115
    Object getResult() {
191
        if (valueSpecified) {
116
        if (valueSpecified) {
192
            return value;
117
            return value;
Lines 201-212 Link Here
201
            }
126
            }
202
        }
127
        }
203
    }
128
    }
204
    
129
205
    /**
130
    /**
206
     * Convert an object to an expected type according to the conversion
131
     * Export the result into a scoped variable.
132
     *
133
     * @param result the value to export
134
     * @throws JspTagException if there was a problem exporting the result
135
     */
136
    void exportToVariable(Object result) throws JspTagException {
137
        /*
138
        * Store the result, letting an IllegalArgumentException
139
        * propagate back if the scope is invalid (e.g., if an attempt
140
        * is made to store something in the session without any
141
        * HttpSession existing).
142
        */
143
        int scopeValue = Util.getScope(scope);
144
        ELContext myELContext = pageContext.getELContext();
145
        VariableMapper vm = myELContext.getVariableMapper();
146
        if (result != null) {
147
            // if the result is a ValueExpression we just export to the mapper
148
            if (result instanceof ValueExpression) {
149
                if (scopeValue != PageContext.PAGE_SCOPE) {
150
                    throw new JspTagException(Resources.getMessage("SET_BAD_DEFERRED_SCOPE", scope));
151
                }
152
                vm.setVariable(var, (ValueExpression)result);
153
            } else {
154
                // make sure to remove it from the VariableMapper if we will be setting into page scope
155
                if (scopeValue == PageContext.PAGE_SCOPE && vm.resolveVariable(var) != null) {
156
                    vm.setVariable(var, null);
157
                }
158
                pageContext.setAttribute(var, result, scopeValue);
159
            }
160
        } else {
161
            //make sure to remove it from the Var mapper
162
            if (vm.resolveVariable(var)!=null) {
163
                vm.setVariable(var, null);
164
            }
165
            if (scope != null) {
166
                pageContext.removeAttribute(var, Util.getScope(scope));
167
            } else {
168
                pageContext.removeAttribute(var);
169
            }
170
        }
171
    }
172
173
    /**
174
     * Export the result into a Map.
175
     *
176
     * @param result the value to export
177
     */
178
    void exportToMapProperty(Object result) {
179
        @SuppressWarnings("unchecked")
180
        Map<Object, Object> map = (Map<Object, Object>) target;
181
        if (result == null) {
182
            map.remove(property);
183
        } else {
184
            map.put(property, result);
185
        }
186
    }
187
188
    /**
189
     * Export the result into a bean property.
190
     *
191
     * @param result the value to export
192
     * @throws JspTagException if there was a problem exporting the result
193
     */
194
    void exportToBeanProperty(Object result) throws JspTagException {
195
        PropertyDescriptor[] descriptors;
196
        try {
197
            descriptors = Introspector.getBeanInfo(target.getClass()).getPropertyDescriptors();
198
        } catch (IntrospectionException ex) {
199
            throw new JspTagException(ex);
200
        }
201
202
        for (PropertyDescriptor pd : descriptors) {
203
            if (pd.getName().equals(property)) {
204
                Method m = pd.getWriteMethod();
205
                if (m == null) {
206
                    throw new JspTagException(Resources.getMessage("SET_NO_SETTER_METHOD", property));
207
                }
208
                try {
209
                    m.invoke(target, convertToExpectedType(result, m));
210
                } catch (ELException ex) {
211
                    throw new JspTagException(ex);
212
                } catch (IllegalAccessException ex) {
213
                    throw new JspTagException(ex);
214
                } catch (InvocationTargetException ex) {
215
                    throw new JspTagException(ex);
216
                }
217
                return;
218
            }
219
        }
220
        throw new JspTagException(Resources.getMessage("SET_INVALID_PROPERTY", property));
221
    }
222
223
    /**
224
     * Convert an object to an expected type of the method parameter according to the conversion
207
     * rules of the Expression Language.
225
     * rules of the Expression Language.
226
     *
227
     * @param value the value to convert
228
     * @param m the setter method
229
     * @return value converted to an instance of the expected type; will be null if value was null
230
     * @throws javax.el.ELException if there was a problem coercing the value
208
     */
231
     */
209
    private Object convertToExpectedType(final Object value, Class expectedType) throws ELException {
232
    private Object convertToExpectedType(final Object value, Method m) throws ELException {
233
        if (value == null) {
234
            return null;
235
        }
236
        Class<?> expectedType = m.getParameterTypes()[0];
210
        JspFactory jspFactory = JspFactory.getDefaultFactory();
237
        JspFactory jspFactory = JspFactory.getDefaultFactory();
211
        ExpressionFactory expressionFactory = jspFactory.getJspApplicationContext(pageContext.getServletContext()).getExpressionFactory();
238
        ExpressionFactory expressionFactory = jspFactory.getJspApplicationContext(pageContext.getServletContext()).getExpressionFactory();
212
        return expressionFactory.coerceToType(value, expectedType);
239
        return expressionFactory.coerceToType(value, expectedType);
Lines 215-228 Link Here
215
    //*********************************************************************
242
    //*********************************************************************
216
    // Accessor methods
243
    // Accessor methods
217
244
218
    // for tag attribute
245
    /**
246
     * Name of the exported scoped variable to hold the value specified in the action.
247
     * The type of the scoped variable is whatever type the value expression evaluates to.
248
     *
249
     * @param var name of the exported scoped variable
250
     */
219
    public void setVar(String var) {
251
    public void setVar(String var) {
220
        this.var = var;
252
        this.var = var;
221
    }
253
    }
222
254
223
    // for tag attribute
255
    /**
256
     * Scope for var.
257
     * Values are verified by TLV.
258
     *
259
     * @param scope the variable scope
260
     */
224
    public void setScope(String scope) {
261
    public void setScope(String scope) {
225
        this.scope = Util.getScope(scope);
262
        this.scope = scope;
226
        this.scopeSpecified = true;
227
    }
263
    }
228
}
264
}
(-)impl/pom.xml (-1 / +9 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/tag/common/core/TestSetSupport.java</include>
141
          </includes>
149
          </includes>
142
          <excludes>
150
          <excludes>
143
            <!-- Old tests -->
151
            <!-- Old tests -->

Return to bug 49548