@@ -503,6 +503,119 @@ open fun findMessagesForUser(@CurrentUser customUser: CustomUser?): ModelAndView
503503----
504504======
505505
506+ Once it is a meta-annotation, parameterization is also available to you.
507+
508+ For example, consider when you have a JWT as your principal and you want to say which claim to retrieve.
509+ As a meta-annotation, you might do:
510+
511+ [tabs]
512+ ======
513+ Java::
514+ +
515+ [source,java,role="primary"]
516+ ----
517+ @Target({ElementType.PARAMETER, ElementType.TYPE})
518+ @Retention(RetentionPolicy.RUNTIME)
519+ @Documented
520+ @AuthenticationPrincipal(expression = "claims['sub']")
521+ public @interface CurrentUser {}
522+ ----
523+
524+ Kotlin::
525+ +
526+ [source,kotlin,role="secondary"]
527+ ----
528+ @Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE)
529+ @Retention(AnnotationRetention.RUNTIME)
530+ @MustBeDocumented
531+ @AuthenticationPrincipal(expression = "claims['sub']")
532+ annotation class CurrentUser
533+ ----
534+ ======
535+
536+ which is already quite powerful.
537+ But, it is also limited to retrieving the `sub` claim.
538+
539+ To make this more flexible, first publish the `AnnotationTemplateExpressionDefaults` bean like so:
540+
541+ [tabs]
542+ ======
543+ Java::
544+ +
545+ [source,java,role="primary"]
546+ ----
547+ @Bean
548+ public AnnotationTemplateExpressionDefaults templateDefaults() {
549+ return new AnnotationTemplateExpressionDeafults();
550+ }
551+ ----
552+
553+ Kotlin::
554+ +
555+ [source,kotlin,role="secondary"]
556+ ----
557+ @Bean
558+ fun templateDefaults(): AnnotationTemplateExpressionDefaults {
559+ return AnnotationTemplateExpressionDeafults()
560+ }
561+ ----
562+ ======
563+
564+ and then you can supply a parameter to `@CurrentUser` like so:
565+
566+ [tabs]
567+ ======
568+ Java::
569+ +
570+ [source,java,role="primary"]
571+ ----
572+ @Target({ElementType.PARAMETER, ElementType.TYPE})
573+ @Retention(RetentionPolicy.RUNTIME)
574+ @Documented
575+ @AuthenticationPrincipal(expression = "claims['{claim}']")
576+ public @interface CurrentUser {
577+ String claim() default 'sub';
578+ }
579+ ----
580+
581+ Kotlin::
582+ +
583+ [source,kotlin,role="secondary"]
584+ ----
585+ @Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE)
586+ @Retention(AnnotationRetention.RUNTIME)
587+ @MustBeDocumented
588+ @AuthenticationPrincipal(expression = "claims['{claim}']")
589+ annotation class CurrentUser(val claim: String = "sub")
590+ ----
591+ ======
592+
593+ This will allow you more flexibility across your set of applications in the following way:
594+
595+ [tabs]
596+ ======
597+ Java::
598+ +
599+ [source,java,role="primary"]
600+ ----
601+ @RequestMapping("/messages/inbox")
602+ public ModelAndView findMessagesForUser(@CurrentUser("user_id") String userId) {
603+
604+ // .. find messages for this user and return them ...
605+ }
606+ ----
607+
608+ Kotlin::
609+ +
610+ [source,kotlin,role="secondary"]
611+ ----
612+ @RequestMapping("/messages/inbox")
613+ open fun findMessagesForUser(@CurrentUser("user_id") userId: String?): ModelAndView {
614+
615+ // .. find messages for this user and return them ...
616+ }
617+ ----
618+ ======
506619
507620[[mvc-async]]
508621== Spring MVC Async Integration
0 commit comments