Skip to content

Unexpected boolean value on deserialization #372

Closed

Description

@Djaytan

Hello,

When I try to deserialize the following YAML file:

hostname: 'example.com'
port: 1234
isSslEnabled: true

My test fail because of this error message:

org.opentest4j.AssertionFailedError: 
Expecting value to be true but was false
Expected :true
Actual   :false

Whereas I can observe that in debug mode:

image

The unit test:

      // Given
      String yamlFileName = "whenDeserializing_withValidValues.yml";
      Path yamlFile =
          ResourcesHelper.getResourcePath(HostValidatingPropertiesTest.class, yamlFileName);

      // When
      Optional<HostValidatingProperties> optionalHostValidatingProperties =
          YamlDeserializer.deserialize(yamlFile, HostValidatingProperties.class);

      // Then
      assertThat(optionalHostValidatingProperties).isPresent();

      HostValidatingProperties hostValidatingProperties = optionalHostValidatingProperties.get();

      assertAll(() -> assertThat(hostValidatingProperties.getHostname()).isEqualTo("example.com"),
          () -> assertThat(hostValidatingProperties.getPort()).isEqualTo(1234),
          () -> assertThat(hostValidatingProperties.isSslEnabled()).isTrue());

And the YamlDeserializer class:

/**
 * YAML deserializer for testing purposes.
 */
public final class YamlDeserializer {

  private YamlDeserializer() {
    // Static class
  }

  /**
   * Deserializes the given YAML file into the specified type.
   *
   * @param yamlFile The YAML content to deserialize.
   * @param type The expected type of the YAML content.
   * @return The deserialized value if present and of valid type.
   * @param <T> The expected type to be obtained from deserialization.
   */
  @SneakyThrows
  public static <T> @NonNull Optional<T> deserialize(@NonNull Path yamlFile,
      @NonNull Class<T> type) {
    ConfigurationNode rootNode = buildYamlConfigurationNode(yamlFile);
    return Optional.ofNullable(rootNode.get(type));
  }

  @SneakyThrows
  private static @NonNull ConfigurationNode buildYamlConfigurationNode(@NonNull Path yamlFile) {
    return YamlConfigurationLoader.builder().path(yamlFile).build().load();
  }
}

Do you have any idea about why finally the deserialized boolean value has been converted to false? Is it a bug?

Thanks a lot for your time.

Activity

  1. changed the title [-]Boolean value deserialization (unit test context)[/-] [+]Boolean value YAML deserialization (unit test context)[/+] on Jan 20, 2023
  2. changed the title [-]Boolean value YAML deserialization (unit test context)[/-] [+]Unexpected boolean value on YAML deserialization[/+] on Jan 20, 2023
  3. Djaytan commented on Jan 20, 2023

    @Djaytan
    Author

    Same issue with Hocon config file with configurate-hocon module:

    {
      hostname: "example.com",
      port: 1234,
      isSslEnabled: true
    }
  4. changed the title [-]Unexpected boolean value on YAML deserialization[/-] [+]Unexpected boolean value on deserialization[/+] on Jan 20, 2023
  5. zml2008 commented on Jan 20, 2023

    @zml2008
    Member

    This sounds like it's some issue with HostValidatingProperties, do you have that class handy?

  6. Djaytan commented on Jan 20, 2023

    @Djaytan
    Author

    I suspect that the behavior come from HostValidatingProperties effectively:

    /**
     * Represents an annotated Java Beans version of an {@link HostProperties}.
     */
    @ConfigSerializable
    @Data
    @EqualsAndHashCode(callSuper = true)
    @ToString(callSuper = true)
    public final class HostValidatingProperties extends ValidatingConvertibleProperties<HostProperties> {
    
      /**
       * An hostname cannot exceed 255 characters as per the DNS standard specification.
       */
      @NotBlank
      @Size(max = 255)
      private String hostname;
    
      /**
       * A port cannot exceed 65535, which is the maximum value allowed by the Transport Control
       * Protocol (TCP) and User Datagram Protocol (UDP) standards.
       */
      @Max(65535)
      @PositiveOrZero
      private int port;
      private boolean isSslEnabled;
    
      @Override
      protected @NonNull HostProperties convertValidated() {
        return HostProperties.of(hostname, port, isSslEnabled);
      }
    }

    And the parent class ValidatingConvertibleProperties:

    /**
     * Represents a convertible data structure after validation which provides a way to convert it to
     * its final form.
     *
     * <p>This approach allows for decoupling the validation and the final data structure creation.
     *
     * @param <T> The type of the final data structure.
     */
    @EqualsAndHashCode
    @ToString
    public abstract class ValidatingConvertibleProperties<T> {
    
      private boolean isValidated = false;
    
      /**
       * Marks the properties as validated.
       */
      public void markAsValidated() {
        this.isValidated = true;
      }
    
      /**
       * Converts the properties to the "ready to use" data structure version.
       *
       * @return The "ready to use" data structure version.
       * @throws IllegalStateException if properties have not been validated before the conversion.
       */
      public T convert() {
        if (!isValidated) {
          throw new IllegalStateException("Properties must be validated before being converted");
        }
        return convertValidated();
      }
    
      /**
       * Converts the data from the current instance of the class inheriting this.
       *
       * <p><i>Note: This method must be called only after the data structure validation.
       *
       * @return The converted final data structure.
       */
      @NonNull
      protected abstract T convertValidated();
    }

    I suspect a conflict with the boolean value isValidated: it is supposed to remain false.

  7. Djaytan commented on Jan 20, 2023

    @Djaytan
    Author

    I have updated the corresponding test:

    assertAll(() -> assertThat(hostValidatingProperties.getHostname()).isEqualTo("example.com"),
              () -> assertThat(hostValidatingProperties.getPort()).isEqualTo(1234),
              () -> assertThat(hostValidatingProperties.isSslEnabled()).isTrue(),
              () -> assertThat(hostValidatingProperties.isValidated()).isFalse());

    And no problem about the isValidated one: the value is false as expected.

  8. locked and limited conversation to collaborators on Jan 21, 2023
  9. converted this issue into a discussion #373 on Jan 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions