我想识别通过POST
请求的请求正文发送的JSON中插入的不带引号(作为字符串)的数值:
例如,这将是错误的JSON格式,因为age字段不包含引号:
{
"Student":{
"Name": "John",
"Age": 12
}
}
正确的JSON格式为:
{
"Student":{
"Name": "John",
"Age": "12"
}
}
在我的代码中,我已经将age
字段的数据类型定义为String
,因此"12"
应该是正确的输入。但是,即使使用12
,也不会引发任何错误消息。
似乎Jackson会自动将数值转换为字符串。如何识别数值并返回消息?
这是我到目前为止尝试识别这些数值的方法:
public List<Student> getMultiple(StudentDTO Student) {
if(Student.getAge().getClass()==String.class) {
System.out.println("Age entered correctly as String");
} else{
System.out.println("Please insert age value inside inverted commas");
}
}
但是,插入年龄而不带引号的情况下,这不会在控制台上打印"Please insert age value inside inverted commas"
。
答案 0 :(得分:1)
默认情况下,当目标字段为String
类型时,Jackson会将标量值转换为String。这个想法是为String
类型创建一个自定义反序列化器,并注释掉转换部分:
package jackson.deserializer;
import java.io.IOException;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
public class CustomStringDeserializer extends StringDeserializer
{
public final static CustomStringDeserializer instance = new CustomStringDeserializer();
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.hasToken(JsonToken.VALUE_STRING)) {
return p.getText();
}
JsonToken t = p.getCurrentToken();
// [databind#381]
if (t == JsonToken.START_ARRAY) {
return _deserializeFromArray(p, ctxt);
}
// need to gracefully handle byte[] data, as base64
if (t == JsonToken.VALUE_EMBEDDED_OBJECT) {
Object ob = p.getEmbeddedObject();
if (ob == null) {
return null;
}
if (ob instanceof byte[]) {
return ctxt.getBase64Variant().encode((byte[]) ob, false);
}
// otherwise, try conversion using toString()...
return ob.toString();
}
// allow coercions for other scalar types
// 17-Jan-2018, tatu: Related to [databind#1853] avoid FIELD_NAME by ensuring it's
// "real" scalar
/*if (t.isScalarValue()) {
String text = p.getValueAsString();
if (text != null) {
return text;
}
}*/
return (String) ctxt.handleUnexpectedToken(_valueClass, p);
}
}
现在注册该反序列化器:
@Bean
public Module customStringDeserializer() {
SimpleModule module = new SimpleModule();
module.addDeserializer(String.class, CustomStringDeserializer.instance);
return module;
}
当发送整数并且需要String时,出现以下错误:
{“ timestamp”:“ 2019-04-24T15:15:58.968 + 0000”,“ status”:400,“ error”:“ Bad Request“,” message“:” JSON解析错误:无法反序列化以下实例
java.lang.String
个(共VALUE_NUMBER_INT个令牌);嵌套异常为 com.fasterxml.jackson.databind.exc.MismatchedInputException:无法 从VALUE_NUMBER_INT中反序列化java.lang.String
的实例 令牌\ n位于[来源:(PushbackInputStream);行:3,列:13] (通过参考链: org.hello.model.Student [\“ age \”])“”,“路径”:“ / hello / echo”}
答案 1 :(得分:1)
如果您使用的是Spring Boot,则默认情况下它将使用Jackson解析JSON。如this issue中所述,Jackson中没有配置选项可禁用此功能。解决方案是注册自定义JsonDeserializer
,一旦遇到JsonToken.VALUE_STRING
public class StringOnlyDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
if (!JsonToken.VALUE_STRING.equals(jsonParser.getCurrentToken())) {
throw deserializationContext.wrongTokenException(jsonParser, String.class, JsonToken.VALUE_STRING, "No type conversion is allowed, string expected");
} else {
return jsonParser.getValueAsString();
}
}
}
如果仅要将其应用于某些类或字段,则可以使用@JsonDeserialize
批注对其进行批注。例如:
public class Student {
private String name;
@JsonDeserialize(using = StringOnlyDeserializer.class)
private String age;
// TODO: Getters + Setters
}
或者,您可以通过注册SimpleModule
bean来注册自定义的Jackson模块,该bean使用StringOnlyDeserializer
自动反序列化所有字符串。例如:
@Bean
public Module customModule() {
SimpleModule customModule = new SimpleModule();
customModule.addDeserializer(String.class, new StringOnlyDeserializer());
return customModule;
}
这类似于what Eugen suggested。
如果您现在运行应用程序,并且经过了无效的期限,例如12
,12.3
或[12]
,它将抛出异常,并显示以下消息:
JSON parse error: Unexpected token (VALUE_NUMBER_FLOAT), expected VALUE_STRING: Not allowed to parse numbers to string; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (VALUE_NUMBER_FLOAT), expected VALUE_STRING: Not allowed to parse numbers to string\n at [Source: (PushbackInputStream); line: 3, column: 9] (through reference chain: com.example.xyz.Student[\"age\"])