0

I am having an issue parsing the th:field's value to a variable of class Duration. What I want to happen is to input some numbers and I want to be saved as minutes.

This is from my HTML file:

<input type="text" th:field="*{duration}">

On my object's side, I just initialized the variable like:

@Column(nullable = false)
    private Duration duration;

and I get an error webpage:

Validation failed for object='bookingType'. Error count: 1 org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'bookingType' on field 'duration': rejected value [15]; codes [typeMismatch.bookingType.duration,typeMismatch.duration,typeMismatch.java.time.Duration,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [bookingType.duration,duration]; arguments []; default message [duration]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.Duration' for property 'duration'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@javax.persistence.Column java.time.Duration] for value '15'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [15]]

I am using Bootstrap for the front-end, if it does matter at all.

I added the Thymeleaf's java8time extra, tried changing the input type to time and number, and I still get the same error.

İsmail Y.
  • 3,579
  • 5
  • 21
  • 29
  • 1
    *Failed to convert from type [java.lang.String] to type [@javax.persistence.Column java.time.Duration] for value '15';* means a `Duration` cannot be parsed from a plain numerical `String`, the unit is missing. There is a specific format that can be parsed, check the JavaDocs for it. You could possibly create fields for the supported units and concatenate them somehow. – deHaar Mar 25 '22 at 16:11
  • I am aware of that, but the question is how am I supposed to parse that particular value in Thymeleaf or in the controller. – Dimitar Dimitrov Mar 25 '22 at 16:15
  • By default, `java.time.Duration` parses only text in standard [ISO 8601 format](https://en.m.wikipedia.org/wiki/ISO_8601#Durations), with a `P` and a `T`. Your input `15` is not valid. – Basil Bourque Mar 25 '22 at 18:14
  • You can create a custom converter that will convert String -> Duration and vice versa. [Example](https://www.baeldung.com/jpa-attribute-converters) – Eugene Mar 26 '22 at 00:40

1 Answers1

0

I generally recommend creating DTO's between your models and web interfaces, so you can move more freely.

You can see in the error and comments, the problem is clear, string input 15 is not a Duration and cannot be converted.

If your Duration value is a specific type (minute, hour ..), you can add a custom converter like this:

public class StringToDurationConverter
        implements Converter<String, Duration> {

    @Override
    public Duration convert(String from) {
        return Duration.ofMinutes(
                Long.valueOf(from));
    }
}

We also need to tell Spring about this new converter by adding the StringToDurationConverter to the FormatterRegistry. This can be done by implementing the WebMvcConfigurer and overriding addFormatters() method:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToDurationConverter());
    }
}

The default Spring converter we used will apply the conversion on each matching source-destination pair.

If you want to see something conditional: https://stackoverflow.com/a/57539880/2039546

İsmail Y.
  • 3,579
  • 5
  • 21
  • 29