1

I would like to be able to convert a generic Object in a request to a custom object that I have built using Spring Boot and Jackson.

For example, say I have the following controller method:

  @RequestMapping(value = "/user/action", method = RequestMethod.POST)
  public String processAction(@RequestBody Request theRequest){



    return "Success";
  }

Now the Request object looks like this:

public class Request {
  public Request(){

  }
  private String  action;
  private Object actionRequest;

//getters/setters

The actual actionRequest can be any Object (e.g. Boolean, String, or a custom built one).

So say I have a custom built ActionA class:

public class ActionA {
  public ActionA(){

  }
  private int actionAInfo;

  //getters/setters
}

If I invoke my controller with a POST and a payload of

{"action": "startEstimate", "actionRequest":true}

when it reaches the method, the 'actionRequest' is already converted to a boolean.

However, if I provide the payload

{"action": "startEstimate", "actionRequest": {"actionAInfo": 5}}

the 'actionRequest' is just converted to a HashMap with key of 'actionAInfo' and value of '5'.

How can I configure Spring Boot/Jackson to create the ActionA object?

One workaround I have seen is to instead of having Object in the Request, use ObjectNode. Then do something similar to

ObjectMapper om = new ObjectMapper();
ActionA actionA = om.convertValue(theRequest.getActionRequest(), ActionA.class);

However, this does not expand as I add more actions because I would need to know the type before I attempt to build it.

I have also attempted a solution presented here Custom JSON Deserialization with Jackson

and it does not seem to be working. I have created a new ActionADeserializer

public class ActionADeserializer extends JsonDeserializer<ActionA> {

  @Override
  public ActionA deserialize(JsonParser jp, DeserializationContext ctxt) throws
                                                                         IOException,
                                                                         JsonProcessingException {
    return jp.readValueAs(ActionA.class);
  }
}

and altered ActionA class to have

@JsonDeserialize(using = ActionADeserializer.class)
public class ActionA 

When I submit the payload

{"action": "startEstimate", "actionRequest": {"actionAInfo": 5}} 

it still creates the HashMap instead of the ActionA object. I set a breakpoint in the deserializer and do not even see it being invoked.

Community
  • 1
  • 1
  • You need write your custom deserializer for the field. Look at this question: http://stackoverflow.com/questions/19158345/custom-json-deserialization-with-jackson – Andremoniy Feb 08 '17 at 20:55
  • Possible duplicate of [Custom JSON Deserialization with Jackson](http://stackoverflow.com/questions/19158345/custom-json-deserialization-with-jackson) – Andremoniy Feb 08 '17 at 20:55
  • There is an important thing that most developers overlook when asking questions like this (and the reason you always get a HashMap). In Java a class is defined by a name, in JavaScript objects are nameless, and are defined by their properties. If you look at how Jackson handles polymorphic hierarchies, you will see that it requires a field to define the type, since you need to know which Java Class to instantiate and set the properties on. If you don't know the type, a json structure can always be mapped to a `Map`. Look at this, http://stackoverflow.com/a/30386694/2433323 – Klaus Groenbaek Feb 08 '17 at 23:49
  • Thank you for the suggestion @KlausGroenbaek. – springbootrookie Feb 09 '17 at 01:56
  • I tried adding @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include= JsonTypeInfo.As.PROPERTY, property="@class") to the ActionA class with a updated payload of {"@class": "com.townip.workflow.controller.ActionA", "actionAInfo": 5} Still just generates the map. In that example they extend from Animal with subtypes defined in Animal parent. In my case the parent is just Object. Should I be using my own custom parent instead instead of java.lang.Object? If I do that, I am guessing I would lose the auto conversion to the regular boolean/string/int types. – springbootrookie Feb 09 '17 at 02:04

0 Answers0