当前位置: 首页 > 知识库问答 >
问题:

JSON 反序列化 Joda Money 使用 Jackson ObjectMapper 导致异常

党俊健
2023-03-14

使用Dropwizard框架构建API,我使用Jackson ObjectMapper遇到了这个反序列化问题。我同时使用Joda Time和Joda Money。对于JodaTime,定义JodaModule足以解决反序列化问题。但对于JodaMoney来说,JodaModule不足以解决反序列化问题(如果我错了,请纠正我)。因此,我为JodaTime保留了JodaModule,创建了JodaMoney特定的反序列化程序。

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

共有2个答案

慕健
2023-03-14

您可以使用此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);
詹夕
2023-03-14

下面是为 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}
 类似资料:
  • 问题内容: 我需要执行RestRequest并获取一些JSON,因此我不确定我的方法是否真正异步,因为使用此方法时,UI仍然有些冻结。 特别针对以下代码行: 真的不同步吗?因为它似乎阻塞了UI。您能告诉我如何使此函数正确异步吗? 问题答案: 似乎作为参数传递给的委托正在UI线程上执行。如果是这种情况,只需使用即可在线程池上运行委托。 是田野吗?在我看来,它应该是局部变量。另外,在反序列化json之

  • 我有一个问题,将时间值反序列化为本地时间-授予,我对Nodatime很陌生。我想导入一个web服务结果,它以“hh:mm”格式列出了一个时间。除非使用“hh:mm:ss.fff”格式的时间,否则会出现异常。是否有一种方法可以指定一个不同的模式并让“hh:mm”工作? 请看此代码 引发异常:

  • 问题内容: 我是C ++的新手。使用序列化和反序列化类型数据的最简单方法是什么。我发现了一些使用示例,但它们对我来说是晦涩的。 问题答案: 请注意,将键解释为路径,例如,将对“ ab” =“ z”放置将创建{“ a”:{“ b”:“ z”}} JSON,而不是{“ ab”:“ z”} 。否则,使用是微不足道的。这是一个小例子。

  • 我正在开发一个应用程序,它使用Gson作为JSON反序列化器,需要从REST API反序列化多态JSON。在解释mi问题之前,请注意,我已经用Gson研究了多态反序列化,并在几个案例中成功地实现了它。这是我面临的一个具体问题。在问这个问题之前,我也读过这篇很棒的帖子和关于堆栈溢出的讨论。顺便说一下,我正在使用RuntimeTypeAdapterFactory来反序列化多态对象。 我遇到的问题是,G

  • 我使用的是带有Kafka活页夹和Avro的SpringCloudStream版本2.2.0。显然,一个不正确的记录被发布到Kafka主题中,导致所有消费者返回反序列化错误,并进行某种无限重试。 从技术上讲,应该有一种方法可以指定反序列化异常的策略。我可以找到一些不同的策略,如和,但它们适用于我在应用程序中不使用的Kafka流。如果有人能帮助我理解这里缺少什么,我将不胜感激。

  • 问题内容: 我在反序列化以下json数组时遇到麻烦(对不起,大小): 如果将其粘贴到json-viewer中,则会得到以下结构: 现在,包含具有坐标的数组的数组具有可变大小。所以我想在Java中,整个对象应该是一个数组,其中包含数组的集合,每个数组都包含一个。就像是 但是gson不接受这一点。我收到以下错误消息: 这似乎很奇怪,因为对我来说好像不像一个数组。但这可能使我感到困惑,或多或少地迷路了…