==============================================================================
Demo 7 -- @HandleAuthorizationDenied and @AuthorizeReturnObject
==============================================================================
SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.

The exception type you actually catch
-------------------------------------
  thrown          -> org.springframework.security.authorization.AuthorizationDeniedException
  is AccessDeniedException          -> true
  is AuthorizationDeniedException   -> true
  carries an AuthorizationResult    -> ExpressionAuthorizationDecision granted=false

  Handlers written against AccessDeniedException still work -- but the
  concrete type carries the AuthorizationResult that explains the denial.

@HandleAuthorizationDenied: return something instead of throwing
----------------------------------------------------------------
  maskedBalance()  (alice, no ROLE_FINANCE)      ALLOWED  -> ***masked***
  maskedList()     (alice, no ROLE_FINANCE)      ALLOWED  -> []
  maskedBalance()  (cfo, has ROLE_FINANCE)       ALLOWED  -> 1,204,993.22

@AuthorizeReturnObject: the check moves onto the returned object
----------------------------------------------------------------
  returned instance -> com.ankurm.methodsec.Demo7DeniedHandling$Customer$$SpringCGLIB$$0
  customer.getName()   (no authority needed)     ALLOWED  -> alice
  customer.getEmail()  (needs 'pii:read')        DENIED   -> AuthorizationDeniedException: Access Denied
  customer.getEmail()  (has 'pii:read')          ALLOWED  -> alice@example.com

Same thing without the annotation, via AuthorizationProxyFactory
----------------------------------------------------------------
  raw.getEmail()      (unproxied object)         ALLOWED  -> alice@example.com
  wrapped.getEmail()  (proxied object)           DENIED   -> AuthorizationDeniedException: Access Denied
