I have a POST endpoint receiving json in the request body and is mapped to Map<String, Object>
.
The value can be of any string format, I am OK for Spring to auto convert "true"
or "false"
to Boolean
, "123"
to Integer
. But I do not like it to convert "123.456"
to Double
, I want it to leave it as is (String
).
Is there any way (preferably config in application.yml) to selectively stop Spring from auto converting number string in json to Double
only?
You can use the annotation @JsonDeserialize for Jackson.
Here follows an example model class that wraps the payload Map<String,Object> field and a controller class and the JSON deserialization class with the logic to accomplish what you want:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import za.co.twentysevenfour.excel.model.converter.ObjectMapDeserializer;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class TestPayloadWrapper implements Serializable {
private static final long serialVersionUID = 1L;
@JsonDeserialize(using = ObjectMapDeserializer.class)
private Map<String, Object> payload = new HashMap<>();
public TestPayloadWrapper() {}
public Map<String, Object> getPayload() {
return payload;
}
public void setPayload(Map<String, Object> payload) {
this.payload = payload;
}
}
Controller Class:
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import za.co.twentysevenfour.excel.model.jpa.TestPayloadWrapper;
import java.util.Map;
@RestController
public class PayloadController {
@RequestMapping(value = "/postEndpoint", method = RequestMethod.POST)
public Map<String, Object> postEndpoint(@RequestBody TestPayloadWrapper payload)
{
return payload.getPayload();
}
}
JsonDeserializer class:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class ObjectMapDeserializer extends JsonDeserializer<Map<String,Object>> {
@Override
public Map<String,Object> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
Map<String,Object> result = new HashMap<>();
ObjectNode objectNode = jsonParser.readValueAsTree();
objectNode.fieldNames().forEachRemaining(field -> {
JsonNode fieldValue = objectNode.get(field);
if(fieldValue.isBoolean()) {
result.put(field,fieldValue.asBoolean());
} else if(fieldValue.isInt()) {
result.put(field,fieldValue.asInt());
} else if(fieldValue.isLong()) {
result.put(field,fieldValue.asLong());
} else if(fieldValue.isDouble()) {
// Here you set the double as a string
result.put(field,fieldValue.asText());
} else {
result.put(field,fieldValue.asText());
}
});
return result;
}
}
This is not the prettiest of solutions, this is the only one I know, I guess you will need to extend and modify the deserializer class somewhat to cater for all value types but at least this gives you a solid example of how to do it for a specific field, I tested this and it works.
I however would suggest you always know the type of the values you will receive but I fully understand there will be certain scenarios where this might not be so.
The test json payload I used is as follow:
{
"payload" : { "testDouble" : 1.40 }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With