private InitBinderBindingContext getBindingContext(Object controller) { List<SyncInvocableHandlerMethod> binderMethods = MethodIntrospector.selectMethods(controller.getClass(), BINDER_METHODS) .stream() .map(method -> new SyncInvocableHandlerMethod(controller, method)) .collect(Collectors.toList()); WebBindingInitializer bindingInitializer = new ConfigurableWebBindingInitializer(); return new InitBinderBindingContext(bindingInitializer, binderMethods); }
/** * Provide the context required to apply {@link #saveModel()} after the * controller method has been invoked. */ public void setSessionContext(SessionAttributesHandler attributesHandler, WebSession session) { this.saveModelOperation = () -> { if (getSessionStatus().isComplete()) { attributesHandler.cleanupAttributes(session); } else { attributesHandler.storeAttributes(session, getModel().asMap()); } }; }
@Override protected WebExchangeDataBinder initDataBinder(WebExchangeDataBinder dataBinder, ServerWebExchange exchange) { this.binderMethods.stream() .filter(binderMethod -> { InitBinder ann = binderMethod.getMethodAnnotation(InitBinder.class); Assert.state(ann != null, "No InitBinder annotation"); String[] names = ann.value(); return (ObjectUtils.isEmpty(names) || ObjectUtils.containsElement(names, dataBinder.getObjectName())); }) .forEach(method -> invokeBinderMethod(dataBinder, exchange, method)); return dataBinder; }
.flatMap(session -> { Map<String, Object> attributes = sessionAttributesHandler.retrieveAttributes(session); bindingContext.getModel().mergeAttributes(attributes); bindingContext.setSessionContext(sessionAttributesHandler, session); return invokeModelAttributeMethods(bindingContext, modelMethods, exchange) .doOnSuccess(aVoid -> findModelAttributes(handlerMethod, sessionAttributesHandler).forEach(name -> { if (!bindingContext.getModel().containsAttribute(name)) { Object value = session.getRequiredAttribute(name); bindingContext.getModel().addAttribute(name, value);
@Override public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) { HandlerMethod handlerMethod = (HandlerMethod) handler; Assert.state(this.methodResolver != null && this.modelInitializer != null, "Not initialized"); InitBinderBindingContext bindingContext = new InitBinderBindingContext( getWebBindingInitializer(), this.methodResolver.getInitBinderMethods(handlerMethod)); InvocableHandlerMethod invocableMethod = this.methodResolver.getRequestMappingMethod(handlerMethod); Function<Throwable, Mono<HandlerResult>> exceptionHandler = ex -> handleException(ex, handlerMethod, bindingContext, exchange); return this.modelInitializer .initModel(handlerMethod, bindingContext, exchange) .then(Mono.defer(() -> invocableMethod.invoke(exchange, bindingContext))) .doOnNext(result -> result.setExceptionHandler(exceptionHandler)) .doOnNext(result -> bindingContext.saveModel()) .onErrorResume(exceptionHandler); }
@Test public void clearModelAttributeFromSession() throws Exception { WebSession session = this.exchange.getSession().block(Duration.ZERO); assertNotNull(session); TestBean testBean = new TestBean("Session Bean"); session.getAttributes().put("bean", testBean); TestController controller = new TestController(); InitBinderBindingContext context = getBindingContext(controller); Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod(); HandlerMethod handlerMethod = new HandlerMethod(controller, method); this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000)); context.getSessionStatus().setComplete(); context.saveModel(); assertEquals(0, session.getAttributes().size()); }
@Test public void saveModelAttributeToSession() throws Exception { TestController controller = new TestController(); InitBinderBindingContext context = getBindingContext(controller); Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod(); HandlerMethod handlerMethod = new HandlerMethod(controller, method); this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000)); WebSession session = this.exchange.getSession().block(Duration.ZERO); assertNotNull(session); assertEquals(0, session.getAttributes().size()); context.saveModel(); assertEquals(1, session.getAttributes().size()); assertEquals("Bean", ((TestBean) session.getRequiredAttribute("bean")).getName()); }
@Nullable @Override public Object resolveArgumentValue( MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) { Assert.isInstanceOf(InitBinderBindingContext.class, bindingContext); return ((InitBinderBindingContext) bindingContext).getSessionStatus(); }
@SuppressWarnings("unchecked") @Test public void modelAttributeMethods() throws Exception { TestController controller = new TestController(); InitBinderBindingContext context = getBindingContext(controller); Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod(); HandlerMethod handlerMethod = new HandlerMethod(controller, method); this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000)); Map<String, Object> model = context.getModel().asMap(); assertEquals(5, model.size()); Object value = model.get("bean"); assertEquals("Bean", ((TestBean) value).getName()); value = model.get("monoBean"); assertEquals("Mono Bean", ((Mono<TestBean>) value).block(Duration.ofMillis(5000)).getName()); value = model.get("singleBean"); assertEquals("Single Bean", ((Single<TestBean>) value).toBlocking().value().getName()); value = model.get("voidMethodBean"); assertEquals("Void Method Bean", ((TestBean) value).getName()); value = model.get("voidMonoMethodBean"); assertEquals("Void Mono Method Bean", ((TestBean) value).getName()); }
@Override protected WebExchangeDataBinder initDataBinder(WebExchangeDataBinder binder, ServerWebExchange exchange) { this.binderMethods.stream() .filter(method -> isBinderMethodApplicable(method, binder)) .forEach(method -> invokeInitBinderMethod(binder, exchange, method)); return binder; }
@SuppressWarnings("unchecked") @Test public void initBinderMethod() throws Exception { Validator validator = mock(Validator.class); TestController controller = new TestController(); controller.setValidator(validator); InitBinderBindingContext context = getBindingContext(controller); Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod(); HandlerMethod handlerMethod = new HandlerMethod(controller, method); this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000)); WebExchangeDataBinder binder = context.createDataBinder(this.exchange, "name"); assertEquals(Collections.singletonList(validator), binder.getValidators()); }
@Test public void retrieveModelAttributeFromSession() throws Exception { WebSession session = this.exchange.getSession().block(Duration.ZERO); assertNotNull(session); TestBean testBean = new TestBean("Session Bean"); session.getAttributes().put("bean", testBean); TestController controller = new TestController(); InitBinderBindingContext context = getBindingContext(controller); Method method = ResolvableMethod.on(TestController.class).annotPresent(GetMapping.class).resolveMethod(); HandlerMethod handlerMethod = new HandlerMethod(controller, method); this.modelInitializer.initModel(handlerMethod, context, this.exchange).block(Duration.ofMillis(5000)); context.saveModel(); assertEquals(1, session.getAttributes().size()); assertEquals("Session Bean", ((TestBean) session.getRequiredAttribute("bean")).getName()); }
private BindingContext createBindingContext(String methodName, Class<?>... parameterTypes) throws Exception { Object handler = new InitBinderHandler(); Method method = handler.getClass().getMethod(methodName, parameterTypes); SyncInvocableHandlerMethod handlerMethod = new SyncInvocableHandlerMethod(handler, method); handlerMethod.setArgumentResolvers(new ArrayList<>(this.argumentResolvers)); handlerMethod.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer()); return new InitBinderBindingContext(this.bindingInitializer, Collections.singletonList(handlerMethod)); }
/** * Create and initialize a BindingContext for the current request. * @param handlerMethod the request handling method * @param exchange the current exchange * @return Mono with the BindingContext instance */ public Mono<BindingContext> createBindingContext(HandlerMethod handlerMethod, ServerWebExchange exchange) { List<SyncInvocableHandlerMethod> invocableMethods = getInitBinderMethods(handlerMethod) .map(method -> { Object bean = handlerMethod.getBean(); SyncInvocableHandlerMethod invocable = new SyncInvocableHandlerMethod(bean, method); invocable.setSyncArgumentResolvers(getInitBinderArgumentResolvers()); return invocable; }) .collect(Collectors.toList()); BindingContext bindingContext = new InitBinderBindingContext(getBindingInitializer(), invocableMethods); return initModel(handlerMethod, bindingContext, exchange).then(Mono.just(bindingContext)); }