Reputation: 11
I am trying to accept a JSON array into a command object. The array looks like this:
[
{prop1:'a', 'prop2:'b', prop3:'c'},
{prop1:'d', 'prop2:'e', prop3:'f'},
{prop1:'g', 'prop2:'h', prop3:'i'},
...
]
I was trying to accept the array via a lazy list
class MyCommand {
List myList = ListUtils.lazyList([], FactoryUtils.instantiateFactory(Map))
}
but I get the following error:
InstantiateFactory: The constructor must exist and be public . Stacktrace follows:
Message: InstantiateFactory: The constructor must exist and be public
Line | Method
->> 113 | findConstructor in org.apache.commons.collections.functors.InstantiateFactory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 86 | <init> in ''
| 67 | getInstance . . . in ''
| 121 | instantiateFactory in org.apache.commons.collections.FactoryUtils
What is the correct syntax to accept an array of maps?
I am sending the data via remoteFunction
like so:
var params = '{"myList":' + JSON.stringify(myList) + '}';
${remoteFunction(controller: 'myController', action: 'myAction',
params: 'params', onSuccess: 'callback(data)')};
Is there a different method I should use?
Upvotes: 0
Views: 535
Reputation: 27220
You don't need to use a lazy list in your command object. You can simplify your code and let the built in data binding system initialize the List
lazily.
// grails-app/controllers/demo/DemoController.groovy
package demo
class DemoController {
def demo(MyCommand co) {
[command: co]
}
}
class MyCommand {
List<Map> data
}
You can send a request to that action with JSON that looks like this...
{"data": [
{prop1:'a', 'prop2:'b', prop3:'c'},
{prop1:'d', 'prop2:'e', prop3:'f'},
{prop1:'g', 'prop2:'h', prop3:'i'},
...
]}
When you do that the data binding system will create an instance of MyCommand
, it will initialize the data
property initially to be an empty List
and then will populate that List
with all of the Maps
represented in the JSON.
That code is in the project at https://github.com/jeffbrown/listofmaps. That project includes the following test which passes:
// test/unit/demo/DemoControllerSpec.groovy
package demo
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(DemoController)
class DemoControllerSpec extends Specification {
void "test binding a List of Map to a command object"() {
when:
request.method = 'POST'
request.json = '''
{"data": [
{"prop1":"a", "prop2":"b", "prop3":"c"},
{"prop1":"d", "prop2":"e", "prop3":"f"},
{"prop1":"g", "prop2":"h", "prop3":"i"}
]
}'''
def model = controller.demo()
def command = model.command
then:
command instanceof MyCommand
command.data instanceof List
command.data.size() == 3
command.data[0] instanceof Map
command.data[0].prop1 == 'a'
command.data[0].prop2 == 'b'
command.data[0].prop3 == 'c'
command.data[1] instanceof Map
command.data[1].prop1 == 'd'
command.data[1].prop2 == 'e'
command.data[1].prop3 == 'f'
command.data[2] instanceof Map
command.data[2].prop1 == 'g'
command.data[2].prop2 == 'h'
command.data[2].prop3 == 'i'
}
}
Upvotes: 1
Reputation: 19682
Map
is an interface, so you cannot instantiate it. You need to pick a concrete type to use, like HashMap
or LinkedHashMap
.
Upvotes: 0