title: Spring Security: How do I enable custom expression result type support?
body: <p>In my Spring Boot application I'm using the <code>@PreAuthorize</code> annotation in my controller methods to make them authorized. The expressions use simple <code>boolean</code>-returning methods, like this:</p>
  
  <pre class="lang-java prettyprint-override"><code>@ResponseStatus(OK)
  @PreAuthorize("@auth.authentication.mayReadMe(principal)")
  public UserDto readMe() {
      ...
  </code></pre>
  
  <p>The <code>mayReadMe(...)</code> method simply returns a boolean value, however it uses ternary logic under the hood and just converts a special enum to <code>boolean</code>:</p>
  
  <pre class="lang-java prettyprint-override"><code>boolean mayReadMe(@Nonnull UserDetails principal);
  </code></pre>
  
  <p>Now let's say I want to rework the authorization components and let the method return the enum:</p>
  
  <pre><code>@Nonnull
  foo.bar.FooBarEnum mayReadMe(@Nonnull final UserDetails principal);
  </code></pre>
  
  <p>However, I'm getting the following exception:</p>
  
  <pre><code>java.lang.IllegalArgumentException: Failed to evaluate expression '@primaryAuth.authentication.mayReadMe(principal)'
      at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:15)
      at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:44)
      at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:57)
      at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:25)
      at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:62)
      at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
      at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
  ...
  Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1001E:(pos 0): Type conversion problem, cannot convert from @javax.annotation.Nonnull foo.bar.FooBarEnum to java.lang.Boolean
      at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:78)
      at org.springframework.expression.common.ExpressionUtils.convertTypedValue(ExpressionUtils.java:53)
      at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:301)
      at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:11)
      ... 113 common frames omitted
  Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [@javax.annotation.Nonnull foo.bar.FooBarEnum] to type [java.lang.Boolean]
      at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313)
      at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195)
      at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:74)
      ... 116 common frames omitted
  </code></pre>
  
  <p>The exception message is really clear, but I can't inject my custom converter in any way. What I've tried so far:</p>
  
  <ul>
  <li>Registering custom converters via <code>WebMvcConfigurerAdapter.addFormatters(FormatterRegistry)</code> (both <code>Converter</code> and <code>GenericConverter</code>)</li>
  <li><code>Bean</code>-ining a custom <code>ExpressionBasedPreInvocationAdvice</code> (but it shouldn't work as far as I understand)</li>
  <li>... and a few other ways I can't recall after spending a few hours unfortunately.</li>
  </ul>
  
  <p>How do I inject a custom type converter so the <code>@PreAuthorization</code> expressions could be aware of the <code>foo.bar.FooBarEnum</code> as the returning type?</p>
  
  <hr>
  
  <h2>Edit 1</h2>
  
  <p>Why do I need a custom type to be returned, and not a boolean. I'm also writing a simple REST API self-describing subsystem, just a simple <code>GET /api</code> endpoint to return a list of endpoints and so on. This list consists of a certain objects describing API end point, HTTP method, incoming and outgoing DTOs, and the last thing I'm trying to add to the definition object is an endpoint authorization policy expression. Note that it's not a good idea to return the <code>@PreAuthorize</code> string expression (I mean a raw string), but it might be good to return a <em>custom</em> object describing the authorization rules. What I want the most is returning an object like:</p>
  
  <pre class="lang-java prettyprint-override"><code>public final class AuthorizationExpression
      implements BooleanSupplier {
      ...
      public IExpression toExpression() {
      ...
  }
  </code></pre>
  
  <p>where <code>BooleanSupplier</code> is expected to be used in the converter I'm trying to inject in order to satisfy the authorization needs -- just return <code>true</code> or <code>false</code>, and where <code>IExpression</code> is expected to be <code>toString</code>-ed in the <code>GET /api</code> handler using the Spring expression evaluator. Hence the <code>mayReadMe</code> signature might be as follows:</p>
  
  <pre class="lang-java prettyprint-override"><code>AuthorizationExpression mayReadMe(...)
  </code></pre>
  
  <p>so I could use <code>AuthorizationExpression</code> up to a certain use case. The <code>FooBarEnum</code> is just a simplification for the original question prior to the edit.</p>