title: Spring JdbcTemplate fail to convert String to Enum (that extend specific interface), since default converter is called even if removed
body: <p>My basic Spring boot app has an endpoint that accepts one single String and use it as key to read a char(1) value from DB, with NamedParameterJdbcTemplate. Simplified version of my code:</p>
  <p><strong>Application.java</strong></p>
  <pre><code>@SpringBootApplication
  @EnableCaching
  @EnableScheduling
  @ComponentScan(basePackages = {&quot;my.package&quot;})
  public class Application {
      public static void main(String[] args) {
          SpringApplication.run(Application.class, args);
      }
  }
  </code></pre>
  <p><strong>Controller.java</strong></p>
  <pre><code>@RestController
  @RequestMapping(path = &quot;enpoint&quot;, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
  public MyController {
  
      @Autowired
      private NamedParameterJdbcTemplate namedJdbcTemplate;
  
      @PostMapping(&quot;do&quot;)
      public Response doStuff(@RequestBody Request request) {
          return this.namedJdbcTemplate.queryForObject(
              &quot;SELECT ONE_CHAR as value FROM TABLE WHERE KEY = :KEY&quot;,
              new MapSqlParameterSource(&quot;KEY&quot;, request.getKey()),
              new BeanPropertyRowMapper(Response.class)
          );
      }
  }
  </code></pre>
  <p><strong>Request.java</strong></p>
  <pre><code>public class Request {
      private String key;
      // ... constructor / getter / setters ... 
  }
  </code></pre>
  <p><strong>Response.java</strong></p>
  <p>Since in the db table the column ONE_CHAR can have only 3 possible values (A, B or C). Instead of having a Response object with just &quot;private String value;&quot;, I created an MyEnum that has only said chars.</p>
  <pre><code>public class Response {
      private MyEnum value;
      // ... constructor / getter / setters ... 
  }
  </code></pre>
  <p><strong>MyEnum.java</strong></p>
  <p>'A', 'B' and 'C' are not good names for my enum values, so I put that information inside an 'id' variable in my enum.</p>
  <pre><code>public enum MyEnum implements EnumById {
  
      GOOD_NAME(&quot;A&quot;), NICE_NAME(&quot;B&quot;), PERFECT_NAME(&quot;C&quot;);
  
      private final String id;
      // ... constructor / getter / setters ... 
  }
  </code></pre>
  <p><strong>EnumById.java</strong></p>
  <p>I created an interface 'EnumById' so I have a common way to handle all enums with the same issue (the values I want to represent as enums are something that can not or should not be used as variable name).</p>
  <pre><code>public interface EnumById {
      String getId();
  }
  </code></pre>
  <hr />
  <p>This code of course does not works. When spring tries to convert whatever value is read from DB, the default StringToEnumConverter does the conversion by enum <strong>name</strong> and not by calling my 'getId()' method (as expected). I have to create my own converter... But since:</p>
  <ul>
  <li>EnumById can be applied on multiple enums</li>
  <li>I need the Class reference to call clazz.getEnumConstants()</li>
  <li>I do not want to write a custom converter for each Enum that will extend EnumById</li>
  </ul>
  <p>... I need to create a custom ConverterFactory</p>
  <p><strong>StringToEnumByIdConverterFactory.java</strong></p>
  <pre><code>public class StringToEnumByIdConverterFactory implements ConverterFactory&lt;String, EnumById&gt; {
  
      private static class StringToEnumByIdConverter&lt;T extends EnumById&gt; implements Converter&lt;String, T&gt; {
  
          private final T[] values;
  
          public StringToEnumByIdConverter(final T[] values) {
                  this.values = values;
          }
  
          public T convert(final String source) {
              for (final T value : values) {
                  if (source.equals(value.getId())) {
                      return value;
                  }
              }
              return null;
          }
      }
  
      public &lt;T extends EnumById&gt; Converter&lt;String, T&gt; getConverter(final Class&lt;T&gt; targetType) {
          return new StringToEnumByIdConverter&lt;&gt;(targetType.getEnumConstants());
      }
  }
  </code></pre>
  <p><strong>WebConfig.java</strong></p>
  <p>As <a href="https://www.baeldung.com/spring-type-conversions" rel="nofollow noreferrer">https://www.baeldung.com/spring-type-conversions</a> tells us I must add my converter factory to the spring format register... so I wrote:</p>
  <pre><code>@Configuration
  public class WebConfig implements WebMvcConfigurer {
      @Override
      public void addFormatters(FormatterRegistry registry) {
          registry.addConverterFactory(new StringToEnumByIdConverterFactory());
      }
  }
  </code></pre>
  <p>Which.... is wrong... My converter will never be called since the default String-to-Enum converter has priority (since it was added earlier that my converter to the formatter registry).</p>
  <p>My solution is to remove the default converter (org.springframework.core.convert.support.StringToEnumConverterFactory), put mine and add again the default one, so my WebConfig class is now like this:</p>
  <p><strong>WebConfig.java</strong></p>
  <pre><code>@Configuration
  public class WebConfig implements WebMvcConfigurer {
      @Override
      public void addFormatters(FormatterRegistry registry) {
          registry.removeConvertible(String.class, Enum.class);
          registry.addConverterFactory(new StringToEnumByIdConverterFactory());
          registry.addConverterFactory(new StringToEnumConverterFactory());
      }
  }
  </code></pre>
  <p>Which is wrong again  because for whatever reason <a href="https://github.com/spring-projects/spring-framework/blob/master/spring-core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java" rel="nofollow noreferrer">StringToEnumConverterFactory is not public</a> (not even <a href="https://github.com/spring-projects/spring-framework/blob/master/spring-core/src/main/java/org/springframework/core/convert/support/ConversionUtils.java" rel="nofollow noreferrer">the ConversionUtils class used inside it</a>, why? StringToEnumConverterFactory is even declared final) ... So I had to copy that code in my project.</p>
  <hr />
  <p>Now that at least my application run, I debugged it and verified that the registry is properly updated when addFormatters is called.</p>
  <p>When I call the endpoint the default converter is still called. I get the same exception I would get if no converter related code was ever written/used/called:</p>
  <pre><code>org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'my.package.constants.Constants$MyEnum' for property 'value'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [my.package.constants.Constants$MyEnum] for value 'A'; nested exception is java.lang.IllegalArgumentException: No enum constant 'my.package.constants.Constants.MyEnum.A'
  </code></pre>
  <p>By looking at the stack trace I found that org.springframework.beans.TypeConverterDelegate.convertIfNecessary is the problem.</p>
  <p>I went to debug <a href="https://github.com/spring-projects/spring-framework/blob/610de3ae786812f332b71a7453a67afd39834a03/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java#L124" rel="nofollow noreferrer">and found out that the ConversionService used</a> <strong>does not have the same converters I saw when I was debugging my WebConfig class</strong> (the register in my class had ~155 converters, the ConversionService used here has only 52). I can clearly see the default StringToEnumConverterFactory:<a href="https://i.stack.imgur.com/uiD9M.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/uiD9M.png" alt="IDE Screenshot" /></a></p>
  <p><strong>Where/How I cant tell the correct ConversionService (there are more than one?) to use my converters?</strong></p>
  <hr />
  <h2><strong>UPDATE: FOUND THE PROBLEM, BUT STILL UNRESOLVED</strong></h2>
  <p>I use <code>new BeanPropertyRowMapper(Response.class)</code> which has its own ConversionService:
  <code>private ConversionService conversionService = DefaultConversionService.getSharedInstance();</code></p>
  <p>This bypass any Spring magic and directly gets a DefaultConversionService... Why the hell is the norm? To properly add my Enum conversion I would have to create my own class that extends BeanPropertyRowMapper... this seems extremely convoluted for now reason. Am I missing something?</p>
  <hr />
  <h2><strong>UPDATE: FOUND A &quot;FAKE&quot; SOLUTION (SINCE IS UGLY AS HELL)</strong></h2>
  <p>Wrote this before the query, and the conversion works now... I moved it somewhere it will be called only one time and still works.</p>
  <pre><code>// this is what BeanPropertyRowMapper use
  DefaultConversionService sharedInstance = (DefaultConversionService) DefaultConversionService.getSharedInstance();
  // remove default String to Enum conversion
  sharedInstance.removeConvertible(String.class, Enum.class); 
  // addd my converter factory
  sharedInstance.addConverterFactory(new StringToEnumByCodeConverterFactory());
  // add again all default converter back, since:
  //  - I removed only the String-&gt;Enum one
  //  - Converters are placed in a LinkedMap
  // No duplicates are inserted, I only get that the default Enum converter is added AFTER my converter
  DefaultConversionService.addDefaultConverters(sharedInstance);
  // Now my converter has priority on the default Strin-&gt;Enum one and BeanPropertyRowMapper can use it
  </code></pre>
  <p>This is dumb and ugly... is this really the only way to trick BeanPropertyRowMapper to use my converter without having to create a whole new class?</p>