Skip to content

Make field parsing more flexible to avoid type casting errors #51

Closed

Description

@sergiobpa

Make field parsing more flexible to avoid type casting errors

Is your feature request related to a problem? Please describe.
The current parsing logic appears to be very strict about the expected data types, which leads to avoidable errors. For example, attempting to parse the value 20 into a double triggers an exception because the code cannot cast an Integer to double. Similarly, when reading 86000 into a field expected to be a String, an error occurs instead of automatically converting the value. This rigid behavior makes the system fragile when dealing with real-world data, where types may vary slightly but are still compatible.

Describe the solution you'd like
I would like the parsing mechanism to be more flexible in handling type conversions. If a value is numerically compatible (e.g., an integer where a double is expected), or can be safely converted to a string, the parser should perform the conversion automatically rather than failing. This would make the system more resilient and user-friendly, reducing the need for pre-processing input data.

Describe alternatives you've considered

Additional context

Activity

  1. Exlll commented on Nov 17, 2025

    @Exlll
    Owner

    Hi @sergiobpa, thanks for your request. :) Could you please show me example code of a number <-> number conversion that is causing issues for you (when using the latest version of ConfigLib, v4.6.4)?

    In general, I'm not a big fan of automatic conversions between other types but I see the usability aspect of them. I don't think such behavior should be the default setting though, meaning that if I add support for something like this, it will have to be enabled via ConfigurationProperties.

    What do you think?

  2. self-assigned this
    on Nov 17, 2025
  3. divios commented on Nov 17, 2025

    @divios

    Hi @Exlll,

    Thanks for the quick response! I understand your point about not enabling automatic conversions by default — I agree that it should be opt-in.

    Here’s a minimal example that currently fails using ConfigLib v4.6.4:

    @Polymorphic
        @PolymorphicTypes({
                @PolymorphicTypes.Type(type = ValueGeneratorConfig.FixedValueGeneratorConfig.class, alias = "FIXED"),
                @PolymorphicTypes.Type(type = ValueGeneratorConfig.RangeValueGeneratorConfig.class, alias = "RANGE"),
                @PolymorphicTypes.Type(type = ValueGeneratorConfig.GaussianValueGeneratorConfig.class, alias = "GAUSSIAN")
        })
        public interface ValueGeneratorConfig {
            record FixedValueGeneratorConfig(double value) implements ValueGeneratorConfig { }
            record RangeValueGeneratorConfig(double min, double max) implements ValueGeneratorConfig { }
            record GaussianValueGeneratorConfig(double mean, double std) implements ValueGeneratorConfig { }
        }
      items:
      "COARSE_DIRT":
        item:
          material: COARSE_DIRT
        buyPrice:
          type: FIXED
          value: 11.5 # works
        sellPrice:
          type: FIXED
          value: 1 # fails

    At work, I usually use Jackson for configuration/data binding, and it handles these types of conversions automatically (e.g., integer → double, number → string), which is what I was expecting here.

  4. Exlll commented on Nov 18, 2025

    @Exlll
    Owner

    Hi @divios, this test runs fine:

    @Polymorphic
    @PolymorphicTypes({
            @PolymorphicTypes.Type(type = ValueGeneratorConfig.FixedValueGeneratorConfig.class, alias = "FIXED"),
            @PolymorphicTypes.Type(type = ValueGeneratorConfig.RangeValueGeneratorConfig.class, alias = "RANGE"),
            @PolymorphicTypes.Type(type = ValueGeneratorConfig.GaussianValueGeneratorConfig.class, alias = "GAUSSIAN")
    })
    public interface ValueGeneratorConfig {
        record FixedValueGeneratorConfig(double value) implements ValueGeneratorConfig {}
    
        record RangeValueGeneratorConfig(double min, double max) implements ValueGeneratorConfig {}
    
        record GaussianValueGeneratorConfig(double mean, double std) implements ValueGeneratorConfig {}
    }
    
    record Cfg(List<ValueGeneratorConfig> items) {}
    
    @Test
    void loadYamlConfigurationWithItems() {
        writeStringToFile(
                """
                items:
                - type: FIXED
                  value: 1
                - type: RANGE
                  min: 2
                  max: 3
                - type: GAUSSIAN
                  mean: 4
                  std: 5
                """
        );
        System.out.println(YamlConfigurations.load(yamlFile, Cfg.class));
    }

    Can you please paste a reproducible example?

  5. divios commented on Nov 21, 2025

    @divios

    Just tested it again and it seems like it’s no longer an issue.
    I guess it must’ve been something on my side — maybe the file formatting or a small mistake I overlooked. 😅

    Sorry for the confusion!
    If I notice anything suspicious again, I’ll make sure to let you know.

  6. Exlll commented on Nov 22, 2025

    @Exlll
    Owner

    Ok, great, thanks for testing it 👍 Would you still like me to add an option for the other conversions?

    If yes, I currently have this API in mind but perhaps there is a better one 🤔

    public enum DeserializationCoercionType {
        /** Converts booleans to strings */
        BOOLEAN_TO_STRING,
        /** Converts numbers to strings */
        NUMBER_TO_STRING,
        /** Converts lists/sets/arrays/maps (recursively) to strings */
        COLLECTION_TO_STRING,
        /** Converts any objects that don't have the above types to strings */
        OBJECT_TO_STRING
    }
    
    ConfigurationProperties.newBuilder()
            // enable specific type coercions (varargs argument):
            .enableDeserializationTypeCoercion(BOOLEAN_TO_STRING, NUMBER_TO_STRING)
            // or, if you want to enable all (taking the risk that there might be added more in the future):
            .enableDeserializationTypeCoercion(DeserializationCoercionType.values())
            .build();
  7. divios commented on Nov 22, 2025

    @divios

    Yep, that looks good to me! I’m totally fine with that design

  8. Exlll commented on Dec 24, 2025

    @Exlll
    Owner

    With version 4.8.0 you can now configure this behavior via ConfigurationProperties:

    ConfigurationProperties.newBuilder()
            .setDeserializationCoercionTypes(DeserializationCoercionType.BOOLEAN_TO_STRING)
            .build();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions