001package io.jstach.opt.spring.webmvc; 002 003import java.util.Map; 004 005import org.springframework.stereotype.Controller; 006import org.springframework.util.ClassUtils; 007import org.springframework.web.method.HandlerMethod; 008import org.springframework.web.servlet.HandlerInterceptor; 009import org.springframework.web.servlet.ModelAndView; 010import org.springframework.web.servlet.View; 011import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 012import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 013 014import io.jstach.jstache.JStache; 015import io.jstach.jstachio.JStachio; 016import jakarta.servlet.http.HttpServletRequest; 017import jakarta.servlet.http.HttpServletResponse; 018 019/** 020 * A {@link HandlerInterceptor} to automatically resolve a {@link Controller} method 021 * return value that is a {@link JStache} model into a {@link JStachioModelView}. 022 * 023 * @author dsyer 024 */ 025@SuppressWarnings("exports") 026public class ViewResolvingHandlerInterceptor implements HandlerInterceptor, WebMvcConfigurer { 027 028 private final JStachio jstachio; 029 030 /** 031 * Spring will inject jstachio 032 * @param jstachio jstachio instance found by spring. 033 */ 034 public ViewResolvingHandlerInterceptor(JStachio jstachio) { 035 super(); 036 this.jstachio = jstachio; 037 } 038 039 /** 040 * {@inheritDoc} If the model contains an attribute that is a {@link JStache} model, 041 * in particular if it has been the result of a {@link Controller} method, then it 042 * will be automatically converted into a {@link JStachioModelView}. 043 */ 044 @Override 045 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 046 ModelAndView modelAndView) throws Exception { 047 048 if (modelAndView == null || !HandlerMethod.class.isInstance(handler)) { 049 return; 050 } 051 052 HandlerMethod method = (HandlerMethod) handler; 053 054 View view = view(method.getReturnType().getParameterType(), modelAndView.getModel()); 055 if (view != null) { 056 modelAndView.setView(view); 057 } 058 } 059 060 private View view(Class<?> modelClass, Map<String, Object> model) { 061 if (!jstachio.supportsType(modelClass)) { 062 return null; 063 } 064 Object value = attribute(modelClass, model); 065 if (value == null) { 066 return null; 067 } 068 return JStachioModelView.of(value, JStachioModelView.DEFAULT_MEDIA_TYPE, jstachio); 069 } 070 071 private Object attribute(Class<?> modelClass, Map<String, Object> model) { 072 String name = ClassUtils.getShortNameAsProperty(modelClass); 073 if (ClassUtils.isAssignableValue(modelClass, model.get(name))) { 074 return model.get(name); 075 } 076 for (String key : model.keySet()) { 077 if (ClassUtils.isAssignableValue(modelClass, model.get(key))) { 078 return model.get(key); 079 } 080 } 081 return null; 082 } 083 084 @Override 085 public void addInterceptors(InterceptorRegistry registry) { 086 registry.addInterceptor(this); 087 } 088 089}