Closed fcruzrj closed 8 months ago
Hello @fcruzrj
Thanks for reporting the issue. I am looking into it.
Why don't you use a FilterRegistrationBean
to register the filter?
Hello @codeconsole.
Thanks a lot. Your answer helped me configure Sitemesh in Spring Boot, which I didn't know was possible. The error I reported occurs in a Eclipse Maven project with Spring MVC.
Hi @fcruzrj, yeah, there is a full SiteMesh3 String Boot starter example app.
All you need is the starter dependency:
org:sitemesh:spring-boot-starter-sitemesh:3.2.0-M2
The issue you were having with AbstractAnnotationConfigDispatcherServletInitializer
is that it is trying to add the ConfigurableSiteMeshFilter
a second time because it was automatically injected due to the @WebFilter
annotation it has. The ConfigurableSiteMeshFilter
must be configured prior to the application container attempting to add the @WebFilter
s. Using web.xml
always overrides all Filter
settings.
Hi @codeconsole,
Thanks for the example!
I used web.xml because java based config didn't works. With java based only, I debug the filter but the generated html isn't decorated.
P.S.: Java based config in Spring Boot application worked!
@fcruzrj What I am saying is there was no need to use web.xml
in the first place because SiteMesh configures automatically without Spring Boot if you have the sitemesh jar in the class path. All you need to do is add /WEB-INF/sitemesh3.xml
to configure it or just add a meta tag to any html page and it will decorate it automatically using convention over configuration.
The default (non spring boot) configuration expects decorators to be in the /WEB-INF/decorators
folder.
Here is a very simple example: https://github.com/codeconsole/spring6-filter
@fcruzrj - I've updated https://github.com/codeconsole/spring6-filter to resemble your configuration and show that you are ending up with 2 filters initialized.
The first one is because Sitemesh is initialized by tomcat automatically due sitemesh being in the classpath. ConfigurableSiteMeshFilter
has a @WebFilter
annotation which is detected in the scan.
The second initialization was due to your protected Filter[] getServletFilters() {
method.
The reason why you were not seeing anything and thinking it was not working is because you did not have a sitemesh3.xml
file that defined url mappings and/or did not define a decorator in any html page using the decorator meta tag.
I've added logging to show when SiteMesh is initialized and also to detect if more than 1 filter has been initialized.
I am closing this ticket due to https://github.com/sitemesh/sitemesh3/commit/f8556d3747fa63481b8fa79543ba3984bf1e7ed3 and https://github.com/sitemesh/sitemesh3/commit/eea55c3b2ada5f0a7bdc61cbd61f29a8f6d13e8c now providing this logging information.
Feel free to reach out if you are experiencing any other issues.
Similar issue here.
Currently i used sitemesh 3.1, springframework 5, fully Java based configuration. (without any xml)
I created CustomFilter, which implements applyCustomConfiguration.
public class MeshFilter extends ConfigurableSiteMeshFilter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("Start URI checking");
super.init(filterConfig);
}
@Override
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
builder.setDecoratorPrefix("/WEB-INF/views/layout")
.addDecoratorPath("/*", "main.jsp")
.addDecoratorPath("/auth/*", "auth.jsp");
}
@Override
public void destroy() {
log.info("End URI checking");
super.destroy();
}
}
So, I enrolled
FilterRegistration.Dynamic filter =
servletContext.addFilter("sitemesh", MeshFilter.class);
filter.addMappingForUrlPatterns(null, false, "*");
filter.setInitParameter("encoding", "utf-8");
filter.addMappingForServletNames(null, false, "dispatcher");
It always logged register twice. It not only works, but also I want to replace Sitemesh Default Filter, not 2 filter initialized. If I use sitemesh3.xml and use default filter, it works. But java based config? not works.
How can I achieve this? ONLY IN FULLY JAVA CONFIG. (Even sitemesh3.xml too. because i set this config in my custom filter)
@xkguq007 it registers twice because you are using a different name than the java config. If you want to override the default configuration, you have to register your filter with the name configurableSiteMeshFilter
@codeconsole thanks for fast reply.
public class SpringStarter implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
FilterRegistration reg = servletContext.getFilterRegistration("configurableSiteMeshFilter");
FilterRegistration.Dynamic filter =
servletContext.addFilter("configurableSiteMeshFilter", new MeshFilter());
filter.addMappingForUrlPatterns(null, false, "*");
filter.setInitParameter("encoding", "utf-8");
filter.addMappingForServletNames(null, false, "dispatcher");
// Root Context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootContextConfiguration.class);
servletContext.addListener(new ContextLoaderListener(rootContext));
...
}
}
FilterRegistration.Dynamic filter always null which means already enrolled.
@Slf4j
@RequiredArgsConstructor
public class MeshFilter extends ConfigurableSiteMeshFilter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("Start URI checking");
super.init(filterConfig);
}
@Override
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
builder.setDecoratorPrefix("/WEB-INF/views/layout")
.addDecoratorPath("/*", "main.jsp")
.addDecoratorPath("/auth/*", "auth.jsp");
}
@Override
public void destroy() {
log.info("End URI checking");
super.destroy();
}
}
My Custom Filter does not have any annotation which indicates filter, component, or else. I set my filter on top of onStartup method. and, reg which define first line on method, is not null. reg is already set by org.sitemesh. any thought about this problem?
ps) fun thing is when i debugged in first line of configurablesitemeshfilter init method and first line of onStartup method, it breaks onStartup method first.
hello @xkguq007, I need some more time to look into this, but I will get it working for you.
@xkguq007 can you please provide me with a very minimal gradle example that does not work?
https://github.com/xkguq007/spring5-filter I forked your test repository, https://github.com/codeconsole/spring6-filter. Just delete sitemesh3.xml and set version spring6 to spring5, jakarta to javax, sitemesh3.2 to 3.1.
In this code, you've been set your own filter and first line of onStartup, you check already that enrolled default filter or not. Run your code, you can check the log that already initialized default filter. This is exactly same as my condition.
I think my forked code's log must not hit the code logger.severe(String.format("*** '%s'
this line. but still hit.
So, Any decorator is not work. Because i removed sitemesh3.xml, and not register my custom filter.
In conclusion, the problem is "I didn't register any sitemesh filter before, except for my customs. It still has default filter" with condition, do not use any xml, including web.xml, sitemesh3.xml, etc.
@xkguq007 the issue is that you need to register your filter prior to @WebFilter
being initialized by the embedded server.
https://stackoverflow.com/questions/18704226/disable-webfilter-embedded-in-dependency-jar
Are you using Spring Boot, if so, you can just create a FilterRegistrationBean
to disable it?
https://github.com/spring-projects/spring-boot/issues/2173
If neither of these solutions work for you, we can explore providing a release that does not have @WebFilter
in it. The key is that you register your filter with the same name before the server attempts to initialize one automatically.
@codeconsole Thank you for your help. I'm using Spring Framework not Spring Boot. I saw stackoverflow links, two answers which is in link is not proper, neither. One is for spring boot, the other(selected) is little hacky way I think. Not unregister, but makes unwanted filter useless.
New release version without @Webfilter
will be the best option for me. Also I prefer registering filter explicitly.
Ok, we will look into repackaging. You can expect a new release in a week timeframe.
@xkguq007 you want to give the latest snapshot a try?
repositories {
mavenCentral()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
dependencies {
runtimeOnly 'org.sitemesh:sitemesh:3.2.1-SNAPSHOT'
}
I separated it here: https://github.com/sitemesh/sitemesh3/commit/7b01ebb46833f0531a1626428b155f6d0d498d56
@codeconsole Thank you I'll give it a try it. I'll close this issue when this dependency works.
@xkguq007 I will do an official release after you confirm it working
@xkguq007 were you able to confirm this working?
@codeconsole Sorry for late. Yeah, I checked it works and it's related source code changes. I will use this SNAPSHOT version until GA version released. Thanks for your help and I think this issue can be closed.
@xkguq007 3.2.1 and 3.1.1 have both just been released to maven central.
@codeconsole I checked maven central that version has been released! Thanks for your help.
Hello,
I tried the java-based configuration but it doesn't work.
I created a custom filter as in the example on the website and registered it in my Spring MVC application according to the code below.
JAKARTA EE 17 SITEMESH 3.2.0-M2 SPRING FRAMEWORK 6.0.12 APACHE TOMCAT 10.1.13 ECLIPSE 2023-09 (4.29.0)
//custom filter public class MySiteMeshFilter extends ConfigurableSiteMeshFilter { @Override protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) { builder.addDecoratorPath("/*", "/decorator.html") .addDecoratorPath("/admin/*", "/admin/decorator.html"); } }
`public class AppConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
}`
If I register the custom filter using web.xml, works.
`
EDIT 1:
With Java based config I can set a breakpoint and debug my CustomSitemeshFilter class, but the decorator is not applied.
Thank you very much in advance.