使用Dropwizard框架构建API,我使用Jackson ObjectMapper遇到了这个反序列化问题。我正在使用Joda Time和Joda Money。对于Joda Time,定义JodaModule足以解决反序列化问题。但是对于Joda Money来说,JodaModule还不足以解决反序列化问题(如果我错了,请纠正我)。因此,为Joda Time保留JodaModule,我创建了Joda Money特定的反序列化器。
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);
}
}
对于产品型号,我为Money添加了反序列化器。如果我需要定义其他任何内容,请告诉我。
public class Product {
...
private Money price;
...
...
@JsonDeserialize(using=JodaMoneyDeserializer.class)
public void setPrice(Money price) {
this.price = price;
}
...
}
这将尝试仅解析“{”并将抛出错误。
非常感谢任何提示。
如果您需要其他信息,请与我们联系。
谢谢!
**更新** 这是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
}
我得到的例外。
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)
这是我注册解串器的方法。
SimpleModule module = new SimpleModule();
module.addDeserializer(Money.class, new MoneyDeserializer());
mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.registerModule(new JodaModule());
这是我反序列化产品对象的地方。
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);
}
答案 0 :(得分:5)
这是一个为Joda Money类型注册序列化器和反序列化器的示例。所有Money对象都转换为JSON字符串。
public class JacksonJodaMoney {
public static class Product {
public final Money price;
@JsonCreator
public Product(@JsonProperty("price") Money price) {
this.price = price;
}
@Override
public String toString() {
return "Product{" +
"price=" + price +
'}';
}
}
private static class MoneySerializer extends StdSerializer<Money> {
protected MoneySerializer() {
super(Money.class);
}
@Override
public void serialize(Money value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeString(value.toString());
}
}
private static class MoneyDeserializer extends StdDeserializer<Money> {
protected MoneyDeserializer() {
super(Money.class);
}
@Override
public Money deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
return Money.parse(jp.readValueAs(String.class));
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Product value = new Product(Money.of(CurrencyUnit.EUR, 40.55));
SimpleModule module = new SimpleModule();
module.addDeserializer(Money.class, new MoneyDeserializer());
module.addSerializer(Money.class, new MoneySerializer());
mapper.registerModule(module);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(value);
System.out.println(json);
System.out.println(mapper.readValue(json, Product.class));
}
}
输出:
{
"price" : "EUR 40.55"
}
Product{price=EUR 40.55}
答案 1 :(得分:0)
您可以使用此MoneyDeserializer,然后注册此反序列化程序
public class MoneyDeserializer extends JsonDeserializer<Money> {
@Override
public Money deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
String currencyCode = "GBP";
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = mapper.readTree(jp);
DoubleNode amountNode = (DoubleNode) root.findValue("amount");
String amount = null;
if (null != amountNode) {
amount = amountNode.asText();
}
JsonNode currencyUnitNode = root.get("currencyUnit");
JsonNode currencyCodeNode = currencyUnitNode.get("currencyCode");
currencyCode = currencyCodeNode.textValue();
if (StringUtils.isBlank(amount) || StringUtils.isBlank(currencyCode)) {
throw new IOException("unable to parse json");
}
return Money.parse(currencyCode + " " + amount);
}}
然后注册反序列化器:
ObjectMapper mapper = new ObjectMapper();
JodaModule module = new JodaModule();
module.addDeserializer(Money.class, new MoneyDeserializer());
mapper.registerModule(module);
YourClass yourclass= mapper.readValue(jsonString, YourClass.class);