No String-Argument Constructor/Factory Method to Deserialize from String Value ('')

I'm running into a json parsing issue when using the ObjectMapper class from the com.fasterxml.jackson.databind package, and the error that I'm getting is:

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 ('')

The web application where this problem is occurring is a Spring MVC application using an AngularJS front end, but I can duplicate the issue with a much smaller, all java program. Here are my beans:

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;
    }
}

Here is the code where I can properly map the 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();
    }
}

When adjusting the data in the jsonMessage var is when I run into the error that I mentioned above:

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

So, the problem happens when changing the json from this:

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

to this:

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

Instead of sending values for my Address bean, I'm getting just an empty string. Unfortunately, I'm receiving my data from a third party and have no control over the data I receive.

Is there an annotation that needs to be added to be able to handle this?

0

9 Answers

Had this when I accidentally was calling

mapper.convertValue(...)

instead of

mapper.readValue(...)

So, just make sure you call correct method, since argument are same and IDE can find many things

6

Try setting

mapper.configure(
          DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,
          true)

or

mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

depending on your Jackson version.

2

This exception says that you are trying to deserialize the object "Address" from string "\"\"" instead of an object description like "{…}". The deserializer can't find a constructor of Address with String argument. You have to replace "" by {} to avoid this error.

1

I received the same exception because I accidentally quoted an object like

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

instead of

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

Use below code snippet This worked for me

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>() {});

Model Class

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

Create Object Mapper as ->

private static final ObjectMapper objectMapper = new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);

and then use

objectMapper.convertValue(object, value.class);

Well, I encountered the same error and it took a long time to debug it. The JSON I was passing had this structure

{
 "details": "id"
}

And the error trace was No String-argument constructor/factory method to deserialize from String value ('id')

Whereas the pojo expected the id to be an object instead, so correct way would be

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

I found a different way to handle this error. (the variables is according to the original question)

   JsonNode parsedNodes = mapper.readValue(jsonMessage , JsonNode.class);
        Response response = xmlMapper.enable(ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,ACCEPT_SINGLE_VALUE_AS_ARRAY )
                .disable(FAIL_ON_UNKNOWN_PROPERTIES, FAIL_ON_IGNORED_PROPERTIES)
                .convertValue(parsedNodes, Response.class);
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

My code work well just as the answer above. The reason is that the json from jackson is different with the json sent from controller.

String test1= mapper.writeValueAsString(result1);

And the json is like(which can be deserialized normally):

{"code":200,"message":"god","data":[{"nics":null,"status":null,"desktopOperatorType":null,"marker":null,"user_name":null,"user_group":null,"user_email":null,"product_id":null,"image_id":null,"computer_name":"AAAA","desktop_id":null,"created":null,"ip_address":null,"security_groups":null,"root_volume":null,"data_volumes":null,"availability_zone":null,"ou_name":null,"login_status":null,"desktop_ip":null,"ad_id":null},{"nics":null,"status":null,"desktopOperatorType":null,"marker":null,"user_name":null,"user_group":null,"user_email":null,"product_id":null,"image_id":null,"computer_name":"BBBB","desktop_id":null,"created":null,"ip_address":null,"security_groups":null,"root_volume":null,"data_volumes":null,"availability_zone":null,"ou_name":null,"login_status":null,"desktop_ip":null,"ad_id":null}]}

but the json send from the another service just like:

{"code":200,"message":"查询桌面列表成功","data":[{"nics":"","status":"","metadata":"","desktopOperatorType":"","marker":"","user_name":"csrgzbsjy","user_group":"ADMINISTRATORS","user_email":"","product_id":"","image_id":"","computer_name":"B-jiegou-all-15","desktop_id":"6360ee29-eb82-416b-aab8-18ded887e8ff","created":"2018-11-12T07:45:15.000Z","ip_address":"192.168.2.215","security_groups":"","root_volume":"","data_volumes":"","availability_zone":"","ou_name":"","login_status":"","desktop_ip":"","ad_id":""},{"nics":"","status":"","metadata":"","desktopOperatorType":"","marker":"","user_name":"glory_2147","user_group":"ADMINISTRATORS","user_email":"","product_id":"","image_id":"","computer_name":"H-pkpm-all-357","desktop_id":"709164e4-d3e6-495d-9c1e-a7b82e30bc83","created":"2018-11-09T09:54:09.000Z","ip_address":"192.168.2.235","security_groups":"","root_volume":"","data_volumes":"","availability_zone":"","ou_name":"","login_status":"","desktop_ip":"","ad_id":""}]}

You can notice the difference when dealing with the param without initiation. Be careful

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

James H. Sterling

James H. Sterling

Environmental Science & Climate Journalist

James Sterling reports on renewable energy developments, climate policy, ecological conservation, and green tech innovations around the globe.

Share this article
Twitter Facebook Pinterest