I've been pulling my hair out on this one for days. I can't figure out what is happening. I am developing a WebApp using GWT which communicates with a different server using RestAPI. I use Jersey client to communicate to a different server from the Server part of the GWT project.
Essentially, i am having problems with Jackson parsing the JSON returned from the RestAPI server. The JSON objects it is parsing are used successfully in an Android application as well as IOS applicaiton with no issues with the RestAPI server.
Essentially, to debug the issue, i took out the Jersey media plugin and have jersey just return a string of the object and then pass the string to an ObjectMapper. I am using the latest Jackson version 2.4.4.
I have a custom deserializer that works on the date format and the errors i receive are always with this date. The raw JSON looks fine but the Jackson object mapper throws an error. The error is not always in the same position but always with the lastInspectionDate. The error is sometimes saying the string is empty it is trying to parse, or the string is some weird values.
Here is some code hopefully to clarify:
The EstablishmentEntity class it is having trouble parsing:
@JsonIgnoreProperties(ignoreUnknown = true)
public class EstablishmentEntity {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
private String establishmentName;
public String getEstablishmentName() {
return establishmentName;
}
public void setEstablishmentName(String establishmentName) {
this.establishmentName = establishmentName;
}
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
private String city;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
private String county;
public String getCounty() {
return county;
}
public void setCounty(String county) {
this.county = county;
}
private String stateOrProvince;
public String getStateOrProvince() {
return stateOrProvince;
}
public void setStateOrProvince(String stateOrProvince) {
this.stateOrProvince = stateOrProvince;
}
private String postalCode;
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
private String telephone;
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
private String establishmentType;
public String getEstablishmentType() {
return establishmentType;
}
public void setEstablishmentType(String establishmentType) {
this.establishmentType = establishmentType;
}
@JsonSerialize(using = JsonDateOnlySerializer.class)
@JsonDeserialize(using = JsonDateOnlyDeserializer.class)
private Date lastInspectionDate;
public Date getLastInspectionDate() {
return lastInspectionDate;
}
public void setLastInspectionDate(Date lastInspectionDate) {
this.lastInspectionDate = lastInspectionDate;
}
private String lastInspectionScore;
public String getLastInspectionScore() {
return lastInspectionScore;
}
public void setLastInspectionScore(String lastInspectionScore) {
this.lastInspectionScore = lastInspectionScore;
}
@JsonSerialize(using = JsonDateOnlySerializer.class)
@JsonDeserialize(using = JsonDateOnlyDeserializer.class)
private Date lastInspectionScoreDate;
public Date getLastInspectionScoreDate() {
return lastInspectionScoreDate;
}
public void setLastInspectionScoreDate(Date lastInspectionScoreDate) {
this.lastInspectionScoreDate = lastInspectionScoreDate;
}
private String lastInspectionGrade;
public String getLastInspectionGrade() {
return lastInspectionGrade;
}
public void setLastInspectionGrade(String lastInspectionGrade) {
this.lastInspectionGrade = lastInspectionGrade;
}
@JsonSerialize(using = JsonDateOnlySerializer.class)
@JsonDeserialize(using = JsonDateOnlyDeserializer.class)
private Date lastInspectionGradeDate;
public Date getLastInspectionGradeDate() {
return lastInspectionGradeDate;
}
public void setLastInspectionGradeDate(Date lastInspectionGradeDate) {
this.lastInspectionGradeDate = lastInspectionGradeDate;
}
private String healthDepartment;
public String getHealthDepartment() {
return healthDepartment;
}
public void setHealthDepartment(String healthDepartment) {
this.healthDepartment = healthDepartment;
}
private boolean lastInspectionCritical;
public boolean isLastInspectionCritical() {
return lastInspectionCritical;
}
public void setLastInspectionCritical(boolean lastInspectionCritical) {
this.lastInspectionCritical = lastInspectionCritical;
}
private boolean lastInspectionPriority;
public boolean isLastInspectionPriority() {
return lastInspectionPriority;
}
public void setLastInspectionPriority(boolean lastInspectionPriority) {
this.lastInspectionPriority = lastInspectionPriority;
}
private boolean lastInspectionPriorityFoundation;
public boolean isLastInspectionPriorityFoundation() {
return lastInspectionPriorityFoundation;
}
public void setLastInspectionPriorityFoundation(boolean lastInspectionPriorityFoundation) {
this.lastInspectionPriorityFoundation = lastInspectionPriorityFoundation;
}
private double latitude;
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
private double longitude;
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
private Timestamp added;
public Timestamp getAdded() {
return added;
}
public void setAdded(Timestamp added) {
this.added = added;
}
private String geocoder;
public String getGeocoder() {
return geocoder;
}
public void setGeocoder(String geocoder) {
this.geocoder = geocoder;
}
private String geocoderVersion;
public String getGeocoderVersion() {
return geocoderVersion;
}
public void setGeocoderVersion(String geocoderVersion) {
this.geocoderVersion = geocoderVersion;
}
private Double hdscoreRankingPercent;
public Double getHdscoreRankingPercent() {
return hdscoreRankingPercent;
}
public void setHdscoreRankingPercent(Double hdscoreRankingPercent) {
this.hdscoreRankingPercent = hdscoreRankingPercent;
}
private String hdscoreProvider;
public String getHdscoreProvider() {
return hdscoreProvider;
}
public void setHdscoreProvider(String hdscoreProvider) {
this.hdscoreProvider = hdscoreProvider;
}
private Double hdscore;
public Double getHdscore() {
return hdscore;
}
public void setHdscore(Double hdscore) {
this.hdscore = hdscore;
}
private String hdscoreVersion;
public String getHdscoreVersion() {
return hdscoreVersion;
}
public void setHdscoreVersion(String hdscoreVersion) {
this.hdscoreVersion = hdscoreVersion;
}
}
The JSON Deserializer:
public class JsonDateOnlyDeserializer extends JsonDeserializer<Date> {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String dateString = jp.getText();
try {
return dateFormat.parse(dateString);
}
catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
The Raw JSON example (Cut off due to length):
{
"responseId":1,
"resultsLimited":true,
"totalResults":485651,
"geoHashLevel":2,
"items":[
{
"establishmentEntity":{
"id":469715,
"establishmentName":"PENNY'S KITCHEN",
"address":"822 W 14th St",
"city":"Coffeyville",
"county":"Montgomery",
"stateOrProvince":"KS",
"postalCode":"67337-4402",
"telephone":"9183317321",
"establishmentType":null,
"lastInspectionScore":null,
"lastInspectionGrade":null,
"healthDepartment":"State of Kansas",
"lastInspectionCritical":false,
"lastInspectionPriority":false,
"lastInspectionPriorityFoundation":false,
"latitude":37.02878,
"longitude":-95.625374,
"added":1409016435000,
"geocoder":"com.hdscores.inspection.source.geocoding.MapQuestLicensedGeocoder",
"geocoderVersion":"1.12",
"hdscoreRankingPercent":0.301823675,
"hdscoreProvider":"com.hdscores.inspection.hdscore.ViolationsHDScoreProvider",
"hdscore":4.373924497631436,
"hdscoreVersion":"1.04",
"lastInspectionDate":"2013-10-17",
"lastInspectionScoreDate":null,
"lastInspectionGradeDate":null
},
"preferredLevel":0,
"logoUrl":null,
"resultsTop":false,
"resultsBottom":false,
"featured":false,
"reportsViolations":true,
"displayName":"PENNY'S KITCHEN"
},
{
"establishmentEntity":{
"id":281253,
"establishmentName":"COFFEYVILLE LIVESTOCK MARKET",
"address":"822 W 14th St",
"city":"Coffeyville",
"county":"Montgomery",
"stateOrProvince":"KS",
"postalCode":"67337-4402",
"telephone":"6202515460",
"establishmentType":null,
"lastInspectionScore":null,
"lastInspectionGrade":null,
"healthDepartment":"State of Kansas",
"lastInspectionCritical":true,
"lastInspectionPriority":false,
"lastInspectionPriorityFoundation":false,
"latitude":37.02878,
"longitude":-95.625374,
"added":1405623496000,
"geocoder":"com.hdscores.inspection.source.geocoding.MapQuestLicensedGeocoder",
"geocoderVersion":"1.12",
"hdscoreRankingPercent":0.133052767,
"hdscoreProvider":"com.hdscores.inspection.hdscore.ViolationsHDScoreProvider",
"hdscore":6.5,
"hdscoreVersion":"1.04",
"lastInspectionDate":"2011-06-23",
"lastInspectionScoreDate":null,
"lastInspectionGradeDate":null
},
"preferredLevel":0,
"logoUrl":null,
"resultsTop":false,
"resultsBottom":false,
"featured":false,
"reportsViolations":true,
"displayName":"COFFEYVILLE LIVESTOCK MARKET"
},
{
"establishmentEntity":{
"id":368166,
"establishmentName":"TROPICAL SNO",
"address":"823 E 11th St",
"city":"Coffeyville",
"county":"Montgomery",
"stateOrProvince":"KS",
"postalCode":"67337-6603",
"telephone":"6203303296",
"establishmentType":null,
"lastInspectionScore":null,
"lastInspectionGrade":null,
"healthDepartment":"State of Kansas",
"lastInspectionCritical":false,
"lastInspectionPriority":false,
"lastInspectionPriorityFoundation":false,
"latitude":37.032937,
"longitude":-95.602057,
"added":1406367309000,
"geocoder":"com.hdscores.inspection.source.geocoding.MapQuestLicensedGeocoder",
"geocoderVersion":"1.12",
"hdscoreRankingPercent":0.449228445,
"hdscoreProvider":"com.hdscores.inspection.hdscore.ViolationsHDScoreProvider",
"hdscore":3.3172017928863275,
"hdscoreVersion":"1.04",
"lastInspectionDate":"2013-04-04",
"lastInspectionScoreDate":null,
"lastInspectionGradeDate":null
},
"preferredLevel":1,
"logoUrl":null,
"resultsTop":false,
"resultsBottom":false,
"featured":false,
"reportsViolations":true,
"displayName":"TROPICAL SNO"
},
{
"establishmentEntity":{
"id":494794,
"establishmentName":"SIR VON II",
"address":"806 E 11th St",
"city":"Coffeyville",
"county":"Montgomery",
"stateOrProvince":"KS",
"postalCode":"67337-6604",
"telephone":"6206886321",
"establishmentType":null,
"lastInspectionScore":null,
"lastInspectionGrade":null,
"healthDepartment":"State of Kansas",
"lastInspectionCritical":true,
"lastInspectionPriority":false,
"lastInspectionPriorityFoundation":false,
"latitude":37.032902,
"longitude":-95.604437,
"added":1410044780000,
"geocoder":"com.hdscores.inspection.source.geocoding.MapQuestLicensedGeocoder",
"geocoderVersion":"1.12",
"hdscoreRankingPercent":0.195856264,
"hdscoreProvider":"com.hdscores.inspection.hdscore.ViolationsHDScoreProvider",
"hdscore":5.5,
"hdscoreVersion":"1.04",
"lastInspectionDate":"2012-07-30",
"lastInspectionScoreDate":null,
"lastInspectionGradeDate":null
},
"preferredLevel":0,
"logoUrl":null,
"resultsTop":false,
"resultsBottom":false,
"featured":false,
"reportsViolations":true,
"displayName":"SIR VON II"
},
{
"establishmentEntity":{
"id":377960,
"establishmentName":"DAYS INN",
"address":"820 E 11th St",
"city":"Coffeyville",
"county":"Montgomery",
"stateOrProvince":"KS",
"postalCode":"67337-6604",
"telephone":"6202510002",
"establishmentType":null,
"lastInspectionScore":null,
"lastInspectionGrade":null,
"healthDepartment":"State of Kansas",
"lastInspectionCritical":false,
"lastInspectionPriority":false,
"lastInspectionPriorityFoundation":false,
"latitude":37.0329,
"longitude":-95.60475,
"added":1406692555000,
"geocoder":"com.hdscores.inspection.source.geocoding.MapQuestLicensedGeocoder",
"geocoderVersion":"1.12",
"hdscoreRankingPercent":0.6747599,
"hdscoreProvider":"com.hdscores.inspection.hdscore.ViolationsHDScoreProvider",
"hdscore":2.0,
"hdscoreVersion":"1.04",
"lastInspectionDate":"2013-12-24",
"lastInspectionScoreDate":null,
"lastInspectionGradeDate":null
},
"preferredLevel":1,
"logoUrl":null,
"resultsTop":false,
"resultsBottom":false,
"featured":false,
"reportsViolations":true,
"displayName":"DAYS INN"
},
{
"establishmentEntity":{
"id":119641,
"establishmentName":"SIRLOIN STOCKADE",
"address":"104 W 11th St",
"city":"Coffeyville",
"county":"Montgomery",
"stateOrProvince":"KS",
"postalCode":"67337-5902",
"telephone":"6202518156",
"establishmentType":null,
"lastInspectionScore":null,
"lastInspectionGrade":null,
"healthDepartment":"State of Kansas",
"lastInspectionCritical":false,
"lastInspectionPriority":false,
"lastInspectionPriorityFoundation":false,
"latitude":37.03298,
"longitude":-95.615787,
"added":1400599518000,
"geocoder":"com.hdscores.inspection.source.geocoding.MapQuestGeocoder",
"geocoderVersion":"1.00",
"hdscoreRankingPercent":0.147512679,
"hdscoreProvider":"com.hdscores.inspection.hdscore.ViolationsHDScoreProvider",
"hdscore":6.209693418399466,
"hdscoreVersion":"1.04",
"lastInspectionDate":"2014-03-07",
"lastInspectionScoreDate":null,
"lastInspectionGradeDate":null
},
"preferredLevel":0,
"logoUrl":null,
"resultsTop":false,
"resultsBottom":false,
"featured":false,
"reportsViolations":true,
"displayName":"SIRLOIN STOCKADE"
},
Here are some of the errors i am getting rerunning the same code multiple times:
java.lang.RuntimeException: com.fasterxml.jackson.databind.JsonMappingException: multiple points (through reference chain: com.hdscores.consumer.service.client.SearchResponse["items"]->java.util.ArrayList[0]->com.hdscores.consumer.service.client.Establishment["establishmentEntity"]->com.hdscores.consumer.service.client.EstablishmentEntity["lastInspectionDate"])
(Removed intermediate errors)
Caused by: java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1101)
at java.lang.Double.parseDouble(Double.java:540)
at java.text.DigitList.getDouble(DigitList.java:168)
at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2088)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
at java.text.DateFormat.parse(DateFormat.java:355)
at com.hdscores.consumer.service.client.JsonDateOnlyDeserializer.deserialize(JsonDateOnlyDeserializer.java:23)
at com.hdscores.consumer.service.client.JsonDateOnlyDeserializer.deserialize(JsonDateOnlyDeserializer.java:16)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:238)
... 51 more
Sometimes this is the error...
Caused by: java.lang.NumberFormatException: For input string: "5E51"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:441)
at java.lang.Long.parseLong(Long.java:483)
at java.text.DigitList.getLong(DigitList.java:194)
at java.text.DecimalFormat.parse(DecimalFormat.java:1316)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
at java.text.DateFormat.parse(DateFormat.java:355)
at com.hdscores.consumer.service.client.JsonDateOnlyDeserializer.deserialize(JsonDateOnlyDeserializer.java:23)
at com.hdscores.consumer.service.client.JsonDateOnlyDeserializer.deserialize(JsonDateOnlyDeserializer.java:16)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:238)
its Crazy, sometimes it works with no errors, sometimes it doesn't....
Any help, would be appreciated....
I figured it out! I found out that SimpleDateFormat is not thread safe, so i created a new instance for every thread and updated my JSON deserializer:
public class JsonDateOnlyDeserializer extends JsonDeserializer<Date> {
//private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
String dateString = jp.getText();
try {
return dateFormat.parse(dateString);
}
catch (ParseException e) {
throw new RuntimeException(e);
}
}
}