2

We have written a Springboot Rest Service, it internally uses Jackson for Serialisation / deserialisation of Json input / output of Rest APIs.

We do not want type conversion of primitives to / from String for API input / output.

We have disabled String to Primitive conversion using

spring.jackson.mapper.allow-coercion-of-scalars=false

But Primitive to String conversion is still being allowed.

e.g.

"name": 123,

from API is still deserialised to "123", Java data type of name is String here.

We have gone through Customize the Jackson ObjectMapper section of Spring Docs and does not look like there is anything in those enums that can be used.

Is there a way to achieve this without writing a custom ObjectMapper / Deserializer?

D159
  • 243
  • 1
  • 3
  • 11
  • 1
    Take a look on my answer to this question [Restrict string data type to only string types for request body in Spring boot 2.4 (Jackson)](https://stackoverflow.com/a/65461398/51591). You need to register custom deserialiser which throws exception for scalar values. – Michał Ziober Jan 07 '21 at 21:36
  • 1
    @MichałZiober : Your solution works, although with slight modification. ```token.isBoolean() || token.isNumeric() || !token.toString().equalsIgnoreCase("VALUE_STRING")``` Since String itself is a scalar, your solution as-is does not work for any Scalar type, including Strings. If you can post your comment as answer, can accept it as solution. – D159 Jan 08 '21 at 05:45

1 Answers1

1

We did not find any config property that achieves this, finally went with the solution posted by Michał Ziober.

package xyz;

import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.core.JsonToken;

import java.io.IOException;

public class StrictStringDeserializer extends StringDeserializer {
    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonToken token = p.currentToken();
        if (token.isBoolean()
                || token.isNumeric()
                || !token.toString().equalsIgnoreCase("VALUE_STRING")) {
            ctxt.reportInputMismatch(String.class, "%s is not a `String` value!", token.toString());
            return null;
        }
        return super.deserialize(p, ctxt);
    }
}



POJO Class

public class XyzAbc {

    // ...
    @JsonDeserialize(using = StrictStringDeserializer.class)
    private String name;
    // ...
}

D159
  • 243
  • 1
  • 3
  • 11
  • 1
    I'm glad to see you found a solution and improved implementation. I did not have time to post this as an answer and check your proposal. You can always upvote other my answer if it was helpful. – Michał Ziober Jan 11 '21 at 14:48