Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marshaling JSON and Generics in Java with Spring MVC

I'm trying to marshall a JSON object into a wrapper class that contains a generic object, as well as additional information about the object's signature.

public class Signable<T> {

    private T object;
    private String signature;

    public class Signable() {
       generateSignature();
    }

    /* Getters and setters  */
}

The wrapper class works fine as long as I construct it with the object already created, and it is able to produce the desired json

@RequestMapping(value="/test/json/return",method=RequestMethod.GET)
public @ResponseBody Signable<Cart> getTest()
{
    Cart cart = new Cart();
    // populate cart with OrderItems ...
    Signable<Cart> sign = new Signable<Cart>();
    sign.setObject(cart);
    return sign;
}

which is able to generate the expected output

{
   "object":{
        "orderItems":[
              {
                  "id": "****",
                  "desc": "asdlfj",
                  "price": 25.53
              }
        ]
   },
   "signature":"s9d94f9f9gdfg67d8678g6s87d6f7g6";
}

Which is the format I want. However, when trying to marshal the same json generated from Signable back into Signable, I receive the following error:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to Cart

For some reason it's not able to determine that "object" in the json should be mapped to the type of Cart (it just defaults to the LinkedHashMap), even though it's specified in method header.

@RequestMapping(value="/test/json/post",method=RequestMethod.POST)
public @ResponseBody Signable<Cart> postTest(@RequestBody Signable<Cart> sign)

Is there a way to explicitly say which types of objects you want to generate from the JSON to insert in place of a generic?

Any help would be greatly appreciated.

Thanks.

like image 938
Craig Kochis Avatar asked Jul 21 '11 17:07

Craig Kochis


2 Answers

The issue here is that of passing proper type information, to fill in missing info (which occurs due to Java type erasure).

But the easiest way is often to just sub-class type you want, to have something like:

class CartSignable extends Signable<Cart>  { }

and use that, instead of constructing generic instance; and if so, type information is correctly included (since it is stored in class definition of CartSignable; whereas Signable only has type variable!).

Jackson can take in type information during serialization as well, but the issue here is that of how Spring would pass such information. So it is usually easier to just use sub-classing style. Note that you can use anonymous inner-classes for sub-classing as well.

like image 166
StaxMan Avatar answered Oct 07 '22 15:10

StaxMan


I ended up extending

class ListMyObject extends ArrayList<MyObject>  { }

thanks StaxMan -- great help
PS: the json format > [{"id":"1", "mountain":2},{"id":"3", "mountain":7}]

like image 4
Imtiaz Mirza Avatar answered Oct 07 '22 15:10

Imtiaz Mirza