Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use @JsonCreator and @JsonValue on enums #168

Closed
altro3 opened this issue Mar 27, 2022 · 3 comments
Closed

Can't use @JsonCreator and @JsonValue on enums #168

altro3 opened this issue Mar 27, 2022 · 3 comments

Comments

@altro3
Copy link
Contributor

altro3 commented Mar 27, 2022

Expected Behavior

The @JsonCreator and @JsonValue annotations must be supported correctly

Actual Behaviour

Now serialization and deserialization of enums always goes by name, without the ability to customize enums in the form of codes or numeric identifiers.

See below for an example. You will get an exception when trying to deserialize:

17:29:09.735 ERROR [main] c.m.b.c.MyEntityConfig [MyEntityConfig.java:59] - Can't read config for variant VAR2
java.lang.IllegalArgumentException: No enum constant com.micronaut.bug.config.data.VariantEnum.2
	at java.base/java.lang.Enum.valueOf(Enum.java:273)
	at io.micronaut.serde.support.serdes.EnumSerde.deserializeNonNull(EnumSerde.java:42)
	at io.micronaut.serde.support.serdes.EnumSerde.deserializeNonNull(EnumSerde.java:36)
	at io.micronaut.serde.util.NullableDeserializer.deserialize(NullableDeserializer.java:38)
	at io.micronaut.serde.support.deserializers.SpecificObjectDeserializer.deserializeValue(SpecificObjectDeserializer.java:400)
	at io.micronaut.serde.support.deserializers.SpecificObjectDeserializer.deserialize(SpecificObjectDeserializer.java:174)
	at io.micronaut.serde.jackson.JacksonJsonMapper.readValue0(JacksonJsonMapper.java:131)
	at io.micronaut.serde.jackson.JacksonJsonMapper.readValue(JacksonJsonMapper.java:116)
	at io.micronaut.serde.jackson.JacksonJsonMapper.readValue(JacksonJsonMapper.java:160)
	at io.micronaut.serde.ObjectMapper.readValue(ObjectMapper.java:46)
	at com.micronaut.bug.config.MyEntityConfig.myConfigs(MyEntityConfig.java:55)
	at com.micronaut.bug.config.$MyEntityConfig$MyConfigs0$Definition.build(Unknown Source)

Steps To Reproduce

I have configuration in several json-files - var1.json, var2.json. My configuration structure:
ConfigData.java:

@Serdeable
public record ConfigData(
        VariantEnum variant,
        List<String> params,
        List<Double> params2,
        List<ConfigItem> items
) {

    @Serdeable
    public record ConfigItem(
            boolean prop1,
            double prop2
    ) {
    }
}

VariantEnum.java:

public enum VariantEnum {

    VAR1(1),
    VAR2(2),
    ;

    public static final Map<Byte, VariantEnum> BY_ID;

    static {

        var byId = new HashMap<Byte, VariantEnum>();
        for (var value : values()) {
            byId.put(value.id, value);
        }

        BY_ID = Map.copyOf(byId);
    }

    private final byte id;

    VariantEnum(int id) {
        this.id = (byte) id;
    }

    @JsonValue
    public byte getId() {
        return id;
    }

    @ReflectiveAccess
    @JsonCreator
    public static VariantEnum byId(byte id) {
        var value = BY_ID.get(id);
        if (value == null) {
            throw new IllegalArgumentException("Unknown id: " + id);
        }
        return value;
    }
}

var1.json:

{
  "variant": 1,
  "params": ["val1", "val2"],
  "params2": [122.23, 2222.56],
  "items": [
    {
      "prop1": true,
      "prop2": 3434.34
    },
    {
      "prop2": 3434.34
    }
  ]
}

Configuration load:

    @Bean
    @Named("myConfigs")
    public Map<VariantEnum, ConfigData> myConfigs(ObjectMapper objectMapper) {

        var myConfigs = new EnumMap<VariantEnum, ConfigData>(VariantEnum.class);

        for (var variant : VariantEnum.values()) {
            try {
                var fileUrl = ClassLoader.getSystemResourceAsStream("configs/" + variant.name().toLowerCase(Locale.ENGLISH) + ".json");
                if (fileUrl == null) {
                    continue;
                }
                var configData = objectMapper.readValue(fileUrl, ConfigData.class);
                log.info("Read {}", configData);
                myConfigs.put(variant, configData);
            } catch (Throwable t) {
                log.error("Can't read config for variant {}", variant, t);
            }
        }

        return myConfigs;
    }

Problem with methods

    @JsonValue
    public byte getId() {
        return id;
    }

    @ReflectiveAccess
    @JsonCreator
    public static VariantEnum byId(byte id) {
        var value = BY_ID.get(id);
        if (value == null) {
            throw new IllegalArgumentException("Unknown id: " + id);
        }
        return value;
    }

in my enum. I want to use specified code or identifier for enum, but now I can use only enum.name. With jackson this logic works fine

Environment Information

  • Windows 11
  • JDK 17

Example Application

https://github.com/altro3/micronaut3-bug

Version

3.4.0

@graemerocher graemerocher changed the title [BUG?] Can't use @JsonCreator and @JsonValue annotations with serde [BUG?] Can't use @JsonCreator and @JsonValue on enums Mar 28, 2022
@graemerocher graemerocher changed the title [BUG?] Can't use @JsonCreator and @JsonValue on enums Can't use @JsonCreator and @JsonValue on enums Mar 28, 2022
@graemerocher
Copy link
Contributor

Should be fixed in #300

@graemerocher
Copy link
Contributor

Sorry in #298

@graemerocher
Copy link
Contributor

Fixed by 78acd71

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants