Skip to content

Commit 3e641d7

Browse files
committed
Merge branch '3.1.x' of github.com:grails/grails-core into 3.1.x
2 parents ee1b48e + b9107c8 commit 3e641d7

File tree

11 files changed

+188
-7
lines changed

11 files changed

+188
-7
lines changed

grails-test-suite-web/src/test/groovy/org/grails/web/mapping/UrlMappingsHolderTests.groovy

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,28 @@ mappings {
5858
}
5959
'''
6060

61+
def mappingWithNamespace = '''
62+
mappings {
63+
"/$namespace/$controller/$action?/$id?" ()
64+
}
65+
'''
66+
67+
@Test
68+
void testGetReverseMappingWithNamespace() {
69+
def res = new ByteArrayResource(mappingWithNamespace.bytes)
70+
71+
def evaluator = new DefaultUrlMappingEvaluator(mainContext)
72+
def mappings = evaluator.evaluateMappings(res)
73+
74+
def holder = new DefaultUrlMappingsHolder(mappings)
75+
76+
def m = holder.getReverseMapping("product", "show", "foo", null, [:])
77+
assertNotNull "getReverseMapping returned null", m
78+
79+
assertEquals "/foo/product/show", m.createURL("product", "show", "foo", null, [:], "utf-8")
80+
}
81+
82+
6183
@Test
6284
void testGetReverseMappingWithNamedArgsAndClosure() {
6385
def res = new ByteArrayResource(mappingWithNamedArgsAndClosure.bytes)

grails-web-common/src/main/groovy/org/grails/web/servlet/mvc/DefaultRequestStateLookupStrategy.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ private String getControllerNameInternal(GrailsWebRequest req) {
8383
return null;
8484
}
8585

86+
public String getControllerNamespace() {
87+
final GrailsWebRequest req = getWebRequest();
88+
if (req != null) {
89+
return req.getControllerNamespace();
90+
}
91+
return null;
92+
}
93+
8694
public String getActionName() {
8795
final GrailsWebRequest req = getWebRequest();
8896
if (req != null) {

grails-web-common/src/main/groovy/org/grails/web/servlet/mvc/GrailsRequestStateLookupStrategy.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ public interface GrailsRequestStateLookupStrategy {
4343
*/
4444
public String getControllerName();
4545

46+
/**
47+
* The controller namespace
48+
*
49+
* @return The controller namespace or null if not known
50+
*/
51+
public String getControllerNamespace();
52+
4653
/**
4754
* The action name for the given controller name
4855
*

grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/CachingLinkGenerator.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.Map;
1919

20+
import grails.util.GrailsStringUtils;
2021
import grails.web.mapping.LinkGenerator;
2122
import grails.web.mapping.UrlMapping;
2223
import grails.util.GrailsMetaClassUtils;
@@ -120,6 +121,13 @@ private void appendMapKey(StringBuilder buffer, Map map) {
120121
}
121122
appendKeyValue(buffer, map, key, value);
122123
}
124+
if (map.get(UrlMapping.NAMESPACE) == null) {
125+
String namespace = getRequestStateLookupStrategy().getControllerNamespace();
126+
if (GrailsStringUtils.isNotEmpty(namespace)) {
127+
appendCommaIfNotFirst(buffer, first);
128+
appendKeyValue(buffer, map, UrlMapping.NAMESPACE, namespace);
129+
}
130+
}
123131
buffer.append(CLOSING_BRACKET);
124132
}
125133

grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/DefaultLinkGenerator.groovy

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,19 +243,19 @@ class DefaultLinkGenerator implements LinkGenerator, org.codehaus.groovy.grails.
243243
params.put(ATTRIBUTE_ID, id)
244244
}
245245
def pluginName = attrs.get(UrlMapping.PLUGIN)?.toString()
246-
def namespace = attrs.get(UrlMapping.NAMESPACE)?.toString()
246+
def namespace = attrs.get(UrlMapping.NAMESPACE)?.toString() ?: requestStateLookupStrategy.controllerNamespace
247247
UrlCreator mapping = urlMappingsHolder.getReverseMappingNoDefault(controller,action,namespace,pluginName,httpMethod,params)
248248
if (mapping == null && isDefaultAction) {
249249
mapping = urlMappingsHolder.getReverseMappingNoDefault(controller,null,namespace,pluginName,httpMethod,params)
250250
}
251251
if (mapping == null) {
252-
mapping = urlMappingsHolder.getReverseMapping(controller,action,pluginName,httpMethod,params)
252+
mapping = urlMappingsHolder.getReverseMapping(controller,action,namespace,pluginName,httpMethod,params)
253253
}
254254

255255
boolean absolute = isAbsolute(attrs)
256256

257257
if (!absolute) {
258-
url = mapping.createRelativeURL(convertedControllerName, convertedActionName, params, encoding, frag)
258+
url = mapping.createRelativeURL(convertedControllerName, convertedActionName, namespace, pluginName, params, encoding, frag)
259259
final contextPathAttribute = attrs.get(ATTRIBUTE_CONTEXT_PATH)
260260
final cp = contextPathAttribute == null ? getContextPath() : contextPathAttribute
261261
if (attrs.get(ATTRIBUTE_BASE) || cp == null) {
@@ -268,7 +268,7 @@ class DefaultLinkGenerator implements LinkGenerator, org.codehaus.groovy.grails.
268268
writer.append url
269269
}
270270
else {
271-
url = mapping.createRelativeURL(convertedControllerName, convertedActionName, params, encoding, frag)
271+
url = mapping.createRelativeURL(convertedControllerName, convertedActionName, namespace, pluginName, params, encoding, frag)
272272
writer.append handleAbsolute(attrs)
273273
writer.append url
274274
}

grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/DefaultUrlMappingsHolder.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public int weightOf(List<UrlMappingInfo> values) {
8585
private Map<UrlMappingKey, UrlMapping> mappingsLookup = new HashMap<UrlMappingKey, UrlMapping>();
8686
private Map<String, UrlMapping> namedMappings = new HashMap<String, UrlMapping>();
8787
private UrlMappingsList mappingsListLookup = new UrlMappingsList();
88+
private Set<String> DEFAULT_NAMESPACE_PARAMS = CollectionUtils.newSet(
89+
UrlMapping.NAMESPACE, UrlMapping.CONTROLLER, UrlMapping.ACTION);
8890
private Set<String> DEFAULT_CONTROLLER_PARAMS = CollectionUtils.newSet(
8991
UrlMapping.CONTROLLER, UrlMapping.ACTION);
9092
private Set<String> DEFAULT_ACTION_PARAMS = CollectionUtils.newSet(UrlMapping.ACTION);
@@ -356,6 +358,27 @@ private UrlCreator resolveUrlCreator(final String controller,
356358
}
357359
}
358360
}
361+
if (mapping == null || (mapping instanceof ResponseCodeUrlMapping)) {
362+
Set<String> lookupParams = new HashSet<String>(DEFAULT_NAMESPACE_PARAMS);
363+
Set<String> paramKeys = new HashSet<String>(params.keySet());
364+
paramKeys.removeAll(lookupParams);
365+
lookupParams.addAll(paramKeys);
366+
UrlMappingKey lookupKey = new UrlMappingKey(null, null, null, pluginName, httpMethod, version,lookupParams);
367+
mapping = mappingsLookup.get(lookupKey);
368+
if (mapping == null) {
369+
lookupKey.httpMethod = UrlMapping.ANY_HTTP_METHOD;
370+
mapping = mappingsLookup.get(lookupKey);
371+
}
372+
if (mapping == null) {
373+
lookupParams.removeAll(paramKeys);
374+
UrlMappingKey lookupKeyModifiedParams = new UrlMappingKey(null, null, null, pluginName, httpMethod, version,lookupParams);
375+
mapping = mappingsLookup.get(lookupKeyModifiedParams);
376+
if (mapping == null) {
377+
lookupKeyModifiedParams.httpMethod = UrlMapping.ANY_HTTP_METHOD;
378+
mapping = mappingsLookup.get(lookupKeyModifiedParams);
379+
}
380+
}
381+
}
359382
UrlCreator creator = null;
360383
if (mapping == null || (mapping instanceof ResponseCodeUrlMapping)) {
361384
if (useDefault) {

grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/RegexUrlMapping.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ private void populateParameterList(Map paramValues, String encoding, StringBuild
558558
usedParams.add("controller");
559559
usedParams.add("action");
560560
usedParams.add("namespace");
561+
usedParams.add("plugin");
561562

562563
// A 'null' encoding will cause an exception, so default to 'UTF-8'.
563564
if (encoding == null) {

grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/mvc/UrlMappingsHandlerMapping.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import grails.web.mime.MimeTypeResolver
2525
import grails.web.http.HttpHeaders
2626
import org.grails.exceptions.ExceptionUtils
2727
import org.grails.web.servlet.mvc.GrailsWebRequest
28+
import org.grails.web.util.GrailsApplicationAttributes
2829
import org.grails.web.util.WebUtils
2930
import org.springframework.beans.factory.annotation.Autowired
3031
import org.springframework.util.Assert
@@ -162,6 +163,7 @@ class UrlMappingsHandlerMapping extends AbstractHandlerMapping {
162163
info.configure(webRequest)
163164
if(info instanceof GrailsControllerUrlMappingInfo) {
164165
request.setAttribute(MATCHED_REQUEST, info)
166+
request.setAttribute(GrailsApplicationAttributes.GRAILS_CONTROLLER_CLASS, ((GrailsControllerUrlMappingInfo)info).controllerClass)
165167
return info
166168
}
167169
else if(info.viewName || info.URI) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package org.codehaus.groovy.grails.web.mapping
2+
3+
import grails.util.GrailsWebMockUtil
4+
import org.grails.web.mapping.CachingLinkGenerator
5+
import org.grails.web.servlet.mvc.DefaultRequestStateLookupStrategy
6+
import org.grails.web.servlet.mvc.GrailsWebRequest
7+
import org.springframework.web.context.request.RequestContextHolder
8+
import spock.lang.Shared
9+
import spock.lang.Specification
10+
11+
/**
12+
* Tests for the {@link org.grails.web.mapping.CachingLinkGenerator} class
13+
*/
14+
class CachingLinkGeneratorSpec extends Specification {
15+
16+
@Shared
17+
MyCachingLinkGenerator linkGenerator
18+
19+
@Shared
20+
GrailsWebRequest request
21+
22+
void setup() {
23+
linkGenerator = new MyCachingLinkGenerator("http://grails.org/")
24+
request = GrailsWebMockUtil.bindMockWebRequest()
25+
linkGenerator.requestStateLookupStrategy = new DefaultRequestStateLookupStrategy(request)
26+
}
27+
28+
void cleanup() {
29+
RequestContextHolder.resetRequestAttributes()
30+
}
31+
32+
void "test namespace"() {
33+
given:
34+
String key
35+
36+
when: "not in the request or params"
37+
key = linkGenerator.makeKey([controller: "foo", action: "bar"])
38+
39+
then: "its not in the key"
40+
key == "link[controller:foo, action:bar]"
41+
42+
when: "its in the params"
43+
key = linkGenerator.makeKey([controller: "foo", action: "bar", namespace: "foo"])
44+
45+
then: "its in the key"
46+
key == "link[controller:foo, action:bar, namespace:foo]"
47+
48+
when: "its in the request"
49+
request.setControllerNamespace("fooReq")
50+
key = linkGenerator.makeKey([controller: "foo", action: "bar"])
51+
52+
then: "its in the key"
53+
key == "link[controller:foo, action:bar, namespace:fooReq]"
54+
55+
when: "its in the request and the params"
56+
request.setControllerNamespace("fooReq")
57+
key = linkGenerator.makeKey([controller: "foo", action: "bar", namespace: "fooParam"])
58+
59+
then: "params wins"
60+
key == "link[controller:foo, action:bar, namespace:fooParam]"
61+
}
62+
63+
64+
class MyCachingLinkGenerator extends CachingLinkGenerator {
65+
public MyCachingLinkGenerator(String serverBaseURL) {
66+
super(serverBaseURL)
67+
}
68+
69+
String makeKey(Map attrs) {
70+
super.makeKey(LINK_PREFIX, attrs)
71+
}
72+
}
73+
}

grails-web-url-mappings/src/test/groovy/org/codehaus/groovy/grails/web/mapping/LinkGeneratorSpec.groovy

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,39 @@ class LinkGeneratorSpec extends Specification {
285285
then:
286286
cacheKey == "somePrefix[resource:org.codehaus.groovy.grails.web.mapping.Widget->2]"
287287
}
288-
288+
289+
def 'link should take into affect namespace'() {
290+
given:
291+
final webRequest = GrailsWebMockUtil.bindMockWebRequest()
292+
MockHttpServletRequest request = webRequest.currentRequest
293+
linkParams.contextPath = ''
294+
295+
when: "A namespace is specified"
296+
linkParams.namespace = 'fooBar'
297+
linkParams.controller = 'one'
298+
linkParams.action = 'two'
299+
300+
then: "it exists in the url"
301+
link == '/fooBar/one/two'
302+
303+
when: "The namespace is in the request params"
304+
webRequest.setControllerNamespace("fooBarReq")
305+
linkParams.remove('namespace')
306+
linkParams.controller = 'one'
307+
linkParams.action = 'two'
308+
309+
then: "it exists in the url"
310+
link == '/fooBarReq/one/two'
311+
312+
when: "Params and the request attribute exist"
313+
webRequest.setControllerNamespace("fooBarReq")
314+
linkParams.namespace = 'fooBarParam'
315+
linkParams.controller = 'one'
316+
linkParams.action = 'two'
317+
318+
then: "params wins"
319+
link == '/fooBarParam/one/two'
320+
}
289321

290322
void cleanup() {
291323
RequestContextHolder.resetRequestAttributes()
@@ -294,8 +326,8 @@ class LinkGeneratorSpec extends Specification {
294326
protected getGenerator(boolean cache=false) {
295327
def generator = cache ? new CachingLinkGenerator(baseUrl, context) : new DefaultLinkGenerator(baseUrl, context)
296328
final callable = { String controller, String action, String namespace, String pluginName, String httpMethod, Map params ->
297-
[createRelativeURL: { String c, String a, Map parameterValues, String encoding, String fragment ->
298-
"/$controller/$action".toString()
329+
[createRelativeURL: { String c, String a, String n, String p, Map parameterValues, String encoding, String fragment ->
330+
"${namespace ? '/' + namespace : ''}/$controller/$action".toString()
299331
}] as UrlCreator
300332
}
301333
generator.grailsUrlConverter = new CamelCaseUrlConverter()

0 commit comments

Comments
 (0)