Razvan Popian opened SPR-15607 and commented

The DefaultFormattingConversionService always converts an empty string to null. However, there may be some scenarios when an empty string needs to be converted to an actual object. For example we may need to default a numeric property to 0 if empty string is passed to the conversion service. The code I am referring to is in the org.springframework.format.support.FormattingConversionService class at line 193:

String text = (String) source;
if (!StringUtils.hasText(text)) {
    return null;
}

I think that maybe the target Formatter (Parser) should be given a chance to deal with the empty string.


Affects: 4.3.7

Comment From: wagnerluis1982

Is this issue still relevant?

Comment From: jMediaConverter

For me it still is.

Comment From: snicoll

Can you share a small sample that reproduces the issue before we look into this? The following code returns an empty String, not null:

new DefaultFormattingConversionService().convert("", String.class);

Comment From: jMediaConverter

I will once I get to a computer, but as far as I remember if you try to convert the empty string to an Integer for example the converter for this combination is not called. I may have used the wrong word - formatter in the title.

On Thu, Nov 2, 2023, 10:20 AM Stéphane Nicoll @.***> wrote:

Can you share a small sample that reproduces the issue before we look into this? The following code returns an empty String, not null:

new DefaultFormattingConversionService().convert("", String.class);

— Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-framework/issues/20166#issuecomment-1790265877, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFOBNMK7OUTKTH2QRBIPFCDYCNJUNAVCNFSM4JE2TBE2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCNZZGAZDMNJYG43Q . You are receiving this because you commented.Message ID: @.***>

Comment From: jMediaConverter

Notice the formatter parse method gets called for 10, but not for empty string in the code below. Empty string is converted to null, but I think the formatter should be given a chance to deal with empty string the way it sees fit. You may want to convert the empty string to 0 for example and there is no way to achieve this. Or say you are converting from string to some other object like a Cup. You may want to represent an empty Cup as something other than null.

    @Test
    public void test2() {
        DefaultFormattingConversionService cs = new DefaultFormattingConversionService();
        cs.addFormatter(new Formatter<Integer>() {

            @Override
            public String print(Integer object, Locale locale) {
                return String.valueOf(object);
            }

            @Override
            public Integer parse(String text, Locale locale) throws ParseException {
                System.out.println("Got called for " + text);
                return Integer.parseInt(text);
            }
        });

        System.out.println(cs.convert("10", Integer.class));

        System.out.println(cs.convert("", Integer.class));
    }

Comment From: sbrannen

Hi @jMediaConverter,

Thanks for providing the example code.

but not for empty string in the code below. Empty string is converted to null, but I think the formatter should be given a chance to deal with empty string the way it sees fit.

When you register a Formatter, internally two delegating converters are registered for the formatter. For the parsing side, a FormattingConversionService.ParserConverter is registered, and its convert(...) method always returns null for an empty source string.

So there's currently no way to achieve the desired behavior when registering a Formatter.

However, you can achieve the desired behavior by registering a custom Converter, as demonstrated in the following test.

@Test
void test() {
    DefaultFormattingConversionService cs = new DefaultFormattingConversionService();

    cs.addConverter(String.class, Integer.class,
            text -> (StringUtils.hasText(text) ? Integer.parseInt(text) : 0));

    assertThat(cs.convert("10", Integer.class)).isEqualTo(10);
    assertThat(cs.convert("", Integer.class)).isEqualTo(0);
    assertThat(cs.convert(null, Integer.class)).isNull();

    assertThat(cs.convert(10, String.class)).isEqualTo("10");
    assertThat(cs.convert(0, String.class)).isEqualTo("0");
    assertThat(cs.convert(null, String.class)).isNull();
}

Comment From: sbrannen

  • duplicate of #12969

Comment From: jMediaConverter

Thank you for the explanation, I wish I knew this 6 years ago :). To me this is still a bit of an inconsistency, Before the ConversionService was introduced I had used PropertyEditors for binding strings to objects and it was really easy with those to convert empty string to whatever as the empty string was passed to the PropertyEditor#setAsText method, unlike what is happening today with the Formatters. I also don't see any reason why the empty string would be passed to a Converter, but not to the Formatter. But if you think this is working as designed and there is a workaround, I suppose this can be closed.

Comment From: snicoll

Thanks for following up. I think Sam meant to close it already.