Repository: PebbleTemplates/pebble
Pull request #513 (2020-05-17 21:54:14)

#512: Add beans access for reactive app


Patch:
diff --git a/docs/src/orchid/resources/changelog/v3_1_4.md b/docs/src/orchid/resources/changelog/v3_1_4.md
index 4b6ba977..4249b17e 100644
--- a/docs/src/orchid/resources/changelog/v3_1_4.md
+++ b/docs/src/orchid/resources/changelog/v3_1_4.md
@@ -5,4 +5,5 @@ version: '3.1.4'
 - Slice filter: Use collection size when toIndex is greater than collection size  (#504)
 - Adjust spring boot doc (#509) 
 - Build with jdk14 (#508)
-- Set proxyBeanMethods to false (#507)
\ No newline at end of file
+- Set proxyBeanMethods to false (#507)
+- Add access to Spring Beans/request/session and response when using Pebble with WebFlux (#512)
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java
index 9cf61957..122cdb68 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java
@@ -17,10 +17,8 @@ class PebbleServletWebConfiguration extends AbstractPebbleConfiguration {
   @ConditionalOnMissingBean(name = "pebbleViewResolver")
   PebbleViewResolver pebbleViewResolver(PebbleProperties properties,
       PebbleEngine pebbleEngine) {
-    PebbleViewResolver pvr = new PebbleViewResolver();
+    PebbleViewResolver pvr = new PebbleViewResolver(pebbleEngine);
     properties.applyToMvcViewResolver(pvr);
-
-    pvr.setPebbleEngine(pebbleEngine);
     if (pebbleEngine.getLoader() instanceof ClasspathLoader) {
       // classpathloader doesn't like leading slashes in paths
       pvr.setPrefix(this.stripLeadingSlash(properties.getPrefix()));
diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java
index c0809e71..48c2c51d 100644
--- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java
+++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java
@@ -1,9 +1,17 @@
 package com.mitchellbosecke.pebble.spring.reactive;
 
+import static java.util.Optional.ofNullable;
+
 import com.mitchellbosecke.pebble.PebbleEngine;
 import com.mitchellbosecke.pebble.error.PebbleException;
+import com.mitchellbosecke.pebble.spring.context.Beans;
 import com.mitchellbosecke.pebble.template.PebbleTemplate;
-
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Locale;
+import java.util.Map;
 import org.springframework.context.i18n.LocaleContextHolder;
 import org.springframework.core.io.buffer.DataBuffer;
 import org.springframework.core.io.buffer.DataBufferUtils;
@@ -12,20 +20,16 @@ import org.springframework.lang.Nullable;
 import org.springframework.util.MimeType;
 import org.springframework.web.reactive.result.view.AbstractUrlBasedView;
 import org.springframework.web.server.ServerWebExchange;
-
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.util.Locale;
-import java.util.Map;
-
-import static java.util.Optional.ofNullable;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class PebbleReactiveView extends AbstractUrlBasedView {
 
+  private static final String BEANS_VARIABLE_NAME = "beans";
+  private static final String REQUEST_VARIABLE_NAME = "request";
+  private static final String RESPONSE_VARIABLE_NAME = "response";
+  private static final String SESSION_VARIABLE_NAME = "session";
+
   private PebbleEngine pebbleEngine;
   private String templateName;
 
@@ -47,6 +51,7 @@ public class PebbleReactiveView extends AbstractUrlBasedView {
     try {
       Charset charset = this.getCharset(contentType);
       Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset);
+      this.addVariablesToModel(renderAttributes, exchange);
       this.evaluateTemplate(renderAttributes, locale, writer);
     } catch (Exception ex) {
       DataBufferUtils.release(dataBuffer);
@@ -55,6 +60,13 @@ public class PebbleReactiveView extends AbstractUrlBasedView {
     return exchange.getResponse().writeWith(Flux.just(dataBuffer));
   }
 
+  private void addVariablesToModel(Map<String, Object> model, ServerWebExchange exchange) {
+    model.put(BEANS_VARIABLE_NAME, new Beans(this.getApplicationContext()));
+    model.put(REQUEST_VARIABLE_NAME, exchange.getRequest());
+    model.put(RESPONSE_VARIABLE_NAME, exchange.getResponse());
+    model.put(SESSION_VARIABLE_NAME, exchange.getSession());
+  }
+
   private Charset getCharset(@Nullable MediaType mediaType) {
     return ofNullable(mediaType)
         .map(MimeType::getCharset)
diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java
index 138e7ae7..3f4a4734 100644
--- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java
+++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java
@@ -1,7 +1,6 @@
 package com.mitchellbosecke.pebble.spring.reactive;
 
 import com.mitchellbosecke.pebble.PebbleEngine;
-
 import org.springframework.web.reactive.result.view.AbstractUrlBasedView;
 import org.springframework.web.reactive.result.view.UrlBasedViewResolver;
 
@@ -27,8 +26,4 @@ public class PebbleReactiveViewResolver extends UrlBasedViewResolver {
   protected Class<?> requiredViewClass() {
     return PebbleReactiveView.class;
   }
-
-  public PebbleEngine getPebbleEngine() {
-    return this.pebbleEngine;
-  }
 }
diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java
index 0b7a66f4..01271123 100644
--- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java
+++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java
@@ -8,18 +8,17 @@ package com.mitchellbosecke.pebble.spring.servlet;
 
 import com.mitchellbosecke.pebble.PebbleEngine;
 import com.mitchellbosecke.pebble.loader.Loader;
-
 import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Required;
 import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
 import org.springframework.web.servlet.view.AbstractUrlBasedView;
 
 public class PebbleViewResolver extends AbstractTemplateViewResolver implements InitializingBean {
 
   private String characterEncoding = "UTF-8";
-  private PebbleEngine pebbleEngine;
+  private final PebbleEngine pebbleEngine;
 
-  public PebbleViewResolver() {
+  public PebbleViewResolver(PebbleEngine pebbleEngine) {
+    this.pebbleEngine = pebbleEngine;
     this.setViewClass(this.requiredViewClass());
   }
 
@@ -34,11 +33,6 @@ public class PebbleViewResolver extends AbstractTemplateViewResolver implements
     this.characterEncoding = characterEncoding;
   }
 
-  @Required
-  public void setPebbleEngine(PebbleEngine pebbleEngine) {
-    this.pebbleEngine = pebbleEngine;
-  }
-
   @Override
   protected AbstractUrlBasedView buildView(String viewName) throws Exception {
     PebbleView view = (PebbleView) super.buildView(viewName);


Test patch:
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java
index 52eb0afa..795b843d 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java
@@ -26,4 +26,14 @@ public class Controllers {
     return "extensions";
   }
 
+  @RequestMapping("/beans.action")
+  public String beans() {
+    return "beans";
+  }
+
+  @RequestMapping("/response.action")
+  public String response() {
+    return "responseObject";
+  }
+
 }
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java
new file mode 100644
index 00000000..f4531508
--- /dev/null
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java
@@ -0,0 +1,9 @@
+package com.mitchellbosecke.pebble.boot;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class Foo {
+
+  public String value = "bar";
+}
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java
index 210b4624..60d6a8b2 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java
@@ -36,7 +36,7 @@ class ReactiveAppTest {
         .expectBody(String.class)
         .returnResult().getResponseBody();
 
-    assertThat(result).isEqualTo("ctx path:");
+    assertThat(result).isEqualTo("ctx path:/contextPath.action");
   }
 
   @Test
@@ -74,5 +74,27 @@ class ReactiveAppTest {
 
     assertThat(result).isEqualTo("Hola Boot! Tested!");
   }
+
+  @Test
+  void testBeansAccess() throws Exception {
+    String result = this.client.get().uri("/beans.action").exchange()
+        .expectStatus().isOk()
+        .expectHeader().contentTypeCompatibleWith(MediaType.TEXT_HTML)
+        .expectBody(String.class)
+        .returnResult().getResponseBody();
+
+    assertThat(result).isEqualTo("beans:bar");
+  }
+
+  @Test
+  void testResponseAccess() throws Exception {
+    String result = this.client.get().uri("/response.action").exchange()
+        .expectStatus().isOk()
+        .expectHeader().contentTypeCompatibleWith(MediaType.TEXT_HTML)
+        .expectBody(String.class)
+        .returnResult().getResponseBody();
+
+    assertThat(result).isEqualTo("response:200 OK");
+  }
 }
 
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java
index 431142b2..b4bdeb58 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java
@@ -70,4 +70,19 @@ class ServletAppTest {
         .andExpect(content().string("Hola Boot! Tested!"));
   }
 
+  @Test
+  void testBeansAccess() throws Exception {
+    this.mockMvc.perform(get("/beans.action"))
+        .andExpect(status().isOk())
+        .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+        .andExpect(content().string("beans:bar"));
+  }
+
+  @Test
+  void testResponseAccess() throws Exception {
+    this.mockMvc.perform(get("/response.action"))
+        .andExpect(status().isOk())
+        .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+        .andExpect(content().string("response:200"));
+  }
 }
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble
new file mode 100644
index 00000000..c0a95852
--- /dev/null
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble
@@ -0,0 +1,1 @@
+beans:{{beans.foo.value}}
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble
index 6b2af787..bf5fc36c 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble
@@ -1,1 +1,1 @@
-ctx path:{{request.contextPath}}
\ No newline at end of file
+ctx path:{{request.contextPath}}{{request.path}}
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble
new file mode 100644
index 00000000..1b11aa7d
--- /dev/null
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble
@@ -0,0 +1,1 @@
+response:{{response.status}}{{response.statusCode}}
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java b/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java
index 56d3a661..10122412 100644
--- a/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java
+++ b/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java
@@ -61,10 +61,9 @@ public class MVCConfig {
 
   @Bean
   public ViewResolver viewResolver(PebbleEngine pebbleEngine) {
-    PebbleViewResolver viewResolver = new PebbleViewResolver();
+    PebbleViewResolver viewResolver = new PebbleViewResolver(pebbleEngine);
     viewResolver.setPrefix("com/mitchellbosecke/pebble/spring/template/");
     viewResolver.setSuffix(".html");
-    viewResolver.setPebbleEngine(pebbleEngine);
     viewResolver.setContentType("text/html");
     return viewResolver;
   }