diff --git a/grace-plugin-gsp/build.gradle b/grace-plugin-gsp/build.gradle index ca7bb201c3..379b587a94 100644 --- a/grace-plugin-gsp/build.gradle +++ b/grace-plugin-gsp/build.gradle @@ -1,12 +1,11 @@ dependencies { compileOnly libs.jakarta.servlet - api libs.commons.text api project(":grace-core") api project(":grace-plugin-api") api project(":grace-plugin-codecs") + implementation project(":grace-plugin-taglibs") api project(":grace-web-gsp") api project(":grace-web-mvc") - api project(":grace-web-taglib") api project(":grace-web-url-mappings") api libs.spring.boot.autoconfigure annotationProcessor libs.spring.boot.autoconfigureProcessor diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GroovyPagesAutoConfiguration.java b/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GroovyPagesAutoConfiguration.java index 75fefac85e..7c8020cf6f 100644 --- a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GroovyPagesAutoConfiguration.java +++ b/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GroovyPagesAutoConfiguration.java @@ -64,7 +64,6 @@ import org.grails.web.pages.GroovyPagesServlet; import org.grails.web.servlet.view.GroovyPageViewResolver; import org.grails.web.sitemesh.GroovyPageLayoutFinder; -import org.grails.web.taglib.StandaloneTagLibraryLookup; import org.grails.web.util.GrailsApplicationAttributes; /** @@ -190,12 +189,6 @@ public FilteringCodecsByContentTypeSettings filteringCodecsByContentTypeSettings return new FilteringCodecsByContentTypeSettings(grailsApplication.getIfAvailable()); } - @Bean - @ConditionalOnMissingBean - public DefaultGrailsTagDateHelper grailsTagDateHelper() { - return new DefaultGrailsTagDateHelper(); - } - @Bean @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) public ServletRegistrationBean groovyPagesServlet() { @@ -253,14 +246,6 @@ public GroovyPageViewResolver jspViewResolver(GroovyPagesProperties groovyPagesP return groovyPageViewResolver; } - @Bean - @ConditionalOnMissingBean - public StandaloneTagLibraryLookup gspTagLibraryLookup(ObjectProvider grailsApplication) { - StandaloneTagLibraryLookup tagLibraryLookup = new StandaloneTagLibraryLookup(); - grailsApplication.ifAvailable(tagLibraryLookup::setGrailsApplication); - return tagLibraryLookup; - } - @Bean({"groovyTemplateEngine", "groovyPagesTemplateEngine"}) @ConditionalOnMissingBean public GroovyPagesTemplateEngine groovyPagesTemplateEngine( diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GroovyPagesGrailsPlugin.groovy b/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GroovyPagesGrailsPlugin.groovy index 187d70bdb8..0c0b29de5a 100644 --- a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GroovyPagesGrailsPlugin.groovy +++ b/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GroovyPagesGrailsPlugin.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2004-2024 the original author or authors. + * Copyright 2004-2025 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. @@ -18,24 +18,10 @@ package org.grails.plugins.web import groovy.transform.CompileStatic import org.springframework.core.Ordered -import grails.core.gsp.GrailsTagLibClass import grails.plugins.Plugin import grails.util.GrailsUtil import grails.web.pages.GroovyPagesUriService -import org.grails.core.artefact.gsp.TagLibArtefactHandler import org.grails.gsp.GroovyPagesTemplateEngine -import org.grails.plugins.web.taglib.ApplicationTagLib -import org.grails.plugins.web.taglib.CountryTagLib -import org.grails.plugins.web.taglib.FormTagLib -import org.grails.plugins.web.taglib.FormatTagLib -import org.grails.plugins.web.taglib.JavascriptTagLib -import org.grails.plugins.web.taglib.PluginTagLib -import org.grails.plugins.web.taglib.RenderTagLib -import org.grails.plugins.web.taglib.SitemeshTagLib -import org.grails.plugins.web.taglib.UrlMappingTagLib -import org.grails.plugins.web.taglib.ValidationTagLib -import org.grails.taglib.TagLibraryLookup -import org.grails.taglib.TagLibraryMetaUtils import org.grails.web.pages.FilteringCodecsByContentTypeSettings /** @@ -54,49 +40,14 @@ class GroovyPagesGrailsPlugin extends Plugin implements Ordered { def version = GrailsUtil.getGrailsVersion() def dependsOn = [core: GrailsUtil.getGrailsVersion()] - def watchedResources = ["file:./plugins/*/grails-app/taglib/**/*TagLib.groovy", - "file:./grails-app/taglib/**/*TagLib.groovy", - "file:./plugins/*/app/taglib/**/*TagLib.groovy", - "file:./app/taglib/**/*TagLib.groovy"] - - def providedArtefacts = [ - ApplicationTagLib, - CountryTagLib, - FormatTagLib, - FormTagLib, - JavascriptTagLib, - RenderTagLib, - UrlMappingTagLib, - ValidationTagLib, - PluginTagLib, - SitemeshTagLib - ] - int order = 600 /** * Configures the various Spring beans required by GSP */ - Closure doWithSpring() { - { -> - def application = grailsApplication - - // Now go through tag libraries and configure them in Spring too. With AOP proxies and so on - def taglibs = application.getArtefacts(TagLibArtefactHandler.TYPE) - for (taglib in taglibs) { - final tagLibClass = taglib.clazz - - "${taglib.fullName}"(tagLibClass) { bean -> - bean.autowire = true - bean.lazyInit = true + Closure doWithSpring() { { -> - // Taglib scoping support could be easily added here. Scope could be based on a static field in the taglib class. - //bean.scope = 'request' - } - } - - } - } + } } /** * Clear the page cache with the ApplicationContext is loaded @@ -109,27 +60,8 @@ class GroovyPagesGrailsPlugin extends Plugin implements Ordered { @Override void onChange(Map event) { - def application = grailsApplication def ctx = applicationContext - if (application.isArtefactOfType(TagLibArtefactHandler.TYPE, event.source)) { - GrailsTagLibClass taglibClass = (GrailsTagLibClass) application.addArtefact(TagLibArtefactHandler.TYPE, event.source) - if (taglibClass) { - // replace tag library bean - def beanName = taglibClass.fullName - beans { - "$beanName"(taglibClass.clazz) { bean -> - bean.autowire = true - } - } - - // The tag library lookup class caches "tag -> taglib class" - // so we need to update it now. - def lookup = applicationContext.getBean('gspTagLibraryLookup', TagLibraryLookup) - lookup.registerTagLib(taglibClass) - TagLibraryMetaUtils.enhanceTagLibMetaClass(taglibClass, lookup) - } - } // clear uri cache after changes ctx.getBean('groovyPagesUriService', GroovyPagesUriService).clear() } diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/AbstractGrailsTagTests.groovy b/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/AbstractGrailsTagTests.groovy index fd04ae5673..51914518a2 100644 --- a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/AbstractGrailsTagTests.groovy +++ b/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/AbstractGrailsTagTests.groovy @@ -71,6 +71,7 @@ import org.grails.plugins.codecs.URLCodec import org.grails.plugins.core.CoreConfiguration import org.grails.plugins.databinding.DataBindingConfiguration import org.grails.plugins.support.PluginManagerAwareBeanPostProcessor +import org.grails.plugins.web.GrailsTagLibraryAutoConfiguration import org.grails.plugins.web.GroovyPagesAutoConfiguration import org.grails.plugins.web.controllers.ControllersPluginConfiguration import org.grails.plugins.web.mapping.UrlMappingsPluginConfiguration @@ -102,6 +103,7 @@ abstract class AbstractGrailsTagTests { CodecsPluginConfiguration, ControllersPluginConfiguration, DataBindingConfiguration, + GrailsTagLibraryAutoConfiguration, GroovyPagesAutoConfiguration, MimeTypesConfiguration, UrlMappingsPluginConfiguration] @@ -317,6 +319,7 @@ class MockController { dependantPluginClasses << gcl.loadClass("org.grails.plugins.web.mapping.UrlMappingsGrailsPlugin") dependantPluginClasses << gcl.loadClass("org.grails.plugins.web.controllers.ControllersGrailsPlugin") dependantPluginClasses << gcl.loadClass("org.grails.plugins.web.GroovyPagesGrailsPlugin") + dependantPluginClasses << gcl.loadClass("org.grails.plugins.web.TaglibsGrailsPlugin") List dependentPlugins = dependantPluginClasses.collect { new DefaultGrailsPlugin(it, new DescriptiveResource(it.toString()), grailsApplication) diff --git a/grace-plugin-rest/build.gradle b/grace-plugin-rest/build.gradle index 70f9886f4e..fac621a398 100644 --- a/grace-plugin-rest/build.gradle +++ b/grace-plugin-rest/build.gradle @@ -20,11 +20,7 @@ dependencies { transitive = false } compileOnly libs.grace.datastore.gorm.support - compileOnly(project(":grace-web-gsp")) { - exclude group:'org.graceframework', module:'grace-core' - exclude group:'org.graceframework', module:'grace-encoder' - exclude group:'org.graceframework', module:'grace-web-common' - } + compileOnly project(":grace-web-gsp") implementation libs.caffeine testImplementation libs.jakarta.servlet diff --git a/grace-plugin-taglibs/README.md b/grace-plugin-taglibs/README.md new file mode 100644 index 0000000000..00283c72f5 --- /dev/null +++ b/grace-plugin-taglibs/README.md @@ -0,0 +1 @@ +## grace-plugin-taglibs diff --git a/grace-plugin-taglibs/build.gradle b/grace-plugin-taglibs/build.gradle new file mode 100644 index 0000000000..e3dcc2b89f --- /dev/null +++ b/grace-plugin-taglibs/build.gradle @@ -0,0 +1,17 @@ +dependencies { + compileOnly libs.jakarta.servlet + api libs.commons.text + api project(":grace-core") + api project(":grace-plugin-api") + api project(":grace-plugin-codecs") + api project(":grace-web-gsp") + api project(":grace-web-mvc") + api project(":grace-web-taglib") + api project(":grace-web-url-mappings") + api libs.spring.boot.autoconfigure + annotationProcessor libs.spring.boot.autoconfigureProcessor + annotationProcessor libs.spring.boot.configurationProcessor + + testImplementation libs.spring.test + testImplementation project(":grace-test-support") +} diff --git a/grace-plugin-gsp/src/main/groovy/grails/compiler/traits/ControllerTagLibraryTraitInjector.groovy b/grace-plugin-taglibs/src/main/groovy/grails/compiler/traits/ControllerTagLibraryTraitInjector.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/grails/compiler/traits/ControllerTagLibraryTraitInjector.groovy rename to grace-plugin-taglibs/src/main/groovy/grails/compiler/traits/ControllerTagLibraryTraitInjector.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/DefaultGrailsTagDateHelper.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/DefaultGrailsTagDateHelper.groovy similarity index 98% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/DefaultGrailsTagDateHelper.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/DefaultGrailsTagDateHelper.groovy index 309da4c668..182baaf210 100644 --- a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/DefaultGrailsTagDateHelper.groovy +++ b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/DefaultGrailsTagDateHelper.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2004-2022 the original author or authors. + * Copyright 2004-2025 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. diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GrailsTagDateHelper.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/GrailsTagDateHelper.groovy similarity index 98% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GrailsTagDateHelper.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/GrailsTagDateHelper.groovy index 4a8d7ccf49..950832caa4 100644 --- a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/GrailsTagDateHelper.groovy +++ b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/GrailsTagDateHelper.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2004-2022 the original author or authors. + * Copyright 2004-2025 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. diff --git a/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/GrailsTagLibraryAutoConfiguration.java b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/GrailsTagLibraryAutoConfiguration.java new file mode 100644 index 0000000000..edf860ecf6 --- /dev/null +++ b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/GrailsTagLibraryAutoConfiguration.java @@ -0,0 +1,51 @@ +/* + * Copyright 2022-2025 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.grails.plugins.web; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; + +import grails.core.GrailsApplication; + +import org.grails.web.taglib.StandaloneTagLibraryLookup; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Grails Tag Library. + * + * @author Michael Yan + * @since 2024.0.0 + */ +@AutoConfiguration +public class GrailsTagLibraryAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public DefaultGrailsTagDateHelper grailsTagDateHelper() { + return new DefaultGrailsTagDateHelper(); + } + + @Bean + @ConditionalOnMissingBean + public StandaloneTagLibraryLookup gspTagLibraryLookup(ObjectProvider grailsApplication) { + StandaloneTagLibraryLookup tagLibraryLookup = new StandaloneTagLibraryLookup(); + grailsApplication.ifAvailable(tagLibraryLookup::setGrailsApplication); + return tagLibraryLookup; + } + +} diff --git a/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/TaglibsGrailsPlugin.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/TaglibsGrailsPlugin.groovy new file mode 100644 index 0000000000..7492596f64 --- /dev/null +++ b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/TaglibsGrailsPlugin.groovy @@ -0,0 +1,118 @@ +/* + * Copyright 2004-2025 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.grails.plugins.web + +import org.springframework.core.Ordered + +import grails.core.gsp.GrailsTagLibClass +import grails.plugins.Plugin +import grails.util.GrailsUtil + +import org.grails.core.artefact.gsp.TagLibArtefactHandler +import org.grails.plugins.web.taglib.ApplicationTagLib +import org.grails.plugins.web.taglib.CountryTagLib +import org.grails.plugins.web.taglib.FormTagLib +import org.grails.plugins.web.taglib.FormatTagLib +import org.grails.plugins.web.taglib.JavascriptTagLib +import org.grails.plugins.web.taglib.PluginTagLib +import org.grails.plugins.web.taglib.RenderTagLib +import org.grails.plugins.web.taglib.SitemeshTagLib +import org.grails.plugins.web.taglib.UrlMappingTagLib +import org.grails.plugins.web.taglib.ValidationTagLib +import org.grails.taglib.TagLibraryLookup +import org.grails.taglib.TagLibraryMetaUtils + +/** + * Grails plugin provides taglibs. + * + * @author Michael Yan + * @since 2024.0.0 + */ +class TaglibsGrailsPlugin extends Plugin implements Ordered { + + def grailsVersion = "2022.0.0 > *" + def version = GrailsUtil.getGrailsVersion() + def dependsOn = [core: GrailsUtil.getGrailsVersion()] + + def watchedResources = ["file:./plugins/*/grails-app/taglib/**/*TagLib.groovy", + "file:./grails-app/taglib/**/*TagLib.groovy", + "file:./plugins/*/app/taglib/**/*TagLib.groovy", + "file:./app/taglib/**/*TagLib.groovy"] + + def providedArtefacts = [ + ApplicationTagLib, + CountryTagLib, + FormatTagLib, + FormTagLib, + JavascriptTagLib, + RenderTagLib, + UrlMappingTagLib, + ValidationTagLib, + PluginTagLib, + SitemeshTagLib + ] + + int order = 650 + + /** + * Configures the various Spring beans required by GSP + */ + Closure doWithSpring() { + { -> + def application = grailsApplication + + // Now go through tag libraries and configure them in Spring too. With AOP proxies and so on + def taglibs = application.getArtefacts(TagLibArtefactHandler.TYPE) + for (taglib in taglibs) { + final tagLibClass = taglib.clazz + + "${taglib.fullName}"(tagLibClass) { bean -> + bean.autowire = true + bean.lazyInit = true + + // Taglib scoping support could be easily added here. Scope could be based on a static field in the taglib class. + //bean.scope = 'request' + } + } + } + } + + @Override + void onChange(Map event) { + def application = grailsApplication + def ctx = applicationContext + + if (application.isArtefactOfType(TagLibArtefactHandler.TYPE, event.source)) { + GrailsTagLibClass taglibClass = (GrailsTagLibClass) application.addArtefact(TagLibArtefactHandler.TYPE, event.source) + if (taglibClass) { + // replace tag library bean + def beanName = taglibClass.fullName + beans { + "$beanName"(taglibClass.clazz) { bean -> + bean.autowire = true + } + } + + // The tag library lookup class caches "tag -> taglib class" + // so we need to update it now. + def lookup = applicationContext.getBean('gspTagLibraryLookup', TagLibraryLookup) + lookup.registerTagLib(taglibClass) + TagLibraryMetaUtils.enhanceTagLibMetaClass(taglibClass, lookup) + } + } + } + +} diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/ApplicationTagInvocationContextCustomizer.java b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/ApplicationTagInvocationContextCustomizer.java similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/ApplicationTagInvocationContextCustomizer.java rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/ApplicationTagInvocationContextCustomizer.java diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/ApplicationTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/ApplicationTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/ApplicationTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/ApplicationTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/CountryTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/CountryTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/CountryTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/CountryTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/FormTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/FormTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/FormTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/FormTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/FormatTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/FormatTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/FormatTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/FormatTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/JavascriptTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/JavascriptTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/JavascriptTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/JavascriptTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/PluginTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/PluginTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/PluginTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/PluginTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/RenderTagInvocationContextCustomizer.java b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/RenderTagInvocationContextCustomizer.java similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/RenderTagInvocationContextCustomizer.java rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/RenderTagInvocationContextCustomizer.java diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/RenderTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/RenderTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/RenderTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/RenderTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/SitemeshTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/SitemeshTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/SitemeshTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/SitemeshTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/TemplateNamespacedTagDispatcher.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/TemplateNamespacedTagDispatcher.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/TemplateNamespacedTagDispatcher.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/TemplateNamespacedTagDispatcher.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/UrlMappingTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/UrlMappingTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/UrlMappingTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/UrlMappingTagLib.groovy diff --git a/grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/ValidationTagLib.groovy b/grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/ValidationTagLib.groovy similarity index 100% rename from grace-plugin-gsp/src/main/groovy/org/grails/plugins/web/taglib/ValidationTagLib.groovy rename to grace-plugin-taglibs/src/main/groovy/org/grails/plugins/web/taglib/ValidationTagLib.groovy diff --git a/grace-plugin-taglibs/src/main/resources/META-INF/grails-plugin.xml b/grace-plugin-taglibs/src/main/resources/META-INF/grails-plugin.xml new file mode 100644 index 0000000000..7b2431d3de --- /dev/null +++ b/grace-plugin-taglibs/src/main/resources/META-INF/grails-plugin.xml @@ -0,0 +1,3 @@ + + org.grails.plugins.web.TaglibsGrailsPlugin + \ No newline at end of file diff --git a/grace-plugin-gsp/src/main/resources/META-INF/grails.factories b/grace-plugin-taglibs/src/main/resources/META-INF/grails.factories similarity index 100% rename from grace-plugin-gsp/src/main/resources/META-INF/grails.factories rename to grace-plugin-taglibs/src/main/resources/META-INF/grails.factories diff --git a/grace-plugin-taglibs/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/grace-plugin-taglibs/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000..e394256a48 --- /dev/null +++ b/grace-plugin-taglibs/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.grails.plugins.web.GrailsTagLibraryAutoConfiguration \ No newline at end of file diff --git a/grace-plugin-gsp/src/test/groovy/grails/util/MockRequestDataValueProcessor.groovy b/grace-plugin-taglibs/src/test/groovy/grails/util/MockRequestDataValueProcessor.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/grails/util/MockRequestDataValueProcessor.groovy rename to grace-plugin-taglibs/src/test/groovy/grails/util/MockRequestDataValueProcessor.groovy diff --git a/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/AbstractGrailsTagTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/AbstractGrailsTagTests.groovy new file mode 100644 index 0000000000..51914518a2 --- /dev/null +++ b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/AbstractGrailsTagTests.groovy @@ -0,0 +1,595 @@ +package org.grails.web.taglib + +import javax.xml.parsers.DocumentBuilder +import javax.xml.parsers.DocumentBuilderFactory +import javax.xml.xpath.XPath +import javax.xml.xpath.XPathConstants +import javax.xml.xpath.XPathFactory + +import com.opensymphony.module.sitemesh.RequestConstants +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.springframework.beans.BeansException +import org.springframework.beans.factory.config.AutowireCapableBeanFactory +import org.springframework.beans.factory.config.BeanFactoryPostProcessor +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory +import org.springframework.beans.factory.support.RootBeanDefinition +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware +import org.springframework.context.MessageSource +import org.springframework.context.support.StaticMessageSource +import org.springframework.core.convert.support.DefaultConversionService +import org.springframework.core.io.DescriptiveResource +import org.springframework.core.io.Resource +import org.springframework.core.io.support.PathMatchingResourcePatternResolver +import org.springframework.mock.web.MockHttpServletRequest +import org.springframework.mock.web.MockHttpServletResponse +import org.springframework.mock.web.MockServletContext +import org.springframework.ui.context.Theme +import org.springframework.ui.context.ThemeSource +import org.springframework.ui.context.support.SimpleTheme +import org.springframework.web.context.WebApplicationContext +import org.springframework.web.context.request.RequestContextHolder +import org.springframework.web.servlet.DispatcherServlet +import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver +import org.springframework.web.servlet.support.JstlUtils +import org.springframework.web.servlet.theme.SessionThemeResolver +import org.w3c.dom.Document + +import grails.build.support.MetaClassRegistryCleaner +import grails.core.DefaultGrailsApplication +import grails.core.GrailsApplication +import grails.gorm.validation.PersistentEntityValidator +import grails.plugins.GrailsPluginManager +import grails.util.GrailsWebMockUtil +import grails.util.Holders +import grails.util.Metadata +import grails.web.pages.GroovyPagesUriService + +import org.grails.buffer.FastStringWriter +import org.grails.commons.CodecArtefactHandler +import org.grails.config.PropertySourcesConfig +import org.grails.core.artefact.ControllerArtefactHandler +import org.grails.core.artefact.gsp.TagLibArtefactHandler +import org.grails.core.support.GrailsApplicationAwareBeanPostProcessor +import org.grails.encoder.Encoder +import org.grails.encoder.impl.HTML4Codec +import org.grails.encoder.impl.HTMLJSCodec +import org.grails.encoder.impl.JavaScriptCodec +import org.grails.encoder.impl.RawCodec +import org.grails.gsp.GroovyPage +import org.grails.gsp.GroovyPageMetaInfo +import org.grails.gsp.GroovyPageTemplate +import org.grails.gsp.GroovyPagesTemplateEngine +import org.grails.gsp.compiler.SitemeshPreprocessor +import org.grails.plugins.DefaultGrailsPlugin +import org.grails.plugins.MockGrailsPluginManager +import org.grails.plugins.codecs.CodecsPluginConfiguration +import org.grails.plugins.codecs.HTMLCodec +import org.grails.plugins.codecs.URLCodec +import org.grails.plugins.core.CoreConfiguration +import org.grails.plugins.databinding.DataBindingConfiguration +import org.grails.plugins.support.PluginManagerAwareBeanPostProcessor +import org.grails.plugins.web.GrailsTagLibraryAutoConfiguration +import org.grails.plugins.web.GroovyPagesAutoConfiguration +import org.grails.plugins.web.controllers.ControllersPluginConfiguration +import org.grails.plugins.web.mapping.UrlMappingsPluginConfiguration +import org.grails.plugins.web.mime.MimeTypesConfiguration +import org.grails.spring.DefaultRuntimeSpringConfiguration +import org.grails.taglib.GroovyPageAttributes +import org.grails.taglib.TagOutput +import org.grails.taglib.encoder.OutputContextLookupHelper +import org.grails.taglib.encoder.OutputEncodingStack +import org.grails.taglib.encoder.WithCodecHelper +import org.grails.web.mapping.DefaultLinkGenerator +import org.grails.web.pages.DefaultGroovyPagesUriService +import org.grails.web.pages.GSPResponseWriter +import org.grails.web.servlet.mvc.GrailsWebRequest +import org.grails.web.sitemesh.GSPSitemeshPage +import org.grails.web.sitemesh.GrailsHTMLPageParser +import org.grails.web.sitemesh.GrailsLayoutView +import org.grails.web.util.GrailsApplicationAttributes + +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertFalse +import static org.junit.jupiter.api.Assertions.assertTrue +import static org.junit.jupiter.api.Assertions.fail + +abstract class AbstractGrailsTagTests { + + static final Class[] DEFAULT_AUTO_CONFIGURATIONS = [ + CoreConfiguration, + CodecsPluginConfiguration, + ControllersPluginConfiguration, + DataBindingConfiguration, + GrailsTagLibraryAutoConfiguration, + GroovyPagesAutoConfiguration, + MimeTypesConfiguration, + UrlMappingsPluginConfiguration] + + MockServletContext servletContext + GrailsWebRequest webRequest + MockHttpServletRequest request + MockHttpServletResponse response + AnnotationConfigServletWebApplicationContext ctx + def originalHandler + ApplicationContext appCtx + GrailsApplication ga + GrailsPluginManager mockManager + GroovyClassLoader gcl = new GroovyClassLoader() + MetaClassRegistryCleaner registryCleaner = MetaClassRegistryCleaner.createAndRegister() + + boolean enableProfile = false + + GrailsApplication grailsApplication + MessageSource messageSource + + DocumentBuilder domBuilder + XPath xpath + + def withConfig(String text, Closure callable) { + def config = new ConfigSlurper().parse(text) + try { + buildMockRequest(config) + callable() + } + finally { + RequestContextHolder.resetRequestAttributes() + Holders.config = null + } + } + + GrailsWebRequest buildMockRequest(ConfigObject co) throws Exception { + co.grails.resources.pattern = '/**' + def config = new PropertySourcesConfig().merge(co) + + ga.config = config + Holders.config = config + servletContext.setAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT, appCtx) + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appCtx) + webRequest = GrailsWebMockUtil.bindMockWebRequest(appCtx) + initRequestAndResponse() + return webRequest + } + + def profile(String name, Closure callable) { + if (!enableProfile) return callable.call() + + def now = System.currentTimeMillis() + for (i in 0..100) { + callable.call() + } + println "$name took ${System.currentTimeMillis() - now}ms" + } + + def withTag(String tagName, Writer out, String tagNamespace = "g", Closure callable) { + def result = null + runTest { + def webRequest = RequestContextHolder.currentRequestAttributes() + webRequest.out = out + + def mockController = grailsApplication.getControllerClass("MockController").newInstance() + + request.setAttribute(GrailsApplicationAttributes.CONTROLLER, mockController) + request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new AcceptHeaderLocaleResolver()) + + def tagLibrary = grailsApplication.getArtefactForFeature(TagLibArtefactHandler.TYPE, tagNamespace + ":" + tagName) + if (!tagLibrary) { + fail("No tag library found for tag $tagName") + } + def go = tagLibrary.newInstance() + appCtx.autowireCapableBeanFactory.autowireBeanProperties(go, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false) + if (go instanceof ApplicationContextAware) { + go.applicationContext = appCtx + } + def gspTagLibraryLookup = appCtx.gspTagLibraryLookup + + OutputEncodingStack stack = OutputEncodingStack.currentStack(OutputContextLookupHelper.lookupOutputContext(), true) + + stack.push(out) + try { + println "calling tag '${tagName}'" + def tag = go.getProperty(tagName)?.clone() + + def tagWrapper = { Object[] args -> + def attrs = args?.size() > 0 ? args[0] : [:] + if (!(attrs instanceof GroovyPageAttributes)) { + attrs = new GroovyPageAttributes(attrs) + } + ((GroovyPageAttributes) attrs).setGspTagSyntaxCall(true) + def body = args?.size() > 1 ? args[1] : null + if (body && !(body instanceof Closure)) { + body = new TagOutput.ConstantClosure(body) + } + + def tagresult = null + + boolean encodeAsPushedToStack = false + try { + boolean returnsObject = gspTagLibraryLookup.doesTagReturnObject(tagNamespace, tagName) + Object codecInfo = gspTagLibraryLookup.getEncodeAsForTag(tagNamespace, tagName) + if (attrs.containsKey(GroovyPage.ENCODE_AS_ATTRIBUTE_NAME)) { + codecInfo = attrs.get(GroovyPage.ENCODE_AS_ATTRIBUTE_NAME) + } + else if (GroovyPage.DEFAULT_NAMESPACE.equals(tagNamespace) && GroovyPage.APPLY_CODEC_TAG_NAME.equals(tagName)) { + codecInfo = attrs + } + if (codecInfo != null) { + stack.push(WithCodecHelper.createOutputStackAttributesBuilder(codecInfo, webRequest.getAttributes().getGrailsApplication()).build()) + encodeAsPushedToStack = true + } + switch (tag.getParameterTypes().length) { + case 1: + tagresult = tag.call(attrs) + outputTagResult(stack.taglibWriter, returnsObject, tagresult) + if (body) { + body.call() + } + break + case 2: + tagresult = tag.call(attrs, (body != null) ? body : TagOutput.EMPTY_BODY_CLOSURE) + outputTagResult(stack.taglibWriter, returnsObject, tagresult) + break + } + + Encoder taglibEncoder = stack.taglibEncoder + if (returnsObject && tagresult && !(tagresult instanceof Writer) && taglibEncoder) { + tagresult = taglibEncoder.encode(tagresult) + } + tagresult + } + finally { + if (encodeAsPushedToStack) stack.pop() + } + } + result = callable.call(tagWrapper) + } + finally { + stack.pop() + } + } + return result + } + + private void outputTagResult(Writer taglibWriter, boolean returnsObject, Object tagresult) { + if (returnsObject && tagresult != null && !(tagresult instanceof Writer)) { + taglibWriter.print(tagresult) + } + } + + protected void onSetUp() { + } + + @BeforeEach + protected void setUp() throws Exception { + GroovySystem.metaClassRegistry.addMetaClassRegistryChangeEventListener(registryCleaner) + GroovyPageMetaInfo.DEFAULT_PLUGIN_PATH = null + domBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder() + xpath = XPathFactory.newInstance().newXPath() + originalHandler = GroovySystem.metaClassRegistry.metaClassCreationHandle + + GroovySystem.metaClassRegistry.metaClassCreationHandle = new ExpandoMetaClassCreationHandle() + onSetUp() + Metadata.getInstance(new ByteArrayInputStream(""" +info.app.name: ${getClass().name} +""".bytes)) + grailsApplication = new DefaultGrailsApplication(gcl.loadedClasses, gcl) + ga = grailsApplication + ga.config.grails.resources.pattern = '/**' + ga.config.grails.gsp.tldScanPattern = 'classpath*:/META-INF/spring*.tld,classpath*:/META-INF/fmt.tld,classpath*:/META-INF/c.tld,classpath*:/META-INF/core.tld,classpath*:/META-INF/c-1_0-rt.tld' + grailsApplication.initialise() + mockManager = new MockGrailsPluginManager(grailsApplication) + mockManager.registerProvidedArtefacts(grailsApplication) + + def mockControllerClass = gcl.parseClass(''' +@grails.artefact.Artefact("Controller") +class MockController { + def index = {} +} +''') + grailsApplication.addArtefact(ControllerArtefactHandler.TYPE, mockControllerClass) + grailsApplication.addArtefact(CodecArtefactHandler.TYPE, HTMLCodec) + grailsApplication.addArtefact(CodecArtefactHandler.TYPE, HTML4Codec) + grailsApplication.addArtefact(CodecArtefactHandler.TYPE, JavaScriptCodec) + grailsApplication.addArtefact(CodecArtefactHandler.TYPE, HTMLJSCodec) + grailsApplication.addArtefact(CodecArtefactHandler.TYPE, URLCodec) + grailsApplication.addArtefact(CodecArtefactHandler.TYPE, RawCodec) + + ctx = new AnnotationConfigServletWebApplicationContext() + ctx.setServletContext(new MockServletContext()) + ctx.registerBeanDefinition("messageSource", new RootBeanDefinition(StaticMessageSource)) + + ctx.beanFactory.registerSingleton(GrailsApplication.APPLICATION_ID, grailsApplication) + ctx.beanFactory.registerSingleton("pluginManager", mockManager) + ctx.beanFactory.registerSingleton("grailsLinkGenerator", new DefaultLinkGenerator("http://localhost:8080")) + ctx.beanFactory.registerSingleton("manager", mockManager) + ctx.beanFactory.registerSingleton("conversionService", new DefaultConversionService()) + ctx.beanFactory.registerSingleton(GroovyPagesUriService.BEAN_ID, new DefaultGroovyPagesUriService()) + ctx.register(DEFAULT_AUTO_CONFIGURATIONS) + ctx.servletContext.setAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT, ctx) + + onInitMockBeans() + + List dependantPluginClasses = [] + dependantPluginClasses << gcl.loadClass("org.grails.plugins.core.CoreGrailsPlugin") + dependantPluginClasses << gcl.loadClass("org.grails.plugins.codecs.CodecsGrailsPlugin") + dependantPluginClasses << gcl.loadClass("org.grails.plugins.domain.DomainClassGrailsPlugin") + dependantPluginClasses << gcl.loadClass("org.grails.plugins.i18n.I18nGrailsPlugin") + dependantPluginClasses << gcl.loadClass("org.grails.plugins.web.mapping.UrlMappingsGrailsPlugin") + dependantPluginClasses << gcl.loadClass("org.grails.plugins.web.controllers.ControllersGrailsPlugin") + dependantPluginClasses << gcl.loadClass("org.grails.plugins.web.GroovyPagesGrailsPlugin") + dependantPluginClasses << gcl.loadClass("org.grails.plugins.web.TaglibsGrailsPlugin") + + List dependentPlugins = dependantPluginClasses.collect { + new DefaultGrailsPlugin(it, new DescriptiveResource(it.toString()), grailsApplication) + } + + dependentPlugins.each { mockManager.registerMockPlugin(it); it.manager = mockManager } + mockManager.registerProvidedArtefacts(grailsApplication) + mockManager.setApplicationContext(ctx) + + def springConfig = new DefaultRuntimeSpringConfiguration() + + springConfig.registerPostProcessor(new BeanFactoryPostProcessor() { + + @Override + void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + beanFactory.addBeanPostProcessor(new GrailsApplicationAwareBeanPostProcessor(grailsApplication)) + beanFactory.addBeanPostProcessor(new PluginManagerAwareBeanPostProcessor(mockManager)) + } + }) + + mockManager.doRuntimeConfiguration(springConfig) + springConfig.registerBeansWithRegistry(ctx) + ctx.refresh() + + grailsApplication.setApplicationContext(ctx) + grailsApplication.mainContext = ctx + appCtx = ctx + messageSource = ctx.getBean("messageSource", MessageSource) + + webRequest = GrailsWebMockUtil.bindMockWebRequest(ctx) + onInit() + try { + JstlUtils.exposeLocalizationContext webRequest.getRequest(), null + } + catch (Throwable ignore) { + } + + servletContext = webRequest.servletContext + + mockManager.doDynamicMethods() + initRequestAndResponse() + + ga.domainClasses.each { dc -> + def v = new PersistentEntityValidator() + v.targetClass = dc + dc.validator.messageSource = messageSource + } + } + + private initRequestAndResponse() { + request = webRequest.currentRequest + initThemeSource(request, messageSource) + request.characterEncoding = "utf-8" + response = webRequest.currentResponse + } + + private void initThemeSource(request, MessageSource messageSource) { + request.setAttribute(DispatcherServlet.THEME_SOURCE_ATTRIBUTE, new MockThemeSource(messageSource)) + request.setAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE, new SessionThemeResolver()) + } + + @AfterEach + protected void tearDown() { + // Clear the page cache in the template engine since it's + // static and likely to cause tests to interfere with each other. + appCtx.groovyPagesTemplateEngine.clearPageCache() + + RequestContextHolder.resetRequestAttributes() + GroovySystem.metaClassRegistry.setMetaClassCreationHandle(originalHandler) + + onDestroy() + ga.mainContext.close() + + Holders.servletContext = null + GroovyPageMetaInfo.DEFAULT_PLUGIN_PATH = "" + registryCleaner.clean() + GroovySystem.metaClassRegistry.removeMetaClassRegistryChangeEventListener(registryCleaner) + } + + protected void onInit() { + } + + protected void onDestroy() { + } + + protected void onInitMockBeans() { + } + + protected Resource[] getResources(String pattern) { + new PathMatchingResourcePatternResolver().getResources(pattern) + } + + void runTest(Closure callable) { + callable.call() + } + + void printCompiledSource(template, params = [:]) { + // def text = getCompiledSource(template, params) + // println "----- GSP SOURCE -----" + // println text + } + + def getCompiledSource(template, params = [:]) { + def engine = appCtx.groovyPagesTemplateEngine + + assert engine + def t = engine.createTemplate(template, "test_" + System.currentTimeMillis()) + + def w = t.make(params) + w.showSource = true + + def sw = new StringWriter() + def out = new PrintWriter(sw) + webRequest.out = out + w.writeTo(out) + + String text = sw.toString() + } + + def assertCompiledSourceContains(expected, template, params = [:]) { + def text = getCompiledSource(template, params) + return text.indexOf(expected) > -1 + } + + void assertOutputContains(expected, template, params = [:]) { + def result = applyTemplate(template, params) + assertTrue result.indexOf(expected) > -1, + "Output does not contain expected string [$expected]. Output was: [${result}]" + } + + void assertOutputNotContains(expected, template, params = [:]) { + def result = applyTemplate(template, params) + assertFalse result.indexOf(expected) > -1, + "Output should not contain the expected string [$expected]. Output was: [${result}]" + } + + /** + * Compares the output generated by a template with a string. + * @param expected The string that the template output is expected + * to match. + * @param template The template to run. + * @param params A map of variables to pass to the template - by + * default an empty map is used. + * @param transform A closure that is passed a StringWriter instance + * containing the output generated by the template. It is the result + * of this transformation that is actually compared with the expected + * string. The default transform simply converts the contents of the + * writer to a string. + */ + void assertOutputEquals(expected, template, params = [:], Closure transform = { it.toString() }) { + + GroovyPageTemplate t = createTemplate(template) + + /* + println "------------HTMLPARTS----------------------" + t.metaInfo.htmlParts.eachWithIndex {it, i -> print "htmlpart[${i}]:\n>${it}<\n--------\n" } + */ + + assertTemplateOutputEquals(expected, t, params, transform) + } + + protected GroovyPageTemplate createTemplate(template) { + GroovyPagesTemplateEngine engine = appCtx.groovyPagesTemplateEngine + + //printCompiledSource(template) + + assert engine + GroovyPageTemplate t = engine.createTemplate(template, "test_" + System.currentTimeMillis()) + t.allowSettingContentType = true + return t + } + + protected def assertTemplateOutputEquals(String expected, GroovyPageTemplate template, params = [:], Closure transform = { it.toString() }) { + def w = template.make(params) + + MockHttpServletResponse mockResponse = new MockHttpServletResponse() + mockResponse.setCharacterEncoding("UTF-8") + GSPResponseWriter writer = GSPResponseWriter.getInstance(mockResponse) + webRequest.out = writer + w.writeTo(writer) + + writer.flush() + assertEquals(expected, transform(mockResponse.contentAsString)) + } + + def applyTemplate(template, params = [:], target = null, String filename = null) { + + GroovyPagesTemplateEngine engine = appCtx.groovyPagesTemplateEngine + + //printCompiledSource(template) + + assert engine + def t = engine.createTemplate(template, filename ?: "test_" + System.currentTimeMillis()) + + def w = t.make(params) + + if (!target) { + target = new FastStringWriter() + } + webRequest.out = target + + w.writeTo(target) + target.flush() + + return target.toString() + } + + /** + * Applies sitemesh preprocessing to a template + */ + String sitemeshPreprocess(String template) { + def preprocessor = new SitemeshPreprocessor() + preprocessor.addGspSitemeshCapturing(template) + } + + String applyLayout(String layout, String template, Map params = [:]) { + def gspSiteMeshPage = new GSPSitemeshPage() + request.setAttribute(GrailsLayoutView.GSP_SITEMESH_PAGE, gspSiteMeshPage) + def content = applyTemplate(template, params) + request.removeAttribute(GrailsLayoutView.GSP_SITEMESH_PAGE) + + def page = null + if (!params.parse && gspSiteMeshPage != null && gspSiteMeshPage.isUsed()) { + page = gspSiteMeshPage + } + else { + def parser = new GrailsHTMLPageParser() + page = parser.parse(content.toCharArray()) + } + try { + request.setAttribute(RequestConstants.PAGE, page) + request.setAttribute(GrailsLayoutView.GSP_SITEMESH_PAGE, new GSPSitemeshPage()) + return applyTemplate(layout, params, null, "/layouts/test_" + System.currentTimeMillis()) + } + finally { + request.removeAttribute(RequestConstants.PAGE) + request.removeAttribute(GrailsLayoutView.GSP_SITEMESH_PAGE) + } + } + /** + * Parses the given XML text and creates a DOM document from it. + */ + protected final Document parseText(String xml) { + return domBuilder.parse(new ByteArrayInputStream(xml.getBytes("UTF-8"))) + } + + /** + * Asserts that the given XPath expression matches at least one + * node in the given DOM document. + */ + protected final void assertXPathExists(Document doc, String expr) { + assertTrue xpath.evaluate(expr, doc, XPathConstants.BOOLEAN) + } + + /** + * Asserts that the given XPath expression matches no nodes in the + * given DOM document. + */ + protected final void assertXPathNotExists(Document doc, String expr) { + assertFalse xpath.evaluate(expr, doc, XPathConstants.BOOLEAN) + } +} + +class MockThemeSource implements ThemeSource { + + private messageSource + + MockThemeSource(MessageSource messageSource) { + this.messageSource = messageSource + } + + Theme getTheme(String themeName) { new SimpleTheme(themeName, messageSource) } +} diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ApplicationTagLibResourcesTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ApplicationTagLibResourcesTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ApplicationTagLibResourcesTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ApplicationTagLibResourcesTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ApplicationTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ApplicationTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ApplicationTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ApplicationTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ApplyCodecTagSpec.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ApplyCodecTagSpec.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ApplyCodecTagSpec.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ApplyCodecTagSpec.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ControllerTagLibMethodDispatchSpec.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ControllerTagLibMethodDispatchSpec.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ControllerTagLibMethodDispatchSpec.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ControllerTagLibMethodDispatchSpec.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ControllerTagLibMethodInheritanceSpec.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ControllerTagLibMethodInheritanceSpec.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ControllerTagLibMethodInheritanceSpec.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ControllerTagLibMethodInheritanceSpec.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/CoreTagsTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/CoreTagsTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/CoreTagsTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/CoreTagsTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/CountryTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/CountryTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/CountryTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/CountryTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormRenderingTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormRenderingTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormRenderingTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormRenderingTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLib2Tests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLib2Tests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLib2Tests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLib2Tests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLib3Tests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLib3Tests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLib3Tests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLib3Tests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLibResourceTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLibResourceTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLibResourceTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLibResourceTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLibWithConfigSpec.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLibWithConfigSpec.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormTagLibWithConfigSpec.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormTagLibWithConfigSpec.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormatTagLibSpec.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormatTagLibSpec.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormatTagLibSpec.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormatTagLibSpec.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormatTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormatTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/FormatTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/FormatTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/InvokeTagLibAsMethodTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/InvokeTagLibAsMethodTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/InvokeTagLibAsMethodTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/InvokeTagLibAsMethodTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/InvokeTagLibWithBodyAsMethodTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/InvokeTagLibWithBodyAsMethodTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/InvokeTagLibWithBodyAsMethodTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/InvokeTagLibWithBodyAsMethodTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/JavascriptTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/JavascriptTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/JavascriptTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/JavascriptTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/JsessionIdMockHttpServletResponse.java b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/JsessionIdMockHttpServletResponse.java similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/JsessionIdMockHttpServletResponse.java rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/JsessionIdMockHttpServletResponse.java diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/LayoutWriterStackTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/LayoutWriterStackTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/LayoutWriterStackTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/LayoutWriterStackTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/LinkRenderingTagLib2Tests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/LinkRenderingTagLib2Tests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/LinkRenderingTagLib2Tests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/LinkRenderingTagLib2Tests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/LinkRenderingTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/LinkRenderingTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/LinkRenderingTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/LinkRenderingTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/MessageTagTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/MessageTagTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/MessageTagTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/MessageTagTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamedTagBodyParamsTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamedTagBodyParamsTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamedTagBodyParamsTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamedTagBodyParamsTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamespacedNamedUrlMappingTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamespacedNamedUrlMappingTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamespacedNamedUrlMappingTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamespacedNamedUrlMappingTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamespacedTagAndActionConflictTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamespacedTagAndActionConflictTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamespacedTagAndActionConflictTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamespacedTagAndActionConflictTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamespacedTagLibMethodTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamespacedTagLibMethodTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamespacedTagLibMethodTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamespacedTagLibMethodTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamespacedTagLibRenderMethodTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamespacedTagLibRenderMethodTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/NamespacedTagLibRenderMethodTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/NamespacedTagLibRenderMethodTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/OverlappingReverseMappedLinkTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/OverlappingReverseMappedLinkTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/OverlappingReverseMappedLinkTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/OverlappingReverseMappedLinkTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/PageScopeSpec.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/PageScopeSpec.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/PageScopeSpec.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/PageScopeSpec.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/PageScopeTagTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/PageScopeTagTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/PageScopeTagTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/PageScopeTagTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/PluginTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/PluginTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/PluginTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/PluginTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/RenderTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/RenderTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/RenderTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/RenderTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ReturnValueTagLibTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ReturnValueTagLibTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ReturnValueTagLibTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ReturnValueTagLibTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/SelectTagTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/SelectTagTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/SelectTagTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/SelectTagTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/TagLibraryDynamicPropertyTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/TagLibraryDynamicPropertyTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/TagLibraryDynamicPropertyTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/TagLibraryDynamicPropertyTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/UploadFormTagTests.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/UploadFormTagTests.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/UploadFormTagTests.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/UploadFormTagTests.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ValidationTagLibSpec.groovy b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ValidationTagLibSpec.groovy similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/ValidationTagLibSpec.groovy rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/ValidationTagLibSpec.groovy diff --git a/grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/grails-taglib-tests.xml b/grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/grails-taglib-tests.xml similarity index 100% rename from grace-plugin-gsp/src/test/groovy/org/grails/web/taglib/grails-taglib-tests.xml rename to grace-plugin-taglibs/src/test/groovy/org/grails/web/taglib/grails-taglib-tests.xml diff --git a/grace-test-suite-uber/build.gradle b/grace-test-suite-uber/build.gradle index cb5a40709f..3ad6ba1882 100644 --- a/grace-test-suite-uber/build.gradle +++ b/grace-test-suite-uber/build.gradle @@ -48,14 +48,7 @@ dependencies { exclude group: 'javassist', module: 'javassist' } testImplementation libs.grace.async.core - testImplementation project(":grace-plugin-gsp"), { - exclude module:'grace-plugin-codecs' - exclude module:'grace-plugin-controllers' - exclude module:'grace-core' - exclude module:'grace-plugin-domain-class' - exclude module:'grace-web-common' - exclude module:'grace-encoder' - } + testImplementation project(":grace-plugin-gsp") testRuntimeOnly libs.h2 testRuntimeOnly libs.aspectj.rt diff --git a/grace-test-suite-web/build.gradle b/grace-test-suite-web/build.gradle index 4e90caa1d4..d2a03b7a0e 100644 --- a/grace-test-suite-web/build.gradle +++ b/grace-test-suite-web/build.gradle @@ -59,14 +59,7 @@ dependencies { exclude group: 'javassist', module: 'javassist' } - testImplementation project(":grace-plugin-gsp"), { - exclude module:'grace-plugin-codecs' - exclude module:'grace-plugin-controllers' - exclude module:'grace-core' - exclude module:'grace-plugin-domain-class' - exclude module:'grace-web-common' - exclude module:'grace-encoder' - } + testImplementation project(":grace-plugin-gsp") testImplementation libs.grace.async.core testRuntimeOnly libs.spring.aspects diff --git a/grace-test-support/build.gradle b/grace-test-support/build.gradle index 47a74fc452..ab46411bf1 100755 --- a/grace-test-support/build.gradle +++ b/grace-test-support/build.gradle @@ -10,6 +10,7 @@ dependencies { api libs.grace.async.core api project(":grace-plugin-gsp") + api project(":grace-plugin-taglibs") api project(":grace-views-json") api project(":grace-web-gsp") api libs.groovy.test.junit5 diff --git a/grace-test-support/src/main/groovy/org/grails/testing/runtime/support/LazyTagLibraryLookup.java b/grace-test-support/src/main/groovy/org/grails/testing/runtime/support/LazyTagLibraryLookup.java index 6f2f8ab473..929b93aeb5 100644 --- a/grace-test-support/src/main/groovy/org/grails/testing/runtime/support/LazyTagLibraryLookup.java +++ b/grace-test-support/src/main/groovy/org/grails/testing/runtime/support/LazyTagLibraryLookup.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 the original author or authors. + * Copyright 2016-2025 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. @@ -26,7 +26,7 @@ import grails.core.gsp.GrailsTagLibClass; -import org.grails.plugins.web.GroovyPagesGrailsPlugin; +import org.grails.plugins.web.TaglibsGrailsPlugin; import org.grails.taglib.TagLibraryLookup; /** @@ -36,7 +36,7 @@ @SuppressWarnings({ "unchecked", "rawtypes" }) public class LazyTagLibraryLookup extends TagLibraryLookup { - List tagLibClasses = (List) new GroovyPagesGrailsPlugin().getProvidedArtefacts(); + List tagLibClasses = (List) new TaglibsGrailsPlugin().getProvidedArtefacts(); private final Map lazyLoadableTagLibs = new HashMap<>(); diff --git a/settings.gradle b/settings.gradle index b66b5d80f3..f77b335985 100644 --- a/settings.gradle +++ b/settings.gradle @@ -64,6 +64,7 @@ include ( 'grace-plugin-rest', 'grace-plugin-scaffolding', 'grace-plugin-services', + 'grace-plugin-taglibs', 'grace-plugin-url-mappings', 'grace-plugin-validation',