Grails 1.3.5
When mapping to a new controller in my application:
"/order/$action/$id?" {
controller = "customerOrder"
}
the request for "/order/show/13" resolves to "/()/()?/(*)?" as seen here in the log:
17:53:02 DEBUG UrlMappingsFilter - Matched URI [/order/show/13] to URL mapping [/(*)/(*)?/(*)?], forwarding to [/grails/home/page.dispatch] with response [class org.codehaus.groovy.grails.web.sitemesh.GrailsContentBufferingResponse]
If I add this mapping:
"/order/show/13"{
controller = "customerOrder"
action = "show"
id = 13
}
It still resolves to "/()/()?/(*)?". I edited the mapping:
"/customerOrder/show/13"{
controller = "customerOrder"
action = "show"
id = 13
}
and the log reports:
18:50:08 DEBUG DefaultUrlMappingsHolder - Matched URI [/customerOrder/show/13] with pattern [/customerOrder/show/13], adding to posibilities
Later it also reports:
18:50:08 DEBUG DefaultUrlMappingsHolder - Matched URI [/customerOrder/show/13] with pattern [/(*)/(*)?/(*)?], adding to posibilities
I'm totally baffled on this one. Either way, it resolves the same. Ideas anyone?
Apparently, in 1.3.5, you have to use a named closure intstead of the function syntax when declaring a view function.
def show( Long id ) { }
versus
def show = {}
The latter is correct. If someone could shed some light as to why...
Related
I am probably missing something here as I am new to F#, however, I need the following:
open Microsoft.AspNetCore.Mvc
[<ApiController>]
[<Route("[controller]")>]
type MyController () =
inherit ControllerBase()
//[<HttpGet(Name = "Ip")>] doesn't work neither.
[<HttpGet>]
[<Route("[controller]/[action]")>]
member _.Ip() =
"192.168.199.2"
The URL: https://localhost:5001/my/ip should return: 192.168.199.2.
The error message I am getting instead:
{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-389e8d2f6bc3a342a3754b5c5ce7915f-7e6e851c78f47c4f-00","errors":{"id":["The value 'ip' is not valid."]}}
I don't have much experience with ASP.NET Core, but I think the problem is that you have a route set at both the class and member level. These are additive, so the actual URL of your Ip action is currently https://localhost:5001/my/my/ip.
To fix this, remove the Route attribute entirely from the class level, or remove the [controller] prefix from your member-level route:
[<ApiController>]
[<Route("[controller]")>] // controller is specified here, so...
type MyController() =
inherit ControllerBase()
[<HttpGet>]
[<Route("[action]")>] // ...no controller specified here
member _.Ip() =
"192.168.199.2"
We built an Grails (2.3.7) application where we are overriding the link(Map attr, String encoding = 'UTF-8') in DefaultLinkGenerator class. The reason we are doing this is to have the same URL throughout our application as it was business requirement from the customer. Basically in the overriding link() method, we are modifying the Map with new request parameters.
Now in Production we are seeing the following exception which occurs sporadically and we haven't been able to reproduce it locally.
2014-09-29 01:04:06,257 StackTrace ERROR Full Stack Trace:
java.lang.ArrayIndexOutOfBoundsException: 3
at org.codehaus.groovy.grails.web.mapping.UrlCreatorCache$ReverseMappingKey.<init>(UrlCreatorCache.java:196)
at org.codehaus.groovy.grails.web.mapping.UrlCreatorCache.createKey(UrlCreatorCache.java:62)
at org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingsHolder.getReverseMappingNoDefault(DefaultUrlMappingsHolder.java:265)
at org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingsHolder.getReverseMappingNoDefault(DefaultUrlMappingsHolder.java:257)
at org.codehaus.groovy.grails.web.mapping.DefaultLinkGenerator.link(DefaultLinkGenerator.groovy:213)
at gov.texas.multitenant.core.mapping.MultitenantLinkGenerator.super$2$link(MultitenantLinkGenerator.groovy)
The code in 'UrlCreatorCache$ReverseMappingKey' that throws the above ArrayIndexOutOfException can happen only when Map attribute (params) gets mutated during the loop. The excerpt of that code is below.
paramKeys = new String[params.size()];
paramValues = new String[params.size()];
int i = 0;
for (Map.Entry entry : params.entrySet()) {
**paramKeys[i] = String.valueOf(entry.getKey());** //throws exception here
String value = null;
if (entry.getValue() instanceof CharSequence) {
value = String.valueOf(entry.getValue());
}
...
paramValues[i] = value;
i++;
}
Now my question is, does this Map attribute THREAD SAFE? Can it get mutated between threads since we are modifying it?
Any feedback will be great appreciated. Thanks in advance.
You wouldn't know inside that method - anything implementing the Map interface is allowable. But that's not important - you're causing the problem (by being one of two concurrent editors of an apparently non-threadsafe instance) and can easily fix it.
Instead of modifying the map, create a new one (any Map implementation will do since only your code and the code in that method can access it) and modify that, and pass that in for link generation. Then throw it away and use the real map for further calculations. Something like
def attrs = ... // the 'real' map
def copy = [:] + attrs
copy.foo = 42
copy.bar = 'a very high one indeed'
String link = linkGenerator.link(copy)
//
...
def foo = attrs.foo // not available, set in copy, but no longer using that
...
I'm having a hard time finding information about grails functionality:
DomainClass.properties = params
In my particular case, I have these classes:
class parameterType = {
String name
String desc
static hasMany = [codes : parameterCode]
...
}
class parameterCode = {
String code
String desc
static belongsTo = [parameterType : parameterType]
}
My parameterType/edit.gsp has name, desc and an html table with its list of parameterCodes
At first, I had some variation of the scaffolded controller on the 'update' action. That (I know its wrong but it was a beginners code) it first deleted all the parameterCodes and then reassociated them (or recreated them).
With Ajax I was sending the data in this format:
id=1234&name=paramName&desc=paramDesc&codes[0].code=code1&codes[0].desc=codeDesc1&codes[1].code=code2&codes[1].desc=codeDesc2
And in the controller I had this:
def parameterTypeInstance = ParameterType.get(params.id)
def toDelete = parameterTypeInstance.parameterCodes
parameterTypeInstance.parameterCodes = []
toDelete.each{it.delete(flush: true)}
//And this "magic" line reassociated all the properties in parameterType And Created his parameterCodes in the data base:
parameterTypeInstance.properties = params
I honestly don't how it works, and I just wanted to know if there's a way of doing the same thing without having to previously delete the associated parameterCodes.
Cheers
**Update:**
I just found what I was looking for in these links:
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/
But I had another error.
These talks about LazyList and decorate(), so I just added the next lines to my ParameterType Class:
def List getExpandableCodeList() {
return LazyList.decorate(codes,FactoryUtils.instantiateFactory(ParameterCode.class))
}
But when I do this in my controller update:
parameterTypeInstance.properties = params
I'm getting this error:
groovy.lang.MissingMethodException: No signature of method: static org.apache.commons.collections.list.LazyList.decorate() is applicable for argument types: (org.hibernate.collection.PersistentSet, org.apache.commons.collections.functors.InstantiateFactory) values: [[cE - EE, cA - AA, cC - CC, cD - DD], org.apache.commons.collections.functors.InstantiateFactory#dd768d]
The data is being recieved in the controller this way:
expandableCodeList[0].desc: AA
expandableCodeList[3].code: cE
expandableCodeList[3].id: 35073
expandableCodeList[1].id: 35076
expandableCodeList[0].code: cA
expandableCodeList[2].code: cD
expandableCodeList[1].desc: CC
expandableCodeList[0].id: 35080
expandableCodeList[3].desc: EE
expandableCodeList[2].id: 35075
Any hints on what I'm doing wrong? should I be sending the data in another format?
Any help would be much appreciated. Thanks.
If I not in error .properties is a method added by groovy to the java.lang.Object , look to this javaodc
There is many way to do what you want to do. Please look to grails documentation on data binding .
For example you can do
bindData(parameterTypeInstance, params, [exclude: parameterTypeInstance.parameterCodes])
look here for more info on bindData
Ok, I'm settings this as an answer:
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
At last, lazylist and the decorate() method was what I was looking for. Sadly it takes to take the child collection as a list and it carries out a lot of other issues for me. But its a good solution if anyone needs to make a view with the parent and its child objects the "simple" way.
I'm trying to call a method on a grails service from a controller, but it looks like execution is just skipping the method call.
I've tried debugging the application with a breakpoint inside the method but it is never hit.
My service (generated with grails create-service) is:
class FormatterService {
static transactional = false
def formatList (List<Host>, String fmt) {
OutputObject somePOGO = new OutputObject();
(snip)
return somePOGO
}
}
Then on my controller I have:
class HostController {
def formatterService
def getHostsByLabels = {
(snip)
OutputObject o = formatterService.formatList(someHosts,params.format)
(snip)
}
}
When the formatterService.formatList method should be called in the controller, execution simply skips to the next line, no output is printed to the console and breakpoints within the method are not hit. The OutputObject o reference is null afterward.
What is wrong here? It could be a really basic mistake from my part, but I just can't put my finger on it...
To Me it seems a MetaProgramming Disaster..
Well there are 3 Tests to Debug:
_1) first try to do
println formatterService
println formatterService.getClass()
just to check if its injected bean is the desired one, some plugins sometimes inject beans which overrides the default.
_2) Make sure that the method with a name "formatList" is not injected in your services through metaprogramming by any plugin or core code.
How to test this is simple: Just change the name of the method to some Unrealistic One, ex: "formatListabcdewdw" and then call that one. If it works then its method overriden issue.
and if you are more enthusiastic you can see the metaMethods by
println formatterService.metaClass.methods
_3) just try to do "params.format as String" as the last argument in the method call.\
.
Hope any of these helps, please Do let me know of the findings, i am curious to know.. :)
I found the issue. It has to do with the method signature.
Printing out the thrown exception's message, it says:
No signature of method: hms.FormatterService.formatList() is applicable for argument types: (java.util.TreeSet, java.lang.String) values: (...)
Possible solutions: formatList(java.util.List, java.lang.String)
So, a rookie mistake (wanting to pass a TreeSet for a List) aided by weak typing in Groovy... :P
I've changed the method signature to
def formatList ( items, String fmt) {
and call it as
def activeHosts = ...
OutputObject o = formatterService.formatList(activeHosts, params.format as String)
and now it works.
I have the following route registered;
routes.MapRoute(
"LocationsByArea",
"Locations/{system}/{storage}/{area}",
new { controller = "StorageLocation", action = "Index" },
null
);
...and the following code in my view;
<%= Html.ActionLink("Platser", "Index", "StorageLocation", new { system = Model.System, storage = Model.Storage, area = item.Name }, null)%>
My problem is when the "area = item.Name" contains a colon, e.g. "Area 4:1". If I click the rendered link I get HTTP-error 400, Bad reqest. I guess I have to encode my area parameter in some way, but I cant figure out how. Any help is apreciated.
Thanks!
The built-in encoding/decoding does not work, so I suggest you roll your own, like this:
namespace MyProject.Helpers
{
public static class JobNameHelper
{
public static string JobNameEncode(string jobname)
{
return jobname.Replace(":", "---colon---");
}
public static string JobNameDecode(string jobname)
{
return jobname.Replace("---colon---", ":");
}
}
}
Can you not just use
Server.UrlEnconde(item.Name)
Or am I missing something?
In your routing you may have to use Server.UrlDecde as well although I think It should decode for you on request.
Try using the Routing Debugger to see what the url router is getting passed, then you can see where the decoding needs to happen
ASP.NET 3.5 SP1 and earlier have a number of restrictions on which URLs are valid. In ASP.NET 4 most of these issues have been fixes (or are at least customizable via web.config). I think that the colon character, even when encoded, might not be allowed in ASP.NET 3.5 SP1 and earlier due to security concerns. Allowing colons can be a security problem when performing file checks since they are a little-known syntax for NTFS Alternate Data Streams.
I recommend trying to choose a character other than a colon for these purposes. Maybe a comma, semi-colon, or equal sign might work instead?