Building API using Dropwizard framework and I came across this deserialization issue using Jackson ObjectMapper. I am using both Joda Time and Joda Money. For Joda Time, defining JodaModule was enough to resolve deserialization issue. But for Joda Money, JodaModule wasn't enough to resolve deserialization issue(Correct me if I am wrong). So, keeping JodaModule for Joda Time, I have created Joda Money specific deserializer.
public class JodaMoneyDeserializer extends JsonDeserializer<Money> {
@Override
public Money deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
String text = parser.getText();
return Money.parse(text);
}
}
For product model, I have added deserializer for Money. Let me know if I need to define anything else.
public class Product {
...
private Money price;
...
...
@JsonDeserialize(using=JodaMoneyDeserializer.class)
public void setPrice(Money price) {
this.price = price;
}
...
}
This will attempt to parse "{" only and will throw error.
Any tips are much appreciated.
If you need additional info, let me know.
Thanks!
** UPDATED ** Here's sample JSON.
{
"id": 15,
"productTypeId": 1,
"code": "XYZK",
"name": "PRODUCT - XYZK",
"status": true,
"visible": true,
"createdAt": 1400572157000,
"updatedAt": 1398995061000,
"description": "description of product",
"designator": "XYZK",
"number": "9.032",
"ingredients": "ingredient 1, ingredient 2, ingredient 3",
"size": null,
"weight": 0,
"googleProductCategory": "Health > Personal Care > Color",
"metaDescription": null,
"metaKeyword": null,
"metaTitle": null,
"price": {
"scale": 2,
"amount": 19.95,
"positive": true,
"positiveOrZero": true,
"negativeOrZero": false,
"amountMajor": 34,
"amountMajorLong": 34,
"amountMajorInt": 34,
"amountMinor": 3495,
"amountMinorLong": 3495,
"amountMinorInt": 3495,
"minorPart": 95,
"currencyUnit": {
"code": "USD",
"numericCode": 840,
"decimalPlaces": 2,
"numeric3Code": "840",
"countryCodes": [
"AS",
"US",
"EC",
"MP",
"TL",
"VI",
"VG",
"GU",
"SV",
"MH",
"PW",
"PR",
"FM",
"TC"
],
"pseudoCurrency": false,
"symbol": "$",
"currencyCode": "USD",
"defaultFractionDigits": 2
},
"zero": false,
"negative": false
},
"subPrice": {
"scale": 2,
"amount": 0,
"positive": false,
"positiveOrZero": true,
"negativeOrZero": true,
"amountMajor": 0,
"amountMajorLong": 0,
"amountMajorInt": 0,
"amountMinor": 0,
"amountMinorLong": 0,
"amountMinorInt": 0,
"minorPart": 0,
"currencyUnit": {
"code": "USD",
"numericCode": 840,
"decimalPlaces": 2,
"numeric3Code": "840",
"countryCodes": [
"AS",
"US",
"EC",
"MP",
"TL",
"VI",
"VG",
"GU",
"SV",
"MH",
"PW",
"PR",
"FM",
"TC"
],
"pseudoCurrency": false,
"symbol": "$",
"currencyCode": "USD",
"defaultFractionDigits": 2
},
"zero": true,
"negative": false
},
"priceGroupId": 1,
"ignoreFulfillment": false,
"upc": "2394823409820",
"productSKU": "XYZK",
"boxSKUInitial": "12345",
"boxSKURefill": "12345",
"urlKey": "capri-blonde",
"isAddon": false,
"extendedInfoJson": null
}
Exception that I am getting.
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
...
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:749)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:55)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:12)
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3025)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1637)
at com.fasterxml.jackson.core.JsonParser.readValueAs(JsonParser.java:1346)
at com.madisonreed.monocle.dao.mapper.deserializer.MoneyDeserializer.deserialize(MoneyDeserializer.java:26)
at com.madisonreed.monocle.dao.mapper.deserializer.MoneyDeserializer.deserialize(MoneyDeserializer.java:18)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:332)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1058)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:268)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:124)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3053)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2148)
at com.madisonreed.monocle.resources.ProductResourceTest.testGetProduct(ProductResourceTest.java:127)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at io.dropwizard.testing.junit.DropwizardAppRule$1.evaluate(DropwizardAppRule.java:55)
at org.junit.rules.RunRules.evaluate(RunRules.java:18)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
This is how I register deserializer.
SimpleModule module = new SimpleModule();
module.addDeserializer(Money.class, new MoneyDeserializer());
mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.registerModule(new JodaModule());
This is where I deserialize my product object.
public void testGetProduct() {
System.out.println("getProduct");
ClientResponse response = client.resource(String.format("http://localhost:%d/api/v1/products/15", RULE.getLocalPort())).get(ClientResponse.class);
Product product = null;
Boolean validJson = false;
if (response.getStatus() == 200) {
String productJSON = response.getEntity(String.class);
validJson = JacksonJsonUtility.isValidJSON(productJSON);
System.out.println(productJSON);
try {
product = mapper.readValue(productJSON, Product.class);
} catch (IOException ex) {
ex.printStackTrace();
Logger.getLogger(ProductResourceTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
assertTrue(validJson);
}