@JsonProperty enum desirialization.

1,473 views
Skip to first unread message

yurivan

unread,
May 15, 2017, 8:26:50 PM5/15/17
to jackson-user
Jackson version 2.8.7

I have enum like this

public enum ShippingMethods {
@JsonProperty("0")
SHIPPING_METHODS_UNSPECIFIED(0),

@JsonProperty("10")
SHIPPING_METHODS_FED_EX_PRIORITY_OVERNIGHT(10),

@JsonProperty("11")
SHIPPING_METHODS_FED_EX_STANDARD_OVERNIGHT(11),

@JsonProperty("12")
SHIPPING_METHODS_FED_EX_FIRST_OVERNIGHT(12),

@JsonProperty("13")
SHIPPING_METHODS_FED_EX_2DAY(13),
...

When i am using @JsonProperty annotation with enum values its working properly on serialization, but when desirialization happens mapper is using ordinal() value.
I want Jackson to use @JsonProperty value for desirialization also. Is it supported by Jackson or do i need to use @JsonCreator - @JsonValue pair to implement this behavior?

Tatu Saloranta

unread,
May 16, 2017, 12:57:41 AM5/16/17
to jackson-user
@JsonProperty should also work for deserialization.
If this is not the case, I would like to see full reproduction.

-+ Tatu +-

>
> --
> You received this message because you are subscribed to the Google Groups
> "jackson-user" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to jackson-user...@googlegroups.com.
> To post to this group, send email to jackso...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

yurivan

unread,
May 16, 2017, 3:47:26 AM5/16/17
to jackson-user
Object mapper configuration:
private final objectMapper =                 
                new ObjectMapper()
                        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                        .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
                        .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                        .enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.registerModule(javaTimeModule);

Full enum:
public enum ShippingMethods {
    @JsonProperty("0")
    SHIPPING_METHODS_UNSPECIFIED(0),

    @JsonProperty("10")
    SHIPPING_METHODS_FED_EX_PRIORITY_OVERNIGHT(10),

    @JsonProperty("11")
    SHIPPING_METHODS_FED_EX_STANDARD_OVERNIGHT(11),

    @JsonProperty("12")
    SHIPPING_METHODS_FED_EX_FIRST_OVERNIGHT(12),

    @JsonProperty("13")
    SHIPPING_METHODS_FED_EX_2DAY(13),

    @JsonProperty("14")
    SHIPPING_METHODS_FED_EX_EXPRESS_SAVER(14),

    @JsonProperty("15")
    SHIPPING_METHODS_FED_EX_GROUND(15),

    @JsonProperty("16")
    SHIPPING_METHODS_FED_EX_HOME_DELIVERY(16),

    @JsonProperty("17")
    SHIPPING_METHODS_FED_EX_1DAY_FREIGHT(17),

    @JsonProperty("18")
    SHIPPING_METHODS_FED_EX_2DAY_FREIGHT(18),

    @JsonProperty("19")
    SHIPPING_METHODS_FED_EX_3DAY_FREIGHT(19),

    @JsonProperty("20")
    SHIPPING_METHODS_FED_EX_INTERNATIONAL_PRIORITY(20),

    @JsonProperty("21")
    SHIPPING_METHODS_FED_EX_INTERNATIONAL_ECONOMY(21),

    @JsonProperty("22")
    SHIPPING_METHODS_FED_EX_INTERNATIONAL_FIRST(22),

    @JsonProperty("23")
    SHIPPING_METHODS_FED_EX_INTERNATIONAL_PRIORITY_FREIGHT(23),

    @JsonProperty("24")
    SHIPPING_METHODS_FED_EX_INTERNATIONAL_ECONOMY_FREIGHT(24),

    @JsonProperty("25")
    SHIPPING_METHODS_FED_EX_EUROPE_FIRST_INTERNATIONAL_PRIORITY(25),

    @JsonProperty("26")
    SHIPPING_METHODS_FED_EX_SMART_POST(26),

    @JsonProperty("27")
    SHIPPING_METHODS_FED_EX_2DAY_AM(27),

    @JsonProperty("28")
    SHIPPING_METHODS_FED_EX_FIRST_FREIGHT(28),

    @JsonProperty("29")
    SHIPPING_METHODS_FED_EX_INTERNATIONAL_GROUND(29),

    @JsonProperty("30")
    SHIPPING_METHODS_FED_EX_FREIGHT_ECONOMY(30),

    @JsonProperty("31")
    SHIPPING_METHODS_FED_EX_FREIGHT_PRIORITY(31),

    @JsonProperty("35")
    SHIPPING_METHODS_UPS_FIRST_CLASS(35),

    @JsonProperty("36")
    SHIPPING_METHODS_UPS_PRIORITY_MAIL(36),

    @JsonProperty("37")
    SHIPPING_METHODS_UPS_EXPEDITED_MAIL_INNOVATIONS(37),

    @JsonProperty("38")
    SHIPPING_METHODS_UPS_PRIORITY_MAIL_INNOVATIONS(38),

    @JsonProperty("39")
    SHIPPING_METHODS_UPS_ECONOMY_MAIL_INNOVATIONS(39),

    @JsonProperty("40")
    SHIPPING_METHODS_UPS_NEXT_DAY_AIR(40),

    @JsonProperty("41")
    SHIPPING_METHODS_UPS_EXPRESS(41),

    @JsonProperty("42")
    SHIPPING_METHODS_UPS_2ND_DAY_AIR(42),

    @JsonProperty("43")
    SHIPPING_METHODS_UPS_GROUND(43),

    @JsonProperty("44")
    SHIPPING_METHODS_UPS_WORLDWIDE_EXPRESS(44),

    @JsonProperty("45")
    SHIPPING_METHODS_UPS_WORLDWIDE_EXPEDITED(45),

    @JsonProperty("46")
    SHIPPING_METHODS_UPS_EXPEDITED(46),

    @JsonProperty("47")
    SHIPPING_METHODS_UPS_STANDARD(47),

    @JsonProperty("48")
    SHIPPING_METHODS_UPS_3DAY_SELECT(48),

    @JsonProperty("49")
    SHIPPING_METHODS_UPS_NEXT_DAY_AIR_SAVER(49),

    @JsonProperty("50")
    SHIPPING_METHODS_UPS_SAVER(50),

    @JsonProperty("51")
    SHIPPING_METHODS_UPS_NEXT_DAY_AIR_EARLY_AM(51),

    @JsonProperty("52")
    SHIPPING_METHODS_UPS_EXPRESS_EARLY_AM(52),

    @JsonProperty("53")
    SHIPPING_METHODS_UPS_WORLDWIDE_EXPRESS_PLUS(53),

    @JsonProperty("54")
    SHIPPING_METHODS_UPS_EXPRESS_PLUS(54),

    @JsonProperty("55")
    SHIPPING_METHODS_UPS_2ND_DAY_AIR_AM(55),

    @JsonProperty("56")
    SHIPPING_METHODS_UPS_TODAY_STANDARD(56),

    @JsonProperty("57")
    SHIPPING_METHODS_UPS_TODAY_COURIER(57),

    @JsonProperty("58")
    SHIPPING_METHODS_UPS_TODAY_INTER_CITY(58),

    @JsonProperty("59")
    SHIPPING_METHODS_TODAY_EXPRESS(59),

    @JsonProperty("60")
    SHIPPING_METHODS_TODAY_EXPRESS_SAVER(60),

    @JsonProperty("61")
    SHIPPING_METHODS_UPS_WORLDWIDE_EXPRESS_FREIGHT(61),

    @JsonProperty("62")
    SHIPPING_METHODS_UPS_SURE_POST_LESS_THAN_1LB(62),

    @JsonProperty("63")
    SHIPPING_METHODS_UPS_SURE_POST_1LB_OR_GREATER(63),

    @JsonProperty("64")
    SHIPPING_METHODS_UPS_SURE_POST_BPM(64),

    @JsonProperty("65")
    SHIPPING_METHODS_UPS_SURE_POST_MEDIA(65),

    @JsonProperty("70")
    SHIPPING_METHODS_USPS_EXPRESS(70),

    @JsonProperty("71")
    SHIPPING_METHODS_USPS_FIRST_CLASS(71),

    @JsonProperty("72")
    SHIPPING_METHODS_USPS_PRIORITY(72),

    @JsonProperty("73")
    SHIPPING_METHODS_USPS_PARCEL_POST(73),

    @JsonProperty("75")
    SHIPPING_METHODS_USPS_MEDIA(75),

    @JsonProperty("76")
    SHIPPING_METHODS_USPS_LIBRARY(76),

    @JsonProperty("77")
    SHIPPING_METHODS_USPS_ONLINE(77),

    @JsonProperty("78")
    SHIPPING_METHODS_USPS_GLOBAL_EXPRESS(78),

    @JsonProperty("79")
    SHIPPING_METHODS_USPS_PARCEL_SELECT(79),

    @JsonProperty("80")
    SHIPPING_METHODS_USPS_CRITICAL_MAIL(80),

    @JsonProperty("81")
    SHIPPING_METHODS_USPS_STANDARD_MAIL(81),

    @JsonProperty("82")
    SHIPPING_METHODS_USPS_EXPRESS_MAIL_INTERNATIONAL(82),

    @JsonProperty("83")
    SHIPPING_METHODS_USPS_FIRST_CLASS_MAIL_INTERNATIONAL(83),

    @JsonProperty("84")
    SHIPPING_METHODS_USPS_PRIORITY_MAIL_INTERNATIONAL(84);

    private final int shippingMethodId;

    ShippingMethods(final int shippingMethodId) {
        this.shippingMethodId = shippingMethodId;
    }

    public int getShippingMethodId() {
        return shippingMethodId;
    }
}

As you can see it is sparse enum.

Object that uses this enum:
public class ShippingMethodInfo {
    @JsonProperty("typeId")
    private ShippingProviders typeId;

    @JsonProperty("value")
    private ShippingMethods value;

    @JsonProperty("coverage")
    private ShippingCoverage coverage;

    @JsonProperty("label")
    private String label;

    public ShippingProviders getTypeId() {
        return typeId;
    }

    public void setTypeId(ShippingProviders typeId) {
        this.typeId = typeId;
    }

    public ShippingMethods getValue() {
        return value;
    }

    public void setValue(ShippingMethods value) {
        this.value = value;
    }

    public ShippingCoverage getCoverage() {
        return coverage;
    }

    public void setCoverage(ShippingCoverage coverage) {
        this.coverage = coverage;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }
}


A significant part of the raw API response:
{
    "d": [
        {
            "typeId": 0,
            "value": 17,
            "coverage": 1,
            "label": "FedEx 1 Day Freight®"
        },
        {
            "typeId": 0,
            "value": 27,
            "coverage": 1,
            "label": "FedEx 2 Day AM®"
        },

Result of deserialization of first object:
typeId = "SHIPPING_PROVIDERS_FED_EX"
value
= "SHIPPING_METHODS_FED_EX_SMART_POST"
coverage
= "SHIPPING_COVERAGE_DOMESTIC"
label
= "FedEx 1 Day Freight®"

Result of deserialization of second object:
typeId = "SHIPPING_PROVIDERS_FED_EX"
value
= "SHIPPING_METHODS_UPS_ECONOMY_MAIL_INNOVATIONS"
coverage
= "SHIPPING_COVERAGE_DOMESTIC"
label
= "FedEx 2 Day AM®"

typeId, coverage and label were deserialized correctly, but value was not.

As you can see that value 17 is
    @JsonProperty("17")
    SHIPPING_METHODS_FED_EX_1DAY_FREIGHT(17)
and should have been deserialized as SHIPPING_METHODS_FED_EX_1DAY_FREIGHT

Instead it was deserialized as 
    @JsonProperty("26")
    SHIPPING_METHODS_FED_EX_SMART_POST(26)

SHIPPING_METHODS_FED_EX_SMART_POST has ordinal() value 17. That's why it was deserialized this way i think.
The same situation with second object desirialization.

With serialization of enum values there is no problems.

I've also implemnted approach with @JsonCreator - @JsonValue and it works correctly in both directions.

If you need more info just ask.

yurivan

unread,
May 16, 2017, 4:30:35 AM5/16/17
to jackson-user
And another detail. I previously had 2.7.4 version and problem was the same.

Tatu Saloranta

unread,
May 16, 2017, 11:40:51 AM5/16/17
to jackson-user
Ok. I think I have an idea of the problem (a minimal unit test would
have been even simpler way but this works too). Could you file an
issue for `jackson-databind` please?
I suspect this is related to auto-detection of JSON Strings that look
like numbers, accidentally using ordinal() like you suggest. But I
need to reproduce it, and it may take a while to find time to work on
this.

-+ Tatu +-

Tatu Saloranta

unread,
May 16, 2017, 7:26:57 PM5/16/17
to jackson-user
Looks like I spoke too soon: I can not reproduce this problem with a
simplified unit test, versions 2.8.8 or 2.9.0.pr3.

I created issue:

https://github.com/FasterXML/jackson-databind/issues/1626

but would now need a self-contained reproduction, ideally unit test.

What does not fail is simple enum like:

```java
enum NumberEnum {
@JsonProperty("2")
EN2,
@JsonProperty("0")
EN0,
@JsonProperty("1")
EN1
;
}
```

which serializes and deserializes as expected. And since sample code
included had enum as simple value it is not clear what the difference
would be (handling of Enum as Map key, or element of EnumSet is
different, however).

-+ Tatu +-
Reply all
Reply to author
Forward
0 new messages