Spring can't determine generic types when lambda expression is used instead of anonymous inner class

This post linked in the comments by Alan Stokes explains the issue well.

Basically, in the current JDK, the actual implementation of the lambda is compiled into the declaring class and the JVM produces a Lambda class whose method is the erasure of the method declared in the interface.

So

Converter<ZonedDateTime, String> dateTimeConverter =
    source -> source.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);

produces a synthetic method like

private static java.lang.String com.example.Test.lambda$0(java.time.ZonedDateTime source)  {
    return source.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}

which gets invoked by the generated lambda class instance. Internally, the functional interface method simply casts to the parameter type of the method above. The JLS states

If the erasure of the type of a method being overridden differs in its signature from the erasure of the function type of U, then before evaluating or executing the lambda body, the method's body checks that each argument value is an instance of a subclass or subinterface of the erasure of the corresponding parameter type in the function type of U; if not, a ClassCastException is thrown.

The VM itself produces an overriding method which is the raw equivalent of the method declared in the interface.

The only information you have about the types is in the static method above. Since this method is part of the declaring class, there's no way for Spring to retrieve it given an instance produced from the lambda expression.

However, you can do

interface ZonedDateTimeToStringConverter extends Converter<ZonedDateTime, String> {
}

and

Converter<ZonedDateTime, String> dateTimeConverter = (ZonedDateTimeToStringConverter)
    source -> source.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);

or

ZonedDateTimeToStringConverter dateTimeConverter =  source -> source.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);

This forces the lambda to declare a method like

public String convert(ZonedDateTime zdt);

and Spring will be able to find it and resolve the target and source types.