diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
index 5258c959093..0e1f71a55f7 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
@@ -439,16 +439,17 @@ public class TypeDescriptor {
public String toString() {
if (this == TypeDescriptor.NULL) {
- return "TypeDescriptor.NULL";
+ return "[TypeDescriptor.NULL]";
}
else {
StringBuilder builder = new StringBuilder();
- builder.append("TypeDescriptor ");
+ builder.append("[TypeDescriptor ");
Annotation[] anns = getAnnotations();
for (Annotation ann : anns) {
builder.append("@").append(ann.annotationType().getName()).append(' ');
}
builder.append(ClassUtils.getQualifiedName(getType()));
+ builder.append("]");
return builder.toString();
}
}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java
index b025bee8027..588498217bb 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java
@@ -28,7 +28,6 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
@@ -39,6 +38,7 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.core.convert.converter.GenericConverter;
+import org.springframework.core.style.StylerUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -121,9 +121,12 @@ public class GenericConversionService implements ConversionService, ConverterReg
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
assertNotNull(sourceType, targetType);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Converting value " + StylerUtils.style(source) +" of " + sourceType + " to " + targetType);
+ }
if (sourceType == TypeDescriptor.NULL) {
Assert.isTrue(source == null, "The source must be null if sourceType == TypeDescriptor.NULL");
- return convertNullSource(sourceType, targetType);
+ return convertNullSource(sourceType, targetType);
}
if (targetType == TypeDescriptor.NULL) {
return null;
diff --git a/org.springframework.web.servlet/.classpath b/org.springframework.web.servlet/.classpath
index 1584462c122..e241d01b081 100644
--- a/org.springframework.web.servlet/.classpath
+++ b/org.springframework.web.servlet/.classpath
@@ -50,5 +50,6 @@
+
diff --git a/org.springframework.web.servlet/ivy.xml b/org.springframework.web.servlet/ivy.xml
index 3aa42c9bc1e..47bbebf7523 100644
--- a/org.springframework.web.servlet/ivy.xml
+++ b/org.springframework.web.servlet/ivy.xml
@@ -72,6 +72,8 @@
conf="optional, velocity, freemarker, jasper-reports->compile"/>
+
[] getSpecificTargetClasses() {
+ return null;
+ }
+
+ public boolean canRead(EvaluationContext context, Object target,
+ String name) throws AccessException {
+ if (name.equals("pageContext")) {
+ return true;
+ }
+ // TODO support all other JSP implicit variables defined at http://java.sun.com/javaee/6/docs/api/javax/servlet/jsp/el/ImplicitObjectELResolver.html
+ return this.pageContext.findAttribute(name) != null;
+ }
+
+ public TypedValue read(EvaluationContext context, Object target,
+ String name) throws AccessException {
+ if (name.equals("pageContext")) {
+ return new TypedValue(this.pageContext);
+ }
+ // TODO support all other JSP implicit variables defined at http://java.sun.com/javaee/6/docs/api/javax/servlet/jsp/el/ImplicitObjectELResolver.html
+ return new TypedValue(this.pageContext.findAttribute(name));
+ }
+
+ public boolean canWrite(EvaluationContext context, Object target,
+ String name) throws AccessException {
+ return false;
+ }
+
+ public void write(EvaluationContext context, Object target,
+ String name, Object newValue) throws AccessException {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/main/resources/META-INF/spring.tld b/org.springframework.web.servlet/src/main/resources/META-INF/spring.tld
index 8ac57e7b04d..74f3c460bd0 100644
--- a/org.springframework.web.servlet/src/main/resources/META-INF/spring.tld
+++ b/org.springframework.web.servlet/src/main/resources/META-INF/spring.tld
@@ -358,8 +358,8 @@
true
- Specifies a remote application context. The default is the
- current application context.
+ Specifies a remote application context path. The default is the
+ current application context path.
context
false
true
@@ -414,4 +414,44 @@
+
+ Evaluates a Spring expression (SpEL) and either prints the result or assigns it to a variable.
+ eval
+ org.springframework.web.servlet.tags.EvalTag
+ JSP
+
+ The expression to evaluate.
+ expression
+ true
+ true
+
+
+ The name of the variable to export the evaluation result to.
+ var
+ false
+ true
+
+
+ The scope for the var. 'application', 'session', 'request' and
+ 'page' scopes are supported. Defaults to page scope. This attribute has no
+ effect unless the var attribute is also defined.
+ scope
+ false
+ true
+
+
+ Set HTML escaping for this tag, as boolean value. Overrides the
+ default HTML escaping setting for the current page.
+ htmlEscape
+ false
+ true
+
+
+ Set JavaScript escaping for this tag, as boolean value. Default is false.
+ javaScriptEscape
+ false
+ true
+
+
+
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/AbstractTagTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/AbstractTagTests.java
index 59d76364aac..bc2cc8b7109 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/AbstractTagTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/AbstractTagTests.java
@@ -16,17 +16,13 @@
package org.springframework.web.servlet.tags;
-import java.io.StringWriter;
-
-import javax.servlet.jsp.JspWriter;
-
import junit.framework.TestCase;
-import org.springframework.mock.web.MockBodyContent;
+import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockPageContext;
import org.springframework.mock.web.MockServletContext;
-import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.LocaleResolver;
@@ -48,6 +44,8 @@ public abstract class AbstractTagTests extends TestCase {
SimpleWebApplicationContext wac = new SimpleWebApplicationContext();
wac.setServletContext(sc);
wac.setNamespace("test");
+ // TODO this name index leads to brittle lookup by EvalTag
+ wac.registerSingleton("conversionService", FormattingConversionServiceFactoryBean.class);
wac.refresh();
MockHttpServletRequest request = new MockHttpServletRequest(sc);
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/EvalTagTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/EvalTagTests.java
new file mode 100644
index 00000000000..e415904240b
--- /dev/null
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/EvalTagTests.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.servlet.tags;
+
+import java.math.BigDecimal;
+
+import javax.servlet.jsp.tagext.Tag;
+
+import org.springframework.format.annotation.NumberFormat;
+import org.springframework.format.annotation.NumberFormat.Style;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockPageContext;
+
+public class EvalTagTests extends AbstractTagTests {
+
+ private EvalTag tag;
+
+ private MockPageContext context;
+
+ protected void setUp() throws Exception {
+ context = createPageContext();
+ context.getRequest().setAttribute("bean", new Bean());
+ tag = new EvalTag();
+ tag.setPageContext(context);
+ }
+
+ public void testEndTagPrintScopedAttributeResult() throws Exception {
+ tag.setExpression("bean.method()");
+ int action = tag.doStartTag();
+ assertEquals(Tag.EVAL_BODY_INCLUDE, action);
+ action = tag.doEndTag();
+ assertEquals(Tag.EVAL_PAGE, action);
+ assertEquals("foo", ((MockHttpServletResponse)context.getResponse()).getContentAsString());
+ }
+
+ public void testEndTagPrintFormattedScopedAttributeResult() throws Exception {
+ tag.setExpression("bean.formattable");
+ int action = tag.doStartTag();
+ assertEquals(Tag.EVAL_BODY_INCLUDE, action);
+ action = tag.doEndTag();
+ assertEquals(Tag.EVAL_PAGE, action);
+ // TODO - fails because EL does not consider annotations on getter/setter method or field for properties (just annotations on method parameters)
+ //assertEquals("25%", ((MockHttpServletResponse)context.getResponse()).getContentAsString());
+ }
+
+ public static class Bean {
+
+ public String method() {
+ return "foo";
+ }
+
+ @NumberFormat(style=Style.PERCENT)
+ public BigDecimal getFormattable() {
+ return new BigDecimal(".25");
+ }
+ }
+}