Skip to content

Commit

Permalink
[thymeleaf] Make fragments usable without view folder prefix
Browse files Browse the repository at this point in the history
This commit enhances the DefaultTemplateEngineProducer in a way that it
is possible to use Thymeleaf Fragments as they are shown in the
documentation.

Before this commit, only views returned by controllers were directly
found, because they had the '/WEB-INF/views/' prefix already added to
their path. Fragments which are called inside those views, like by using
'<div th:replace="fragments :: header"></div>', lead to an error, because
they were tried to resolve on the context root. One solution was to
clutter up those declarations by adding the view directory manually, but
this was error prone since the view directory might be changed by
configuration.

Now a second template resolver is checking for other files which are not
returned by controllers BUT are existent inside the view directory. This
way, the fragments can be used without using prefixes or suffixes.
  • Loading branch information
erdlet committed Aug 16, 2022
1 parent 6f1990f commit 59773b1
Show file tree
Hide file tree
Showing 17 changed files with 386 additions and 34 deletions.
4 changes: 2 additions & 2 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ pipeline {
}

stages {
stage("Compile") {
stage("Install") {
steps {
withMaven() {
sh "mvn -Pstaging clean compile"
sh "mvn -Pstaging clean install"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf;
package org.eclipse.krazo.test.ext.thymeleaf.base;

import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf;
package org.eclipse.krazo.test.ext.thymeleaf.base;

import jakarta.inject.Inject;
import jakarta.mvc.Controller;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,17 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf;
package org.eclipse.krazo.test.ext.thymeleaf.base;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
import java.util.Collections;
import java.util.Set;

/**
* Class MyApplication.
*
* @author Rodrigo Turini
*/
@ApplicationPath("resources")
public class MyApplication extends Application {
public class ThymeleafDefaultApplication extends Application {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
*
* 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf.customviewfolder;

import jakarta.enterprise.context.RequestScoped;
import jakarta.mvc.Controller;
import jakarta.mvc.View;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@RequestScoped
@Path("thymeleaf-fragments-custom")
@Controller
public class FragmentController {

@GET
@View("index.html")
public void fragmentedView() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
*
* 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf.customviewfolder;

import jakarta.mvc.engine.ViewEngine;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

import java.util.Map;

@ApplicationPath("resources")
public class ThymeleafCustomViewFolderApplication extends Application {

@Override public Map<String, Object> getProperties() {
return Map.of(ViewEngine.VIEW_FOLDER, "/WEB-INF/custom/");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
*
* 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf.viewfolder;

import jakarta.enterprise.context.RequestScoped;
import jakarta.mvc.Controller;
import jakarta.mvc.View;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@RequestScoped
@Path("thymeleaf-fragments")
@Controller
public class FragmentController {

@GET
@View("index.html")
public void fragmentedView() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
*
* 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf.viewfolder;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("resources")
public class ThymeleafDefaultViewFolderApplication extends Application {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div th:fragment="test" id="from-fragment">I'm from the fragment</div>
10 changes: 10 additions & 0 deletions testsuite/src/main/resources/thymeleaf/viewfolder/views/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Thymeleaf default view folder test</title>
</head>
<body>
<div th:replace="fragment :: test"></div>
</body>
</html>


Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014-2015 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2019 Eclipse Krazo committers and contributors
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,7 +16,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext;
package org.eclipse.krazo.test.ext.thymeleaf;

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomElement;
Expand All @@ -41,9 +41,9 @@
* @author Gregor Tudan
*/
@RunWith(Arquillian.class)
public class ThymeleafIT {
public class ThymeleafBaseIT {

private static final String WEB_INF_SRC = "src/main/resources/thymeleaf/";
private static final String WEB_INF_SRC = "src/main/resources/thymeleaf/base/";

@ArquillianResource
private URL baseURL;
Expand All @@ -62,7 +62,7 @@ public void setUp() {
@Deployment(testable = false, name = "thymeleaf")
public static WebArchive createDeployment() {
return new WebArchiveBuilder()
.addPackage("org.eclipse.krazo.test.ext.thymeleaf")
.addPackage("org.eclipse.krazo.test.ext.thymeleaf.base")
.addView(Paths.get(WEB_INF_SRC).resolve("views/hello.html").toFile(), "hello.html")
.addBeansXml()
.addDependency("org.eclipse.krazo.ext:krazo-thymeleaf")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
*
* 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf;

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.eclipse.krazo.test.ext.util.WebArchiveBuilder;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.net.URL;
import java.nio.file.Paths;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

/**
* This test verifies that another view folder can be used to get Thymeleaf fragments.
* This test uses the same HTML files than
*/
@RunWith(Arquillian.class)
public class ThymeleafFragmentsCustomViewFolderIT {

private static final String WEB_INF_SRC = "src/main/resources/thymeleaf/viewfolder/";

@ArquillianResource
private URL baseURL;

private WebClient webClient;

@Before
public void setUp() {
webClient = new WebClient();
webClient.getOptions()
.setThrowExceptionOnFailingStatusCode(false);
webClient.getOptions()
.setRedirectEnabled(true);
}

@Deployment(testable = false, name = "thymeleaf-fragments-custom")
public static WebArchive createDeployment() {
return new WebArchiveBuilder()
.addPackage("org.eclipse.krazo.test.ext.thymeleaf.customviewfolder")
.addView(Paths.get(WEB_INF_SRC).resolve("views/index.html").toFile(), "custom","index.html")
.addView(Paths.get(WEB_INF_SRC).resolve("views/fragment.html").toFile(), "custom","fragment.html")
.addBeansXml()
.addDependency("org.eclipse.krazo.ext:krazo-thymeleaf")
.build();
}

@Test
public void shouldResolveFragment() throws Exception {
final HtmlPage page = webClient.getPage(baseURL + "resources/thymeleaf-fragments-custom");
final DomElement div = page.getElementById("from-fragment");
assertNotNull(div);
assertTrue(div.getTextContent().contains("I'm from the fragment"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2018, 2022 Eclipse Krazo committers and contributors
*
* 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.eclipse.krazo.test.ext.thymeleaf;

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.eclipse.krazo.test.ext.util.WebArchiveBuilder;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.net.URL;
import java.nio.file.Paths;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

/**
* This test verifies that the default view folder set by MVC / Krazo is used to resolved
* fragments.
*/
@RunWith(Arquillian.class)
public class ThymeleafFragmentsDefaultViewFolderIT {

private static final String WEB_INF_SRC = "src/main/resources/thymeleaf/viewfolder/";

@ArquillianResource
private URL baseURL;

private WebClient webClient;

@Before
public void setUp() {
webClient = new WebClient();
webClient.getOptions()
.setThrowExceptionOnFailingStatusCode(false);
webClient.getOptions()
.setRedirectEnabled(true);
}

@Deployment(testable = false, name = "thymeleaf-fragments")
public static WebArchive createDeployment() {
return new WebArchiveBuilder()
.addPackage("org.eclipse.krazo.test.ext.thymeleaf.viewfolder")
.addView(Paths.get(WEB_INF_SRC).resolve("views/index.html").toFile(), "index.html")
.addView(Paths.get(WEB_INF_SRC).resolve("views/fragment.html").toFile(), "fragment.html")
.addBeansXml()
.addDependency("org.eclipse.krazo.ext:krazo-thymeleaf")
.build();
}

@Test
public void shouldResolveFragment() throws Exception {
final HtmlPage page = webClient.getPage(baseURL + "resources/thymeleaf-fragments");
final DomElement div = page.getElementById("from-fragment");
assertNotNull(div);
assertTrue(div.getTextContent().contains("I'm from the fragment"));
}
}
Loading

0 comments on commit 59773b1

Please sign in to comment.