没有字符串参数的构造函数/工厂方法可以从字符串值('')反序列化。

128

当我使用来自 com.fasterxml.jackson.databind 包的 ObjectMapper 类时,遇到了一个 JSON 解析问题,错误信息如下:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.graybar.utilities.ups.beans.Address: no String-argument constructor/factory method to deserialize from String value ('')

这个问题发生的Web应用程序是一个使用AngularJS前端的Spring MVC应用程序,但我可以通过一个更小的、完全由Java编写的程序复制该问题。以下是我的bean:

Shipment.java

@JsonIgnoreProperties(ignoreUnknown = true)
public class Shipment {
    @JsonProperty("Activity")
    private ArrayList<Activity> activity;
    public ArrayList<Activity> getActivity() {
        return activity;
    }
    public void setActivity(ArrayList<Activity> activity) {
        this.activity = activity;
    }
}

Activity.java

@JsonIgnoreProperties(ignoreUnknown = true)
public class Activity {
    @JsonProperty("ActivityLocation")
    private ArrayList<ActivityLocation> activityLocation;
    public ArrayList<ActivityLocation> getActivityLocation() {
        return activityLocation;
    }
    public void setActivityLocation(ArrayList<ActivityLocation> activityLocation) {
        this.activityLocation = activityLocation;
    }
}

ActivityLocation.java

@JsonIgnoreProperties(ignoreUnknown = true)
public class ActivityLocation {
    @JsonProperty("Address")
    private Address address;
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
}

Address.java

@JsonIgnoreProperties(ignoreUnknown = true)
public class Address {
    @JsonProperty("City")
    private String city;
    @JsonProperty("StateProvinceCode")
    private String stateProvinceCode;
    @JsonProperty("CountryCode")
    private String countryCode;
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getCountryCode() {
        return countryCode;
    }
    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }
    public String getStateProvinceCode() {
        return stateProvinceCode;
    }
    public void setStateProvinceCode(String stateProvinceCode) {
        this.stateProvinceCode = stateProvinceCode;
    }
}

以下是我可以正确映射JSON的代码:

public static void main(String[] args) {
    String jsonMessage = "" +
        "{" + 
        "   \"Activity\": [{ " +
        "       \"ActivityLocation\": { " +
        "           \"Address\": { " +
        "               \"City\": \"Hana\", " +
        "               \"StateProvinceCode\": \"Hi\", " +
        "               \"CountryCode\": \"US\" " +
        "           } " +
        "       } " +
        "   }, " +
        "   { " +
        "       \"ActivityLocation\": { " +
        "           \"Address\": { " +
        "               \"City\": \"Honolulu\", " +
        "               \"StateProvinceCode\": \"Hi\", " +
        "               \"CountryCode\": \"US\" " +
        "           } " +
        "       } " +
        "   }] " +
    "} ";

    try {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

        Shipment shipment = mapper.readValue(jsonMessage, Shipment.class);
        System.out.println("shipment.toString = " + shipment.toString());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

当调整jsonMessage变量中的数据时,我遇到了上述提到的错误:

    "{" + 
    "   \"Activity\": [{ " +
    "       \"ActivityLocation\": { " +
    "           \"Address\": { " +
    "               \"City\": \"Hana\", " +
    "               \"StateProvinceCode\": \"Hi\", " +
    "               \"CountryCode\": \"US\" " +
    "           } " +
    "       } " +
    "   }, " +
    "   { " +
    "       \"ActivityLocation\": { " +
    "           \"Address\": \"\" " +
    "           } " +
    "       } " +
    "   }] " +
    "} ";

那么,当将json从这样的格式更改时会出现问题:

{
    "ActivityLocation": { 
        "Address": {
            "City": "Honolulu", 
            "StateProvinceCode": "Hi", 
            "CountryCode": "US"
        }
    }
}]

变成这样:

{
"ActivityLocation": {
     "Address": ""
    }
}

我收到的数据中,我的Address对象的属性值都是空字符串。但很遗憾的是,这些数据是从第三方那里接收到的,我无法控制。

是否需要添加注释来处理这个问题?

12个回答

173

当我不小心拨打电话时,遇到了这个。

mapper.convertValue(...)

替代

mapper.readValue(...)

因此,请确保您调用正确的方法,因为参数相同且IDE可以找到许多内容。


3
@AbhijitSarkar 什么?问题是错误 "没有String-argument构造函数/工厂方法进行反序列化....."。SO必须提供答案,不仅仅是TS特定的问题,而是整个问题。我曾经遇到过这个问题,只是输入略有不同,但是正在处理完全相同的故障排除过程。我发布了我的答案,因为它可能有助于调试这个特定的问题,但情况稍有改变。第二点是人们将搜索这个输入的问题,这可能会对他们有所帮助。输入是相同的,情况是不同的。 - Andrii Plotnikov
4
我遇到了同样的异常。这个答案对我有帮助。 - ald.li
4
我遇到了同样的异常。这个答案解决了我的问题。 - arcy
17
这是其中一个问题,需要寻找一个平衡点来解决。 - Paweł Nadolski
4
这个答案在过去一周内帮了我两次忙。(真是羞愧) - Ari Bustamante
显示剩余2条评论

65

尝试设置

mapper.configure(
          DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,
          true)
或者
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

根据您的Jackson版本而定。


8
如果我解析的 JSON 没有任何空白或 null 值,那么抛出这个异常的原因是什么呢?我只是想全面地了解一下。 - Kervvv
@Kervvv 如果输入没有任何空字符串,则不会抛出此异常。 - Abhijit Sarkar

15
这个异常提示你试图从字符串 "\"\"" 反序列化对象"Address",而不是类似于 "{...}" 的对象描述。反序列化器无法找到带有字符串参数的Address构造函数。你需要用{}来替换""以避免这个错误。

2
这个异常的原因非常明确!在阅读了这条评论后,我立刻找到了bug!谢谢! - Deekshith Anand

7

使用以下代码片段,对我很有效

ObjectMapper objectMapper = new ObjectMapper();
String jsonString = "{\"symbol\":\"ABCD\}";
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
Trade trade = objectMapper.readValue(jsonString, new TypeReference<Symbol>() {});

模型类

@JsonIgnoreProperties    public class Symbol {
    @JsonProperty("symbol")
    private String symbol;
}

5

我也曾遇到同样的异常,因为我不小心引用了一个对象,例如:

{ "foo": "{ \"value\": 42}" }

替代

{ "foo": { "value": 42 } }

2
创建对象映射器 ->
private static final ObjectMapper objectMapper = new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);

然后使用

objectMapper.convertValue(object, value.class);

1

好的,我遇到了同样的错误,调试花费了很长时间。我传递的JSON具有以下结构

{
 "details": "id"
}

错误跟踪显示:No String-argument constructor/factory method to deserialize from String value ('id')

然而,POJO期望id是一个对象,而不是一个字符串。正确的方法应该是:

{
  "details": {
    "key": "id"
  }
}

1
我也遇到了这个问题,对我有效的解决方案是:
String jsonString="";
ObjectMapper objectMapper = new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
JsonNode jsonObj=objectMapper.readTree(jsonString);
TypeObject typeObject=objectMapper.convertValue(jsonObj, TypeObject.class);

0

异常的主要原因是尝试使用双引号”…”而不是花括号{…}进行反序列化。

Jackson将双引号解释为字符串。因此,它期望目标对象具有一个字符串参数构造函数或工厂方法。因此出现了错误没有字符串参数构造函数/工厂方法


0
在我的情况下,创建一个带有字符串参数的构造函数并用@JsonCreator进行注释是有帮助的:
    @JsonCreator
    public MyClass(String value) throws JsonProcessingException {
        MyClass root = objectMapper.readValue(value, MyClass.class);
        this.inst = root.getInst();
    }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接