No String-argument constructor/factory method to deserialize from String value ('')

JavaJsonSpring

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

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.

Solution 3 - Java

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.

Solution 4 - Java

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

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

instead of

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

Solution 5 - Java

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

Solution 6 - Java

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

Solution 7 - Java

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

Solution 8 - Java

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

Solution 9 - Java

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStephenView Question on Stackoverflow
Solution 1 - JavaAndrii PlotnikovView Answer on Stackoverflow
Solution 2 - JavaAbhijit SarkarView Answer on Stackoverflow
Solution 3 - JavapapaRomikView Answer on Stackoverflow
Solution 4 - JavaMatthiasView Answer on Stackoverflow
Solution 5 - JavaAbhilash RanjanView Answer on Stackoverflow
Solution 6 - Javaorly.sharonView Answer on Stackoverflow
Solution 7 - JavaCodingBeeView Answer on Stackoverflow
Solution 8 - JavaSauravView Answer on Stackoverflow
Solution 9 - JavaHerman XUView Answer on Stackoverflow