27 changed files with 28 additions and 423 deletions
@ -1,131 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2024 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.web.reactive.result.view.script; |
|
||||||
|
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Locale; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
import org.junit.jupiter.api.condition.DisabledForJreRange; |
|
||||||
|
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
|
||||||
import org.springframework.context.annotation.Bean; |
|
||||||
import org.springframework.context.annotation.Configuration; |
|
||||||
import org.springframework.context.support.ResourceBundleMessageSource; |
|
||||||
import org.springframework.http.MediaType; |
|
||||||
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest; |
|
||||||
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse; |
|
||||||
import org.springframework.web.testfixture.server.MockServerWebExchange; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
import static org.junit.jupiter.api.condition.JRE.JAVA_21; |
|
||||||
|
|
||||||
/** |
|
||||||
* Tests for Kotlin script templates running on Kotlin JSR-223 support. |
|
||||||
* |
|
||||||
* @author Sebastien Deleuze |
|
||||||
*/ |
|
||||||
@DisabledForJreRange(min = JAVA_21, disabledReason = "Kotlin doesn't support Java 21+ yet") |
|
||||||
class KotlinScriptTemplateTests { |
|
||||||
|
|
||||||
@Test |
|
||||||
void renderTemplateWithFrenchLocale() throws Exception { |
|
||||||
Map<String, Object> model = new HashMap<>(); |
|
||||||
model.put("foo", "Foo"); |
|
||||||
String url = "org/springframework/web/reactive/result/view/script/kotlin/template.kts"; |
|
||||||
MockServerHttpResponse response = render(url, model, Locale.FRENCH, ScriptTemplatingConfiguration.class); |
|
||||||
assertThat(response.getBodyAsString().block()).isEqualTo("<html><body>\n<p>Bonjour Foo</p>\n</body></html>"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
void renderTemplateWithEnglishLocale() throws Exception { |
|
||||||
Map<String, Object> model = new HashMap<>(); |
|
||||||
model.put("foo", "Foo"); |
|
||||||
String url = "org/springframework/web/reactive/result/view/script/kotlin/template.kts"; |
|
||||||
MockServerHttpResponse response = render(url, model, Locale.ENGLISH, ScriptTemplatingConfiguration.class); |
|
||||||
assertThat(response.getBodyAsString().block()).isEqualTo("<html><body>\n<p>Hello Foo</p>\n</body></html>"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
void renderTemplateWithoutRenderFunction() throws Exception { |
|
||||||
Map<String, Object> model = new HashMap<>(); |
|
||||||
model.put("header", "<html><body>"); |
|
||||||
model.put("hello", "Hello"); |
|
||||||
model.put("foo", "Foo"); |
|
||||||
model.put("footer", "</body></html>"); |
|
||||||
String url = "org/springframework/web/reactive/result/view/script/kotlin/eval.kts"; |
|
||||||
Class<?> configClass = ScriptTemplatingConfigurationWithoutRenderFunction.class; |
|
||||||
MockServerHttpResponse response = render(url, model, Locale.ENGLISH, configClass); |
|
||||||
assertThat(response.getBodyAsString().block()).isEqualTo("<html><body>\n<p>Hello Foo</p>\n</body></html>"); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private MockServerHttpResponse render(String viewUrl, Map<String, Object> model, |
|
||||||
Locale locale, Class<?> configuration) throws Exception { |
|
||||||
|
|
||||||
ScriptTemplateView view = createViewWithUrl(viewUrl, configuration); |
|
||||||
MockServerHttpRequest request = MockServerHttpRequest.get("/").acceptLanguageAsLocales(locale).build(); |
|
||||||
MockServerWebExchange exchange = MockServerWebExchange.from(request); |
|
||||||
view.renderInternal(model, MediaType.TEXT_HTML, exchange).block(); |
|
||||||
return exchange.getResponse(); |
|
||||||
} |
|
||||||
|
|
||||||
private ScriptTemplateView createViewWithUrl(String viewUrl, Class<?> configuration) throws Exception { |
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
|
||||||
ctx.register(configuration); |
|
||||||
ctx.refresh(); |
|
||||||
|
|
||||||
ScriptTemplateView view = new ScriptTemplateView(); |
|
||||||
view.setApplicationContext(ctx); |
|
||||||
view.setUrl(viewUrl); |
|
||||||
view.afterPropertiesSet(); |
|
||||||
return view; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Configuration |
|
||||||
static class ScriptTemplatingConfiguration { |
|
||||||
|
|
||||||
@Bean |
|
||||||
public ScriptTemplateConfigurer kotlinScriptConfigurer() { |
|
||||||
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer(); |
|
||||||
configurer.setEngineName("kotlin"); |
|
||||||
configurer.setScripts("org/springframework/web/reactive/result/view/script/kotlin/render.kts"); |
|
||||||
configurer.setRenderFunction("render"); |
|
||||||
return configurer; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
public ResourceBundleMessageSource messageSource() { |
|
||||||
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); |
|
||||||
messageSource.setBasename("org/springframework/web/reactive/result/view/script/messages"); |
|
||||||
return messageSource; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Configuration |
|
||||||
static class ScriptTemplatingConfigurationWithoutRenderFunction { |
|
||||||
|
|
||||||
@Bean |
|
||||||
public ScriptTemplateConfigurer kotlinScriptConfigurer() { |
|
||||||
return new ScriptTemplateConfigurer("kotlin"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,16 +0,0 @@ |
|||||||
@file:Suppress("UNCHECKED_CAST") |
|
||||||
|
|
||||||
package org.springframework.web.reactive.result.view.script |
|
||||||
|
|
||||||
import kotlin.script.templates.standard.ScriptTemplateWithBindings |
|
||||||
|
|
||||||
fun ScriptTemplateWithBindings.include(path: String) = |
|
||||||
(bindings["include"] as (String) -> String).invoke(path) |
|
||||||
|
|
||||||
|
|
||||||
fun ScriptTemplateWithBindings.i18n(code: String) = |
|
||||||
(bindings["i18n"] as (String) -> String).invoke(code) |
|
||||||
|
|
||||||
var ScriptTemplateWithBindings.foo: String |
|
||||||
get() = bindings["foo"] as String |
|
||||||
set(@Suppress("UNUSED_PARAMETER") value) { throw UnsupportedOperationException() } |
|
||||||
@ -0,0 +1,3 @@ |
|||||||
|
<p> |
||||||
|
Hello $foo |
||||||
|
</p> |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
<p> |
||||||
|
Hello $bar |
||||||
|
</p> |
||||||
@ -1,4 +0,0 @@ |
|||||||
// TODO Improve syntax when KT-15125 will be fixed |
|
||||||
"""${bindings["header"]} |
|
||||||
<p>${bindings["hello"]} ${bindings["foo"]}</p> |
|
||||||
${bindings["footer"]}""" |
|
||||||
@ -1 +0,0 @@ |
|||||||
</body></html> |
|
||||||
@ -1,6 +0,0 @@ |
|||||||
import org.springframework.web.reactive.result.view.script.* |
|
||||||
|
|
||||||
""" |
|
||||||
|<p> |
|
||||||
| ${i18n("hello")} $foo |
|
||||||
|</p>""".trimMargin() |
|
||||||
@ -1,6 +0,0 @@ |
|||||||
import org.springframework.web.reactive.result.view.script.* |
|
||||||
|
|
||||||
""" |
|
||||||
|<p> |
|
||||||
| ${i18n("hello")} $bar |
|
||||||
|</p>""".trimMargin() |
|
||||||
@ -1 +0,0 @@ |
|||||||
<html><body> |
|
||||||
@ -1,16 +0,0 @@ |
|||||||
import org.springframework.beans.factory.getBean |
|
||||||
import org.springframework.context.support.ResourceBundleMessageSource |
|
||||||
import org.springframework.web.reactive.result.view.script.RenderingContext |
|
||||||
import javax.script.ScriptEngineManager |
|
||||||
import javax.script.SimpleBindings |
|
||||||
|
|
||||||
fun render(template: String, model: Map<String, Any>, renderingContext: RenderingContext): String { |
|
||||||
val engine = ScriptEngineManager().getEngineByName("kotlin") |
|
||||||
val bindings = SimpleBindings() |
|
||||||
bindings.putAll(model) |
|
||||||
var messageSource = renderingContext.applicationContext.getBean<ResourceBundleMessageSource>() |
|
||||||
bindings.put("i18n", { code: String -> messageSource.getMessage(code, null, renderingContext.locale) }) |
|
||||||
bindings.put("include", { path: String -> renderingContext.templateLoader.apply("org/springframework/web/reactive/result/view/script/kotlin/$path.html") }) |
|
||||||
return engine.eval(template, bindings) as String |
|
||||||
} |
|
||||||
|
|
||||||
@ -1,5 +0,0 @@ |
|||||||
import org.springframework.web.reactive.result.view.script.* |
|
||||||
|
|
||||||
"""${include("header") } |
|
||||||
<p>${i18n("hello")} $foo</p> |
|
||||||
${include("footer")}""" |
|
||||||
@ -1,142 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2024 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.web.servlet.view.script; |
|
||||||
|
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Locale; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import jakarta.servlet.ServletContext; |
|
||||||
import org.junit.jupiter.api.BeforeEach; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
import org.junit.jupiter.api.condition.DisabledForJreRange; |
|
||||||
|
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
|
||||||
import org.springframework.context.annotation.Bean; |
|
||||||
import org.springframework.context.annotation.Configuration; |
|
||||||
import org.springframework.context.support.ResourceBundleMessageSource; |
|
||||||
import org.springframework.web.context.WebApplicationContext; |
|
||||||
import org.springframework.web.testfixture.servlet.MockHttpServletRequest; |
|
||||||
import org.springframework.web.testfixture.servlet.MockHttpServletResponse; |
|
||||||
import org.springframework.web.testfixture.servlet.MockServletContext; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
import static org.junit.jupiter.api.condition.JRE.JAVA_21; |
|
||||||
import static org.mockito.Mockito.mock; |
|
||||||
|
|
||||||
/** |
|
||||||
* Tests for Kotlin script templates running on Kotlin JSR-223 support. |
|
||||||
* |
|
||||||
* @author Sebastien Deleuze |
|
||||||
* @author Sam Brannen |
|
||||||
*/ |
|
||||||
@DisabledForJreRange(min = JAVA_21, disabledReason = "Kotlin doesn't support Java 21+ yet") |
|
||||||
class KotlinScriptTemplateTests { |
|
||||||
|
|
||||||
private WebApplicationContext webAppContext = mock(); |
|
||||||
|
|
||||||
private ServletContext servletContext = new MockServletContext(); |
|
||||||
|
|
||||||
|
|
||||||
@BeforeEach |
|
||||||
void setup() { |
|
||||||
this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.webAppContext); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
void renderTemplateWithFrenchLocale() throws Exception { |
|
||||||
Map<String, Object> model = new HashMap<>(); |
|
||||||
model.put("foo", "Foo"); |
|
||||||
String url = "org/springframework/web/servlet/view/script/kotlin/template.kts"; |
|
||||||
MockHttpServletResponse response = render(url, model, Locale.FRENCH, ScriptTemplatingConfiguration.class); |
|
||||||
assertThat(response.getContentAsString()).isEqualTo("<html><body>\n<p>Bonjour Foo</p>\n</body></html>"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
void renderTemplateWithEnglishLocale() throws Exception { |
|
||||||
Map<String, Object> model = new HashMap<>(); |
|
||||||
model.put("foo", "Foo"); |
|
||||||
String url = "org/springframework/web/servlet/view/script/kotlin/template.kts"; |
|
||||||
MockHttpServletResponse response = render(url, model, Locale.ENGLISH, ScriptTemplatingConfiguration.class); |
|
||||||
assertThat(response.getContentAsString()).isEqualTo("<html><body>\n<p>Hello Foo</p>\n</body></html>"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
void renderTemplateWithoutRenderFunction() throws Exception { |
|
||||||
Map<String, Object> model = new HashMap<>(); |
|
||||||
model.put("header", "<html><body>"); |
|
||||||
model.put("hello", "Hello"); |
|
||||||
model.put("foo", "Foo"); |
|
||||||
model.put("footer", "</body></html>"); |
|
||||||
MockHttpServletResponse response = render("org/springframework/web/servlet/view/script/kotlin/eval.kts", |
|
||||||
model, Locale.ENGLISH, ScriptTemplatingConfigurationWithoutRenderFunction.class); |
|
||||||
assertThat(response.getContentAsString()).isEqualTo("<html><body>\n<p>Hello Foo</p>\n</body></html>"); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private static MockHttpServletResponse render(String viewUrl, Map<String, Object> model, |
|
||||||
Locale locale, Class<?> configuration) throws Exception { |
|
||||||
|
|
||||||
ScriptTemplateView view = createViewWithUrl(viewUrl, configuration); |
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
|
||||||
request.addPreferredLocale(locale); |
|
||||||
view.renderMergedOutputModel(model, request, response); |
|
||||||
return response; |
|
||||||
} |
|
||||||
|
|
||||||
private static ScriptTemplateView createViewWithUrl(String viewUrl, Class<?> configuration) throws Exception { |
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(configuration); |
|
||||||
|
|
||||||
ScriptTemplateView view = new ScriptTemplateView(); |
|
||||||
view.setApplicationContext(ctx); |
|
||||||
view.setUrl(viewUrl); |
|
||||||
view.afterPropertiesSet(); |
|
||||||
return view; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Configuration |
|
||||||
static class ScriptTemplatingConfiguration { |
|
||||||
|
|
||||||
@Bean |
|
||||||
ScriptTemplateConfigurer kotlinScriptConfigurer() { |
|
||||||
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer(); |
|
||||||
configurer.setEngineName("kotlin"); |
|
||||||
configurer.setScripts("org/springframework/web/servlet/view/script/kotlin/render.kts"); |
|
||||||
configurer.setRenderFunction("render"); |
|
||||||
return configurer; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
ResourceBundleMessageSource messageSource() { |
|
||||||
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); |
|
||||||
messageSource.setBasename("org/springframework/web/servlet/view/script/messages"); |
|
||||||
return messageSource; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Configuration |
|
||||||
static class ScriptTemplatingConfigurationWithoutRenderFunction { |
|
||||||
|
|
||||||
@Bean |
|
||||||
ScriptTemplateConfigurer kotlinScriptConfigurer() { |
|
||||||
return new ScriptTemplateConfigurer("kotlin"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,16 +0,0 @@ |
|||||||
@file:Suppress("UNCHECKED_CAST") |
|
||||||
|
|
||||||
package org.springframework.web.servlet.view.script |
|
||||||
|
|
||||||
import kotlin.script.templates.standard.ScriptTemplateWithBindings |
|
||||||
|
|
||||||
fun ScriptTemplateWithBindings.include(path: String) = |
|
||||||
(bindings["include"] as (String) -> String).invoke(path) |
|
||||||
|
|
||||||
|
|
||||||
fun ScriptTemplateWithBindings.i18n(code: String) = |
|
||||||
(bindings["i18n"] as (String) -> String).invoke(code) |
|
||||||
|
|
||||||
var ScriptTemplateWithBindings.foo: String |
|
||||||
get() = bindings["foo"] as String |
|
||||||
set(@Suppress("UNUSED_PARAMETER") value) { throw UnsupportedOperationException()} |
|
||||||
@ -0,0 +1,3 @@ |
|||||||
|
<p> |
||||||
|
Hello $foo |
||||||
|
</p> |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
<p> |
||||||
|
Hello $bar |
||||||
|
</p> |
||||||
@ -1,4 +0,0 @@ |
|||||||
// TODO Improve syntax when KT-15125 will be fixed |
|
||||||
"""${bindings["header"]} |
|
||||||
<p>${bindings["hello"]} ${bindings["foo"]}</p> |
|
||||||
${bindings["footer"]}""" |
|
||||||
@ -1 +0,0 @@ |
|||||||
</body></html> |
|
||||||
@ -1,6 +0,0 @@ |
|||||||
import org.springframework.web.servlet.view.script.* |
|
||||||
|
|
||||||
""" |
|
||||||
|<p> |
|
||||||
| ${i18n("hello")} $foo |
|
||||||
|</p>""".trimMargin() |
|
||||||
@ -1,6 +0,0 @@ |
|||||||
import org.springframework.web.servlet.view.script.* |
|
||||||
|
|
||||||
""" |
|
||||||
|<p> |
|
||||||
| ${i18n("hello")} $bar |
|
||||||
|</p>""".trimMargin() |
|
||||||
@ -1 +0,0 @@ |
|||||||
<html><body> |
|
||||||
@ -1,15 +0,0 @@ |
|||||||
import javax.script.* |
|
||||||
import org.springframework.web.servlet.view.script.RenderingContext |
|
||||||
import org.springframework.context.support.ResourceBundleMessageSource |
|
||||||
import org.springframework.beans.factory.getBean |
|
||||||
|
|
||||||
fun render(template: String, model: Map<String, Any>, renderingContext: RenderingContext): String { |
|
||||||
val engine = ScriptEngineManager().getEngineByName("kotlin") |
|
||||||
val bindings = SimpleBindings() |
|
||||||
bindings.putAll(model) |
|
||||||
var messageSource = renderingContext.applicationContext.getBean<ResourceBundleMessageSource>() |
|
||||||
bindings.put("i18n", { code: String -> messageSource.getMessage(code, null, renderingContext.locale) }) |
|
||||||
bindings.put("include", { path: String -> renderingContext.templateLoader.apply("org/springframework/web/servlet/view/script/kotlin/$path.html") }) |
|
||||||
return engine.eval(template, bindings) as String |
|
||||||
} |
|
||||||
|
|
||||||
Loading…
Reference in new issue