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>