Search code examples
jsonpostspring-roo

Spring Roo AJAX POST: "java.lang.Integer cannot be cast to java.util.Map"


I have a standard Spring Roo project that I'm trying to use as a REST API to a database, using Web MVC and the automatically-generated JSON controllers. I'm trying to send a POST request to create an object via either form data or JSON (preferably JSON), but I'm receiving fairly strange behaviour.

My hierarchical entity has an optional reference to itself as a parent. It looks like this:

public class LandType {
    private String name;
    private String description;

    @ManyToOne
    private LandType parent;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
    private Set<LandType> children = new HashSet<LandType>();

    @ManyToMany(cascade = CascadeType.ALL)
    private Set<Param> params = new HashSet<Param>();
}

When I try to create a new instance via a JSON POST request without a value for parent (with just name and description), it works. When I try to create it with a parent value (I use the parent ID as an integer, since that's what the stock Roo form does), I get the Spring error:

java.lang.Integer cannot be cast to java.util.Map

I don't know what it's doing trying to convert anything to a map, and following it through with a debugger makes little sense. It goes in via the controller, into fromJsonToLandType, then tries to deserialise and eventually throws the exception:

flexjson.factories.BeanObjectFactory.instantiate(BeanObjectFactory.java:17)
flexjson.ObjectBinder.bind(ObjectBinder.java:86)
flexjson.ObjectBinder.bindIntoObject(ObjectBinder.java:139)
flexjson.factories.ClassLocatorObjectFactory.instantiate(ClassLocatorObjectFactory.java:38)
flexjson.ObjectBinder.bind(ObjectBinder.java:86)
flexjson.ObjectBinder.bind(ObjectBinder.java:65)
flexjson.JSONDeserializer.deserialize(JSONDeserializer.java:158)
...

The same kind of thing happens when I try to pass in an array of parameters as {..., 'params': [10, 11]}. It seems like Spring Roo doesn't quite know how to handle JSON inputs for non-primitive types, or I don't know what format to provide them in. What am I doing wrong here?

Edit

I'm mainly testing this with curl to control exactly what goes in. An example call would be:

> curl -i -X POST -H "Content-type: application/json" -d "{'name':'test', 'description': 'test', 'parent': 8}" http://localhost:8080/mutopia-server/landtypes

... where 8 is the ID of an existing LandType, and again, removing parent makes it work. Strangely enough, I've got the call working for standard form data via the standard Roo controller (replace -H "Content-type: application/json" with -H "Accept: text/html"), so it's not as urgent an issue, but eventually I'll need a fully-operational JSON REST API. Adding Accept: application/json doesn't help either, since the JSON controller is by this point being called, but something funky is going on inside.


Solution

  • So the reason is that Flexjson (the deserialiser) is expecting a set (or JSON array) or Param objects (in JSON object form), but instead it finds an array of integers. Since Flexjson doesn't know anything about Spring or Roo, it doesn't recognise the integers as IDs and look them up with the appropriate Finder as I had naively hoped it would.

    The solution seems to be to manually parse out these kinds of ID references in the controller before calling the JSONDeserializer.deserialize(). Perhaps one day this could become a feature of the @RooJson addon (related issue), but not yet.