I have the following JSON sample:
{
"channel": "VTEX",
"data": "{}",
"refId": 143433.344,
"description": "teste",
"tags": ["tag1", "tag2"]
}
That should map to the following class:
public class AddConfigInput {
public String channel;
public String data;
public String refId;
public String description;
public String[] tags;
public AddConfigInput() {
}
}
Using a code like bellow:
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.ALLOW_COERCION_OF_SCALARS);
String json = STRING_CONTAINING_THE_PREVIOUS_INFORMED_JSON;
AddConfigInput obj = mapper.readValue(json, AddConfigInput.class);
System.out.println(mapper.writeValueAsString(obj));
That produces as output:
{"channel":"VTEX","data":"{}","refId":"143433.344","description":"teste","tags":["tag1","tag2"]}
Please note that the field refId is of type String and I want to avoid this kind of automatic conversion from Numbers to String properties. Instead I want to Jackson throws an error about the type mismatch. How can I do that?
Check if it works for you.
I have added a custom deserializer for attribute refId, there I am checking the type and in case there is a data type mismatch throwing Exception.
Custom deserializer used for force datatype check.
KeepStringDeserializer.java
package oct2020.json;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class KeepStringDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException {
if (jsonParser.getCurrentToken() != JsonToken.VALUE_STRING) {
throw deserializationContext.wrongTokenException(jsonParser,
String.class, JsonToken.VALUE_STRING,
"Expected value is string but other datatype found.");
}
return jsonParser.getValueAsString();
}
}
AddConfigInput.java
For refId attribute using custom deserializer.
package oct2020.json;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class AddConfigInput {
public String channel;
public String data;
@JsonDeserialize(using = KeepStringDeserializer.class)
public String refId;
public String description;
public String[] tags;
public AddConfigInput() {
}
}
TestClient.java
package oct2020.json;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TestClient {
public static void main(String[] args) throws JsonMappingException,
JsonProcessingException {
String json = "{\n \"channel\": \"VTEX\",\n \"data\": \"{}\",\n \"refId\": 143433.344,\n \"description\": \"teste\",\n \"tags\": [\"tag1\", \"tag2\"]\n}\"";
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.ALLOW_COERCION_OF_SCALARS);
AddConfigInput obj = mapper.readValue(json, AddConfigInput.class);
System.out.println(mapper.writeValueAsString(obj));
}
}
Output:
Case1: data mismatch
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (VALUE_NUMBER_FLOAT), Expected value is string but other datatype found.
at [Source: (String)"{
"channel": "VTEX",
"data": "{}",
"refId": 143433.344,
"description": "teste",
"tags": ["tag1", "tag2"]
}""; line: 4, column: 14] (through reference chain: oct2020.json.AddConfigInput["refId"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
Case2: Correct data
Input:
String json = "{\n \"channel\": \"VTEX\",\n \"data\": \"{}\",\n \"refId\": \"143433.344\",\n \"description\": \"teste\",\n \"tags\": [\"tag1\", \"tag2\"]\n}\"";
Output:
{"channel":"VTEX","data":"{}","refId":"143433.344","description":"teste","tags":["tag1","tag2"]}
It seems that mapper.disable(MapperFeature.ALLOW_COERCION_OF_SCALARS);
works for the reverse case, that is, parsing fails when deserializing String
value to numeric field.
Providing custom deserializer for the refId
field seems to resolve this issue.
public class AddConfigInput {
public String channel;
public String data;
//@JsonDeserialize(using = ForceStringDeserializer.class)
public String refId;
public String description;
public String[] tags;
public AddConfigInput() {
}
}
public class ForceStringDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException
{
if (jsonParser.getCurrentToken() != JsonToken.VALUE_STRING) {
deserializationContext.reportWrongTokenException(
String.class, JsonToken.VALUE_STRING,
"Attempted to parse token %s to string",
jsonParser.getCurrentToken());
}
return jsonParser.getValueAsString();
}
}
Update
This custom deserializer may be registered within the ObjectMapper
and override default behaviour:
public class ForcedStringParserModule extends SimpleModule {
private static final long serialVersionUID = 1L;
public ForcedStringParserModule() {
this.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(
DeserializationConfig config, BeanDescription beanDesc,
JsonDeserializer<?> deserializer)
{
if (String.class.isAssignableFrom(beanDesc.getBeanClass())) {
return new ForceStringDeserializer();
}
return deserializer;
}
});
}
}
Then this module can be registered with ObjectMapper
:
mapper.registerModule(new ForcedStringParserModule ());
After modifying slightly the input JSON (using boolean for data
field which must be String), the following exception is thrown:
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException:
Unexpected token (VALUE_FALSE), expected VALUE_STRING:
Attempted to parse token VALUE_FALSE to string
at [Source: (String)"{
"channel": "VTEX",
"data": false,
"refId": "143433.344",
"description": "teste",
"tags": ["tag1", "tag2"]
}"; line: 3, column: 13]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.