@@ -84,7 +84,13 @@ public class ReflectedHandlerInvoker<M extends HandlerMethodMetaInfo> extends De
8484 private MethodAccess methodAccess ;
8585 private M handler ;
8686 private int handlerIndex ;
87- private ConcurrentMap <H .Format , Boolean > templateCache = new ConcurrentHashMap <>();
87+ private ConcurrentMap <H .Format , Boolean > templateAvailabilityCache = new ConcurrentHashMap <>();
88+ private $ .Visitor <H .Format > templateChangeListener = new $ .Visitor <H .Format >() {
89+ @ Override
90+ public void visit (H .Format format ) throws Osgl .Break {
91+ templateAvailabilityCache .remove (format );
92+ }
93+ };
8894 protected Method method ; //
8995 private ParamValueLoaderService paramLoaderService ;
9096 private JsonDTOClassManager jsonDTOClassManager ;
@@ -111,6 +117,7 @@ public class ReflectedHandlerInvoker<M extends HandlerMethodMetaInfo> extends De
111117 private Map <Integer , String > outputParams ;
112118 private boolean hasOutputVar ;
113119 private String templateContext ;
120+ private boolean noTemplateCache ;
114121 private MissingAuthenticationHandler missingAuthenticationHandler ;
115122 private MissingAuthenticationHandler csrfFailureHandler ;
116123
@@ -143,6 +150,7 @@ private ReflectedHandlerInvoker(M handlerMetaInfo, App app) {
143150
144151 sessionFree = method .isAnnotationPresent (SessionFree .class );
145152 express = method .isAnnotationPresent (NonBlock .class );
153+ noTemplateCache = method .isAnnotationPresent (Template .NoCache .class );
146154
147155 paramCount = handler .paramCount ();
148156 paramSpecs = jsonDTOClassManager .beanSpecs (controllerClass , method );
@@ -230,6 +238,11 @@ public Result handle(ActionContext context) throws Exception {
230238 return ActNotFound .get ();
231239 }
232240
241+ context .templateChangeListener (templateChangeListener );
242+ if (noTemplateCache ) {
243+ context .disableTemplateCaching ();
244+ }
245+
233246 String urlContext = this .controller .contextPath ();
234247 if (S .notBlank (urlContext )) {
235248 context .urlContext (urlContext );
@@ -242,17 +255,16 @@ public Result handle(ActionContext context) throws Exception {
242255 preventDoubleSubmission (context );
243256 processForceResponse (context );
244257 ensureJsonDTOGenerated (context );
245- Object controller = controllerInstance (context );
246258
259+ Object controller = controllerInstance (context );
247260
248261 /*
249262 * We will send back response immediately when param validation
250- * failed in the following cases:
251- * a) this is a data endpoint and accept JSON data
252- * b) there is no template associated with the endpoint
253- * TODO: fix me - if method use arbitrary templates, then this check will fail
263+ * failed in either of the following cases:
264+ * 1) this is an ajax call
265+ * 2) the accept content type is **NOT** html
254266 */
255- boolean failOnViolation = context .acceptJson () || checkTemplate ( context ) ;
267+ boolean failOnViolation = context .isAjax () || context . accept () != H . Format . HTML ;
256268
257269 Object [] params = params (controller , context );
258270
@@ -264,19 +276,9 @@ public Result handle(ActionContext context) throws Exception {
264276 try {
265277 return invoke (handler , context , controller , params );
266278 } finally {
267-
268279 if (hasOutputVar ) {
269280 fillOutputVariables (controller , params , context );
270281 }
271-
272- if (null == context .hasTemplate ()) {
273- // template path has been reset by app logic
274- templateCache .remove (context .accept ());
275- }
276- // ensure template is loaded as
277- // request handler might change the
278- // template path
279- checkTemplate (context );
280282 }
281283 }
282284
@@ -628,15 +630,18 @@ public boolean checkTemplate(ActionContext context) {
628630 //we don't check template on interceptors
629631 return false ;
630632 }
633+ H .Format fmt = context .accept ();
634+ if (noTemplateCache || Act .isDev ()) {
635+ return probeTemplate (fmt , context );
636+ }
631637 Boolean hasTemplate = context .hasTemplate ();
632638 if (null != hasTemplate ) {
633639 return hasTemplate ;
634640 }
635- H .Format fmt = context .accept ();
636- hasTemplate = templateCache .get (fmt );
637- if (null == hasTemplate || Act .isDev ()) {
641+ hasTemplate = templateAvailabilityCache .get (fmt );
642+ if (null == hasTemplate ) {
638643 hasTemplate = probeTemplate (fmt , context );
639- templateCache .putIfAbsent (fmt , hasTemplate );
644+ templateAvailabilityCache .putIfAbsent (fmt , hasTemplate );
640645 }
641646 context .setHasTemplate (hasTemplate );
642647 return hasTemplate ;
0 commit comments