CustomDeserializer 没有默认(无参数)构造函数
CustomDeserializer has no default (no arg) constructor
我正在使用带有 RestTemplate 的 REST Api。我从 API 得到的响应有很多嵌套对象。这里有一个小片段作为例子:
"formularios": [
{
"form_data_id": "123006",
"form_data": {
"form_data_id": "123006",
"form_id": "111",
"efs": {
"1": {},
"2": "{\"t\":\"c\",\"st\":\"m\",\"v\":[{\"id\":\"3675\",\"l\":\"a) Just an example\",\"v\":\"1\"},{\"id\":\"3676\",\"l\":\"b) Another example.\",\"v\":\"2\"}]}"
}
}
我遇到的问题是大多数时候“1”实际上有内容,就像“2”一样,jackson 只是将它解析为对象 "efs" 上的字符串。但有时,就像在代码片段中一样,API 将其发送为空,而 jackson 将其作为一个对象,这给了我一个关于 START_OBJECT 的错误(不记得确切的错误,但这对这个问题并不重要)。
所以我决定制作一个自定义反序列化器,这样当 jackson 读取“1”时,它会忽略空对象并将其解析为空字符串。
这是我的自定义解串器:
public class CustomDeserializer extends StdDeserializer<Efs> {
public CustomDeserializer(Class<Efs> t) {
super(t);
}
@Override
public Efs deserialize(JsonParser jp, DeserializationContext dc)
throws IOException, JsonProcessingException {
String string1 = null;
String string2 = null;
JsonToken currentToken = null;
while ((currentToken = jp.nextValue()) != null) {
if (currentToken.equals(JsonToken.VALUE_STRING)) {
if (jp.getCurrentName().equals("1")) {
string1 = jp.getValueAsString();
} else {
string2 = jp.getValueAsString();
}
} else {
if (jp.getCurrentName().equals("2")) {
string2 = jp.getValueAsString();
}
}
}
return new Efs(string1, string2);
}
}
这就是我在收到来自 API 的响应时使用它的方式:
ObjectMapper mapper = new ObjectMapper();
SimpleModule mod = new SimpleModule("EfsModule");
mod.addDeserializer(Efs.class, new CustomDeserializer(Efs.class));
mapper.registerModule(mod);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
jsonMessageConverter.setObjectMapper(mapper);
messageConverters.add(jsonMessageConverter);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(messageConverters);
我遇到错误:
CustomDeserializer has no default (no arg) constructor
但我不知道自己做错了什么,也不知道如何解决。感谢您的帮助和对这个长问题的道歉,我想提供尽可能多的背景信息。
要求您有一个不带参数的默认构造函数。
你可以做的是创建一个(如果你真的不需要它,也可以替换另一个):
public class CustomDeserializer extends StdDeserializer<Efs> {
public CustomDeserializer() {
super(Efs.class);
}
...
}
还有一个用户可能会掉入的陷阱(就像我自己)。如果您将解串器声明为内部 class(不是静态嵌套 class),例如:
@JsonDeserialize(using = DomainObjectDeserializer.class)
public class DomainObject {
private String key;
public class DomainObjectDeserializer extends StdDeserializer<DomainObject> {
public DomainObjectDeserializer() {
super(DomainObject.class);
}
@Override
public DomainObject deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
// code
}
}
}
Jackson 使用不带参数的 Class#getDeclaredConstructor()(方法接受 vararg
),这意味着:给我一个默认(无参数)构造函数。当 Jackson 尝试创建 DomainObjectDeserializer
时,上面的代码将抛出异常,因为 javac
生成接受封闭 class 引用的构造函数。从技术上讲 DomainObjectDeserializer
没有默认构造函数。
出于好奇,您可以执行 DomainObjectDeserializer.class.getDeclaredConstructors()
并确保该方法执行 return 包含构造函数定义并包含 class 引用的单个元素数组。
DomainObjectDeserializer
应声明为 static
class。
这是一个很好的answer阅读更多细节。
我正在使用带有 RestTemplate 的 REST Api。我从 API 得到的响应有很多嵌套对象。这里有一个小片段作为例子:
"formularios": [
{
"form_data_id": "123006",
"form_data": {
"form_data_id": "123006",
"form_id": "111",
"efs": {
"1": {},
"2": "{\"t\":\"c\",\"st\":\"m\",\"v\":[{\"id\":\"3675\",\"l\":\"a) Just an example\",\"v\":\"1\"},{\"id\":\"3676\",\"l\":\"b) Another example.\",\"v\":\"2\"}]}"
}
}
我遇到的问题是大多数时候“1”实际上有内容,就像“2”一样,jackson 只是将它解析为对象 "efs" 上的字符串。但有时,就像在代码片段中一样,API 将其发送为空,而 jackson 将其作为一个对象,这给了我一个关于 START_OBJECT 的错误(不记得确切的错误,但这对这个问题并不重要)。
所以我决定制作一个自定义反序列化器,这样当 jackson 读取“1”时,它会忽略空对象并将其解析为空字符串。
这是我的自定义解串器:
public class CustomDeserializer extends StdDeserializer<Efs> {
public CustomDeserializer(Class<Efs> t) {
super(t);
}
@Override
public Efs deserialize(JsonParser jp, DeserializationContext dc)
throws IOException, JsonProcessingException {
String string1 = null;
String string2 = null;
JsonToken currentToken = null;
while ((currentToken = jp.nextValue()) != null) {
if (currentToken.equals(JsonToken.VALUE_STRING)) {
if (jp.getCurrentName().equals("1")) {
string1 = jp.getValueAsString();
} else {
string2 = jp.getValueAsString();
}
} else {
if (jp.getCurrentName().equals("2")) {
string2 = jp.getValueAsString();
}
}
}
return new Efs(string1, string2);
}
}
这就是我在收到来自 API 的响应时使用它的方式:
ObjectMapper mapper = new ObjectMapper();
SimpleModule mod = new SimpleModule("EfsModule");
mod.addDeserializer(Efs.class, new CustomDeserializer(Efs.class));
mapper.registerModule(mod);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
jsonMessageConverter.setObjectMapper(mapper);
messageConverters.add(jsonMessageConverter);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(messageConverters);
我遇到错误:
CustomDeserializer has no default (no arg) constructor
但我不知道自己做错了什么,也不知道如何解决。感谢您的帮助和对这个长问题的道歉,我想提供尽可能多的背景信息。
要求您有一个不带参数的默认构造函数。 你可以做的是创建一个(如果你真的不需要它,也可以替换另一个):
public class CustomDeserializer extends StdDeserializer<Efs> {
public CustomDeserializer() {
super(Efs.class);
}
...
}
还有一个用户可能会掉入的陷阱(就像我自己)。如果您将解串器声明为内部 class(不是静态嵌套 class),例如:
@JsonDeserialize(using = DomainObjectDeserializer.class)
public class DomainObject {
private String key;
public class DomainObjectDeserializer extends StdDeserializer<DomainObject> {
public DomainObjectDeserializer() {
super(DomainObject.class);
}
@Override
public DomainObject deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
// code
}
}
}
Jackson 使用不带参数的 Class#getDeclaredConstructor()(方法接受 vararg
),这意味着:给我一个默认(无参数)构造函数。当 Jackson 尝试创建 DomainObjectDeserializer
时,上面的代码将抛出异常,因为 javac
生成接受封闭 class 引用的构造函数。从技术上讲 DomainObjectDeserializer
没有默认构造函数。
出于好奇,您可以执行 DomainObjectDeserializer.class.getDeclaredConstructors()
并确保该方法执行 return 包含构造函数定义并包含 class 引用的单个元素数组。
DomainObjectDeserializer
应声明为 static
class。
这是一个很好的answer阅读更多细节。