Repository: incubator-freemarker
Updated Branches:
  refs/heads/3 12a2d49d0 -> f5a44238e


FREEMARKER-55: stringifying string/boolean/date model in url function. 
otherwise exception


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/4779234b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/4779234b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/4779234b

Branch: refs/heads/3
Commit: 4779234b67bb9c6ab0f0812d72ebe4b2152de04a
Parents: 14e4250
Author: Woonsan Ko <woon...@apache.org>
Authored: Fri Sep 15 10:39:26 2017 -0400
Committer: Woonsan Ko <woon...@apache.org>
Committed: Fri Sep 15 10:39:26 2017 -0400

----------------------------------------------------------------------
 .../AbstractSpringTemplateCallableModel.java    |  4 +-
 .../spring/model/MessageFunction.java           |  4 +-
 .../freemarker/spring/model/UrlFunction.java    | 23 ++++++---
 .../spring/example/mvc/users/User.java          |  6 +--
 .../example/mvc/users/UserController.java       |  4 +-
 .../example/mvc/users/UserRepository.java       | 16 +++----
 .../spring/model/BindDirectiveTest.java         |  2 +-
 .../spring/model/EvalFunctionTest.java          |  2 +-
 .../spring/model/MessageFunctionTest.java       |  4 +-
 .../spring/model/NestedPathDirectiveTest.java   |  2 +-
 .../spring/model/ThemeFunctionTest.java         |  2 +-
 .../spring/model/UrlFunctionTest.java           | 49 ++++++++++++++------
 .../test/model/url-function-basic-usages.ftl    | 29 ++++++++++++
 13 files changed, 104 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
index 1c3d71b..d6157b0 100644
--- 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
@@ -81,7 +81,7 @@ abstract class AbstractSpringTemplateCallableModel implements 
TemplateCallableMo
         final ObjectWrapper objectWrapper = env.getObjectWrapper();
 
         if (!(objectWrapper instanceof ObjectWrapperAndUnwrapper)) {
-            CallableUtils.newGenericExecuteException(
+            throw CallableUtils.newGenericExecuteException(
                     "The ObjectWrapper of environment isn't an instance of 
ObjectWrapperAndUnwrapper.", this,
                     calledAsFunction);
         }
@@ -101,7 +101,7 @@ abstract class AbstractSpringTemplateCallableModel 
implements TemplateCallableMo
         TemplateModel rcModel = 
env.getVariable(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE);
 
         if (rcModel == null) {
-            CallableUtils.newGenericExecuteException(
+            throw CallableUtils.newGenericExecuteException(
                     
AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE + " not found.", 
this, false);
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java
 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java
index 3755849..c6ac520 100644
--- 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java
@@ -103,7 +103,7 @@ class MessageFunction extends 
AbstractSpringTemplateFunctionModel {
         final MessageSource messageSource = getMessageSource(requestContext);
 
         if (messageSource == null) {
-            CallableUtils.newGenericExecuteException("MessageSource not 
found.", this);
+            throw CallableUtils.newGenericExecuteException("MessageSource not 
found.", this);
         }
 
         String message = null;
@@ -135,7 +135,7 @@ class MessageFunction extends 
AbstractSpringTemplateFunctionModel {
                 message = messageSource.getMessage(code, (msgArgumentList == 
null) ? null : msgArgumentList.toArray(),
                         null, requestContext.getLocale());
             } else {
-                
CallableUtils.newNullOrOmittedArgumentException(CODE_PARAM_IDX, this);
+                throw 
CallableUtils.newNullOrOmittedArgumentException(CODE_PARAM_IDX, this);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
index e2986a9..7f180ec 100644
--- 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java
@@ -36,9 +36,11 @@ import org.apache.freemarker.core.Environment;
 import org.apache.freemarker.core.TemplateException;
 import org.apache.freemarker.core.model.ArgumentArrayLayout;
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateBooleanModel;
 import org.apache.freemarker.core.model.TemplateHashModelEx2;
 import 
org.apache.freemarker.core.model.TemplateHashModelEx2.KeyValuePairIterator;
 import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateNumberModel;
 import org.apache.freemarker.core.model.TemplateStringModel;
 import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core.util.StringToIndexMap;
@@ -127,20 +129,27 @@ class UrlFunction extends 
AbstractSpringTemplateFunctionModel {
                     paramName = ((TemplateStringModel) 
paramNameModel).getAsString();
 
                     if (paramName.isEmpty()) {
-                        
CallableUtils.newArgumentValueException(PARAMS_PARAM_IDX,
+                        throw 
CallableUtils.newArgumentValueException(PARAMS_PARAM_IDX,
                                 "Parameter name must be a non-blank string.", 
this);
                     }
 
                     if (paramValueModel instanceof TemplateStringModel) {
                         paramValue = ((TemplateStringModel) 
paramValueModel).getAsString();
+                    } else if (paramValueModel instanceof TemplateNumberModel) 
{
+                        paramValue = ((TemplateNumberModel) 
paramValueModel).getAsNumber().toString();
+                    } else if (paramValueModel instanceof 
TemplateBooleanModel) {
+                        paramValue = Boolean.toString(((TemplateBooleanModel) 
paramValueModel).getAsBoolean());
                     } else {
-                        paramValue = env.formatToPlainText(paramValueModel);
+                        throw 
CallableUtils.newArgumentValueException(PARAMS_PARAM_IDX,
+                                "Format the parameter manually to properly 
coerce it to a URL parameter value string. "
+                                        + "e.g, date?string.iso, date?long, 
list?join('_'), etc.",
+                                this);
                     }
 
                     params.add(new _KeyValuePair<String, String>(paramName, 
paramValue));
                 } else {
-                    CallableUtils.newArgumentValueException(PARAMS_PARAM_IDX,
-                            "Parameter name must be string.", this);
+                    throw 
CallableUtils.newArgumentValueException(PARAMS_PARAM_IDX,
+                            "Parameter name must be a string.", this);
                 }
             }
         }
@@ -214,7 +223,7 @@ class UrlFunction extends 
AbstractSpringTemplateFunctionModel {
                 try {
                     uri = uri.replace(template, 
UriUtils.encodePath(paramValue, encoding));
                 } catch (UnsupportedEncodingException e) {
-                    CallableUtils.newGenericExecuteException("Cannot encode 
URI. " + e, this);
+                    throw CallableUtils.newGenericExecuteException("Cannot 
encode URI. " + e, this);
                 }
             } else {
                 template = URL_TEMPLATE_DELIMITER_PREFIX + '/' + paramName + 
URL_TEMPLATE_DELIMITER_SUFFIX;
@@ -225,7 +234,7 @@ class UrlFunction extends 
AbstractSpringTemplateFunctionModel {
                     try {
                         uri = uri.replace(template, 
UriUtils.encodePathSegment(paramValue, encoding));
                     } catch (UnsupportedEncodingException e) {
-                        CallableUtils.newGenericExecuteException("Cannot 
encode URI. " + e, this);
+                        throw CallableUtils.newGenericExecuteException("Cannot 
encode URI. " + e, this);
                     }
                 }
             }
@@ -258,7 +267,7 @@ class UrlFunction extends 
AbstractSpringTemplateFunctionModel {
                         
queryStringBuilder.append(UriUtils.encodeQueryParam(paramValue, encoding));
                     }
                 } catch (UnsupportedEncodingException e) {
-                    CallableUtils.newGenericExecuteException("Cannot encode 
query parameter. " + e, this);
+                    throw CallableUtils.newGenericExecuteException("Cannot 
encode query parameter. " + e, this);
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
index 23d31dc..41b42c4 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
@@ -23,7 +23,7 @@ import java.util.Date;
 
 public class User {
 
-    private Integer id;
+    private Long id;
     private String password;
     private String email;
     private String firstName;
@@ -33,11 +33,11 @@ public class User {
     public User() {
     }
 
-    public User(final Integer id) {
+    public User(final Long id) {
         this.id = id;
     }
 
-    public Integer getId() {
+    public Long getId() {
         return id;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
index 09a416d..5b1799e 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserController.java
@@ -60,7 +60,7 @@ public class UserController {
     public String listUsers(@RequestParam(value = "viewName", required = 
false) String viewName, Model model) {
         List<User> users = new LinkedList<>();
 
-        for (Integer id : userRepository.getUserIds()) {
+        for (Long id : userRepository.getUserIds()) {
             users.add(userRepository.getUser(id));
         }
 
@@ -70,7 +70,7 @@ public class UserController {
     }
 
     @RequestMapping(value = "/users/{id:\\d+}", method = RequestMethod.GET)
-    public String getUser(@PathVariable("id") Integer id,
+    public String getUser(@PathVariable("id") Long id,
             @RequestParam(value = "viewName", required = false) String 
viewName, Model model) {
         User user = userRepository.getUser(id);
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
index 5049521..1f1a9e2 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
@@ -30,21 +30,21 @@ import org.springframework.stereotype.Repository;
 @Repository
 public class UserRepository {
 
-    private Map<Integer, User> usersMap = new ConcurrentHashMap<>();
+    private Map<Long, User> usersMap = new ConcurrentHashMap<>();
     {
-        Integer id = 101;
+        Long id = 101L;
         User user = new User(id);
         user.setEmail("j...@example.com");
         user.setFirstName("John");
         user.setLastName("Doe");
         Calendar birthDate = Calendar.getInstance();
-        birthDate.set(Calendar.YEAR, 1971);
+        birthDate.set(Calendar.YEAR, 1973);
         birthDate.set(Calendar.MONTH, Calendar.JANUARY);
         birthDate.set(Calendar.DATE, 5);
         user.setBirthDate(birthDate.getTime());
         usersMap.put(id, user);
 
-        id = 102;
+        id = 102L;
         user = new User(id);
         user.setEmail("j...@example.com");
         user.setFirstName("Jane");
@@ -57,11 +57,11 @@ public class UserRepository {
         usersMap.put(id, user);
     }
 
-    public synchronized Set<Integer> getUserIds() {
+    public synchronized Set<Long> getUserIds() {
         return new TreeSet<>(usersMap.keySet());
     }
 
-    public synchronized User getUser(final Integer id) {
+    public synchronized User getUser(final Long id) {
         if (id == null) {
             throw new IllegalArgumentException("ID must be non-null.");
         }
@@ -76,7 +76,7 @@ public class UserRepository {
     }
 
     public synchronized User addOrUpdateUser(final User user) {
-        final Integer id = user.getId();
+        final Long id = user.getId();
         User newUser = cloneUser(user, id);
         usersMap.put(id, newUser);
         return cloneUser(newUser, id);
@@ -91,7 +91,7 @@ public class UserRepository {
         return user != null;
     }
 
-    private User cloneUser(final User source, final Integer id) {
+    private User cloneUser(final User source, final Long id) {
         User clone = new User(id);
         clone.setPassword(source.getPassword());
         clone.setEmail(source.getEmail());

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/BindDirectiveTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/BindDirectiveTest.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/BindDirectiveTest.java
index b2a6cd5..0b21a47 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/BindDirectiveTest.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/BindDirectiveTest.java
@@ -59,7 +59,7 @@ public class BindDirectiveTest {
 
     @Test
     public void testBasicUsages() throws Exception {
-        final Integer userId = userRepository.getUserIds().iterator().next();
+        final Long userId = userRepository.getUserIds().iterator().next();
         final User user = userRepository.getUser(userId);
         mockMvc.perform(get("/users/{userId}.", userId).param("viewName", 
"test/model/bind-directive-basic-usages")
                 
.accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/EvalFunctionTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/EvalFunctionTest.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/EvalFunctionTest.java
index 45d98b2..1e92292 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/EvalFunctionTest.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/EvalFunctionTest.java
@@ -60,7 +60,7 @@ public class EvalFunctionTest {
 
     @Test
     public void testBasicUsages() throws Exception {
-        final Integer userId = userRepository.getUserIds().iterator().next();
+        final Long userId = userRepository.getUserIds().iterator().next();
         final User user = userRepository.getUser(userId);
         mockMvc.perform(get("/users/").param("viewName", 
"test/model/eval-function-basic-usages")
                 
.accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MessageFunctionTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MessageFunctionTest.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MessageFunctionTest.java
index d043bfe..37af7eb 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MessageFunctionTest.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/MessageFunctionTest.java
@@ -59,7 +59,7 @@ public class MessageFunctionTest {
 
     @Test
     public void testBasicUsages() throws Exception {
-        final Integer userId = userRepository.getUserIds().iterator().next();
+        final Long userId = userRepository.getUserIds().iterator().next();
         final User user = userRepository.getUser(userId);
         mockMvc.perform(get("/users/{userId}/", userId).param("viewName", 
"test/model/message-function-basic-usages")
                 
.accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
@@ -72,7 +72,7 @@ public class MessageFunctionTest {
 
     @Test
     public void testWithMessageSourceResolvable() throws Exception {
-        final Integer nonExistingUserId = 0;
+        final Long nonExistingUserId = 0L;
         mockMvc.perform(
                 get("/users/{userId}/", nonExistingUserId).param("viewName", 
"test/model/message-function-basic-usages")
                         .accept(MediaType.parseMediaType("text/html")))

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/NestedPathDirectiveTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/NestedPathDirectiveTest.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/NestedPathDirectiveTest.java
index a4999f5..f5f7d18 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/NestedPathDirectiveTest.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/NestedPathDirectiveTest.java
@@ -59,7 +59,7 @@ public class NestedPathDirectiveTest {
 
     @Test
     public void testBasicUsages() throws Exception {
-        final Integer userId = userRepository.getUserIds().iterator().next();
+        final Long userId = userRepository.getUserIds().iterator().next();
         final User user = userRepository.getUser(userId);
         mockMvc.perform(get("/users/{userId}.", userId).param("viewName", 
"test/model/nestedpath-directive-basic-usages")
                 
.accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ThemeFunctionTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ThemeFunctionTest.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ThemeFunctionTest.java
index 804b76d..5dd4bdc 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ThemeFunctionTest.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/ThemeFunctionTest.java
@@ -65,7 +65,7 @@ public class ThemeFunctionTest {
     public void testBasicUsages() throws Exception {
         final MessageSource defaultThemeMessageSource = 
themeSource.getTheme("default").getMessageSource();
 
-        final Integer userId = userRepository.getUserIds().iterator().next();
+        final Long userId = userRepository.getUserIds().iterator().next();
         mockMvc.perform(get("/users/{userId}/", userId).param("viewName", 
"test/model/theme-function-basic-usages")
                 
.accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
                 
.andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/UrlFunctionTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/UrlFunctionTest.java
 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/UrlFunctionTest.java
index 8435bfc..3079556 100644
--- 
a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/UrlFunctionTest.java
+++ 
b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/UrlFunctionTest.java
@@ -19,12 +19,10 @@
 
 package org.apache.freemarker.spring.model;
 
-import static 
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static 
org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
-import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
-import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
 
+import org.apache.freemarker.spring.example.mvc.users.User;
 import org.apache.freemarker.spring.example.mvc.users.UserRepository;
 import org.junit.Before;
 import org.junit.Test;
@@ -38,11 +36,21 @@ import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 import org.springframework.web.context.WebApplicationContext;
 
+import static 
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
+
 @RunWith(SpringJUnit4ClassRunner.class)
 @WebAppConfiguration("classpath:META-INF/web-resources")
 @ContextConfiguration(locations = { 
"classpath:org/apache/freemarker/spring/example/mvc/users/users-mvc-context.xml"
 })
 public class UrlFunctionTest {
 
+    private static final String TEMPLATE_NUMBER_FORMAT = "00000000";
+
+    private static final String TEMPLATE_DATE_FORMAT = "yyyy-MM-dd";
+
     @Autowired
     private WebApplicationContext wac;
 
@@ -58,19 +66,34 @@ public class UrlFunctionTest {
 
     @Test
     public void testBasicUsages() throws Exception {
-        final Integer userId = userRepository.getUserIds().iterator().next();
+        final Long userId = userRepository.getUserIds().iterator().next();
+        final String formattedUerId = new 
DecimalFormat(TEMPLATE_NUMBER_FORMAT).format(userId);
+        final User user = userRepository.getUser(userId);
         mockMvc.perform(get("/users/").param("viewName", 
"test/model/url-function-basic-usages")
                 
.accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
                 
.andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())
-                .andExpect(xpath("//h2[@id='usersListHeader']//a/@href", 
userId).string("/users/"))
-                
.andExpect(xpath("//h3[@id='usersListHeaderWithSortParams']//a/@href", userId)
+                
.andExpect(xpath("//h2[@id='usersListHeader']//a/@href").string("/users/"))
+                
.andExpect(xpath("//h3[@id='usersListHeaderWithSortParams']//a/@href")
                         
.string("/users/?sortField=birthDate&sortDirection=descending"))
-                
.andExpect(xpath("//h2[@id='otherAppsUsersListHeader']//a/@href", 
userId).string("/otherapp/users/"))
-                
.andExpect(xpath("//h3[@id='otherAppsUsersListHeaderWithSortParams']//a/@href", 
userId)
+                
.andExpect(xpath("//h2[@id='otherAppsUsersListHeader']//a/@href").string("/otherapp/users/"))
+                
.andExpect(xpath("//h3[@id='otherAppsUsersListHeaderWithSortParams']//a/@href")
                         
.string("/otherapp/users/?sortField=birthDate&sortDirection=descending"))
-                
.andExpect(xpath("//div[@id='user-%s']//a[@class='userIdLink']/@href", 
userId).string("/users/" + userId + "/"))
-                
.andExpect(xpath("//div[@id='user-%s']//a[@class='userNameLink']/@href", 
userId).string("/users/" + userId + "/"))
-                .andExpect(xpath("//div[@id='freeMarkerManualUrl']//a/@href", 
userId)
+                
.andExpect(xpath("//div[@id='user-%s']//a[@class='userIdLink']/@href", 
formattedUerId)
+                        .string("/users/" + userId + "/"))
+                
.andExpect(xpath("//div[@id='user-%s']//a[@class='userNameLink']/@href", 
formattedUerId)
+                        .string("/users/" + formattedUerId + "/"))
+                
.andExpect(xpath("//div[@id='user-%s']//a[@class='badUserBirthDateLink']/@href",
 formattedUerId)
+                        .doesNotExist())
+                
.andExpect(xpath("//div[@id='user-%s']//a[@class='goodUserBirthDateLink']/@href",
 formattedUerId)
+                        .string("/users/" + userId + "/?birthDate="
+                                + new 
SimpleDateFormat(TEMPLATE_DATE_FORMAT).format(user.getBirthDate())))
+                
.andExpect(xpath("//div[@id='listLinkTest']//a[@class='badListLink']/@href").doesNotExist())
+                
.andExpect(xpath("//div[@id='listLinkTest']//a[@class='goodListLink']/@href")
+                        .string("/users/?items=101_102"))
+                
.andExpect(xpath("//div[@id='mapLinkTest']//a[@class='badMapLink']/@href").doesNotExist())
+                
.andExpect(xpath("//div[@id='mapLinkTest']//a[@class='goodMapLink']/@href")
+                        .string("/users/?items=101_102"))
+                .andExpect(xpath("//div[@id='freeMarkerManualUrl']//a/@href")
                         .string("http://freemarker.org/docs/index.html";));
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/4779234b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/url-function-basic-usages.ftl
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/url-function-basic-usages.ftl
 
b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/url-function-basic-usages.ftl
index e25a2d5..8cc7c65 100644
--- 
a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/url-function-basic-usages.ftl
+++ 
b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/url-function-basic-usages.ftl
@@ -20,6 +20,9 @@
 <html>
 <body>
 
+<#-- NOTE: spring.url function should not use this number format. -->
+<#setting numberFormat="00000000" />
+
 <h2 id="usersListHeader">
   <a href="${spring.url('/users/')}">Users List</a>
 </h2>
@@ -42,6 +45,13 @@
       <div id="user-${user.id!}">
         <a class="userIdLink" href="${spring.url('/users/{userId}/', 
userId=user.id)}">${user.id!}</a>
         <a class="userNameLink" 
href="${spring.url('/users/${user.id}/')}">${user.firstName!} 
${user.lastName!}</a>
+
+        <#attempt>
+          <a class="badUserBirthDateLink" 
href="${spring.url('/users/{userId}/', userId=user.id, 
birthDate=user.birthDate)}">${user.birthDate?date}</a>
+        <#recover>
+          <a class="goodUserBirthDateLink" 
href="${spring.url('/users/{userId}/', userId=user.id, 
birthDate=user.birthDate?string['yyyy-MM-dd'])}">${user.birthDate?date}</a>
+        </#attempt>
+
       </div>
     </li>
   </#list>
@@ -51,5 +61,24 @@
   <a href="${spring.url('http://freemarker.org/docs/index.html')}">Apache 
FreeMarker Manual</a>
 </div>
 
+<#-- List or Map is not allowed to pass as url parameter directly. -->
+<#assign userIdList = [ '101', '102' ] />
+<#assign userInfoMap = { "101": "John", "102": "Jane" } />
+
+<div id="listLinkTest">
+  <#attempt>
+    <a class="badListLink" href="${spring.url('/users/', 
items=userIdList)}">User List Link</a>
+  <#recover>
+    <a class="goodListLink" href="${spring.url('/users/', 
items=userIdList?join('_'))}">User List Link</a>
+  </#attempt>
+</div>
+<div id="mapLinkTest">
+  <#attempt>
+    <a class="badMapLink" href="${spring.url('/users/', 
items=userInfoMap)}">User List Link</a>
+  <#recover>
+    <a class="goodMapLink" href="${spring.url('/users/', 
items=userInfoMap?keys?join('_'))}">User List Link</a>
+  </#attempt>
+</div>
+
 </body>
 </html>

Reply via email to