You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rz...@apache.org on 2024/07/03 18:43:28 UTC
(tomee) branch main updated: TOMEE-4332 Load SpringWebUtils in the context class loader in TomEE w… (#1166)
This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomee.git
The following commit(s) were added to refs/heads/main by this push:
new a8edb2f4a7 TOMEE-4332 Load SpringWebUtils in the context class loader in TomEE w… (#1166)
a8edb2f4a7 is described below
commit a8edb2f4a7588ee3ea266b69d42435ce27649ec2
Author: Jonathan Gallimore <jo...@jrg.me.uk>
AuthorDate: Wed Jul 3 19:43:23 2024 +0100
TOMEE-4332 Load SpringWebUtils in the context class loader in TomEE w… (#1166)
* TOMEE-4332 Load SpringWebUtils in the context class loader in TomEE when the cxf-rs service is initialized
* Fix missing license headers
---------
Co-authored-by: Richard Zowalla <rz...@apache.org>
---
.../arquillian-tomee-jaxrs-tests/pom.xml | 22 +++
.../tests/jaxrs/spring/AlternativeGreeter.java | 38 +++++
.../tests/jaxrs/spring/DemoApplication.java | 29 ++++
.../tests/jaxrs/spring/GreetingController.java | 35 +++++
.../tests/jaxrs/spring/ServletInitializer.java | 29 ++++
.../tests/jaxrs/spring/SpringWebappTest.java | 158 +++++++++++++++++++++
.../src/test/resources/spring-webmvc-pom.xml | 61 ++++++++
.../apache/openejb/server/cxf/rs/CxfRSService.java | 6 +
8 files changed, 378 insertions(+)
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/pom.xml b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/pom.xml
index 6092894a7f..79e888a922 100644
--- a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/pom.xml
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/pom.xml
@@ -40,6 +40,28 @@
<version>${project.version}</version>
<type>war</type>
</dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-loader-tools</artifactId>
+ <version>3.1.11</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <version>3.1.11</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-tomcat</artifactId>
+ <version>3.1.11</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <version>3.1.11</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<properties>
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/AlternativeGreeter.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/AlternativeGreeter.java
new file mode 100644
index 0000000000..1f260e02df
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/AlternativeGreeter.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.openejb.arquillian.tests.jaxrs.spring;
+
+import jakarta.ejb.Lock;
+import jakarta.ejb.LockType;
+import jakarta.ejb.Singleton;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+
+@Singleton
+@Lock(LockType.READ)
+public class AlternativeGreeter {
+
+ @Path("hello")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String sayHello() {
+ return "Hello World!";
+ }
+
+}
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/DemoApplication.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/DemoApplication.java
new file mode 100644
index 0000000000..6236078f62
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/DemoApplication.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.openejb.arquillian.tests.jaxrs.spring;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DemoApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+
+}
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/GreetingController.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/GreetingController.java
new file mode 100644
index 0000000000..6cab6ff394
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/GreetingController.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.openejb.arquillian.tests.jaxrs.spring;
+
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+@RequestMapping("/greet")
+public class GreetingController {
+
+ @GetMapping(produces = MediaType.TEXT_PLAIN_VALUE)
+ @ResponseBody
+ public String sayHello() {
+ return "Hello World!";
+ }
+
+}
\ No newline at end of file
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/ServletInitializer.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/ServletInitializer.java
new file mode 100644
index 0000000000..85291247c8
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/ServletInitializer.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.openejb.arquillian.tests.jaxrs.spring;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+public class ServletInitializer extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(DemoApplication.class);
+ }
+
+}
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/SpringWebappTest.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/SpringWebappTest.java
new file mode 100644
index 0000000000..9599c001d2
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/spring/SpringWebappTest.java
@@ -0,0 +1,158 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.openejb.arquillian.tests.jaxrs.spring;
+
+import org.apache.ziplock.WebModule;
+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.ShrinkWrap;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jboss.shrinkwrap.resolver.api.ResolutionException;
+import org.jboss.shrinkwrap.resolver.api.ResolvedArtifact;
+import org.jboss.shrinkwrap.resolver.api.maven.Maven;
+import org.jboss.shrinkwrap.resolver.api.maven.MavenResolvedArtifact;
+import org.jboss.shrinkwrap.resolver.api.maven.ScopeType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.loader.tools.Libraries;
+import org.springframework.boot.loader.tools.Library;
+import org.springframework.boot.loader.tools.LibraryCallback;
+import org.springframework.boot.loader.tools.LibraryScope;
+import org.springframework.boot.loader.tools.Repackager;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Arquillian.class)
+public class SpringWebappTest {
+
+ @ArquillianResource
+ private URL url;
+
+ @Deployment(testable = false)
+ public static WebArchive getArchive() throws Exception {
+ MavenResolvedArtifact[] dependencies;
+ try { // try offline first since it is generally faster
+ dependencies = Maven.configureResolver()
+ .workOffline()
+ .loadPomFromFile("src/test/resources/spring-webmvc-pom.xml")
+ .importCompileAndRuntimeDependencies().resolve().withTransitivity()
+ .asResolvedArtifact();
+ } catch (ResolutionException re) { // try on central
+ dependencies = Maven.resolver()
+ .loadPomFromFile("src/test/resources/spring-webmvc-pom.xml")
+ .importCompileAndRuntimeDependencies().resolve().withTransitivity()
+ .asResolvedArtifact();
+ }
+
+
+ final WebArchive archive = new WebModule(SpringWebappTest.class.getSimpleName()).getArchive();
+ archive.addClasses(AlternativeGreeter.class, DemoApplication.class, GreetingController.class, ServletInitializer.class);
+ archive.addAsLibraries(toFiles(dependencies));
+
+ // repackage as a Spring Boot WAR file
+ final File originalWarFile = File.createTempFile("test", ".war");
+ archive.as(ZipExporter.class).exportTo(originalWarFile, true);
+
+ final Repackager repackager = new Repackager(originalWarFile);
+ final File repackagedWarFile = File.createTempFile("repackaged", ".war");
+
+ repackager.repackage(repackagedWarFile, new MavenResolvedArtifactLibraries(dependencies));
+
+ final WebArchive repackaged = ShrinkWrap.createFromZipFile(WebArchive.class, repackagedWarFile);
+
+ System.out.println(repackaged.toString(true));
+ return repackaged;
+ }
+
+ private static File[] toFiles(MavenResolvedArtifact[] dependencies) {
+ return Arrays.stream(dependencies)
+ .map(ResolvedArtifact::asFile)
+ .collect(Collectors.toList())
+ .toArray(new File[dependencies.length]);
+ }
+
+ @Test
+ public void validate() throws Exception {
+ final String launchProfile = System.getProperty("arquillian.launch");
+ if ("tomee-embedded".equals(launchProfile)) {
+ System.out.println("Skipping this test in TomEE embedded");
+ return;
+ }
+
+ final InputStream is = new URL(url.toExternalForm() + "hello").openStream();
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ int bytesRead;
+ byte[] buffer = new byte[8192];
+ while ((bytesRead = is.read(buffer)) > -1) {
+ os.write(buffer, 0, bytesRead);
+ }
+
+ is.close();
+ os.close();
+
+ final String output = new String(os.toByteArray(), "UTF-8");
+ assertNotNull("Response shouldn't be null", output);
+ assertTrue("Output should contain: " + "Hello World!" + "\n" + output, output.contains("Hello World!"));
+ }
+
+ public static class MavenResolvedArtifactLibraries implements Libraries {
+
+ private final MavenResolvedArtifact[] artifacts;
+
+ public MavenResolvedArtifactLibraries(final MavenResolvedArtifact[] artifacts) {
+ this.artifacts = artifacts;
+ }
+
+ @Override
+ public void doWithLibraries(final LibraryCallback callback) throws IOException {
+ for (final MavenResolvedArtifact artifact : artifacts) {
+ callback.library(new Library(artifact.asFile(), toScope(artifact)));
+ }
+ }
+
+ private LibraryScope toScope(MavenResolvedArtifact artifact) {
+ final ScopeType scope = artifact.getScope();
+ if (ScopeType.COMPILE.equals(scope)) {
+ return LibraryScope.COMPILE;
+ } else if (ScopeType.RUNTIME.equals(scope)) {
+ return LibraryScope.COMPILE;
+ } else if (ScopeType.TEST.equals(scope)) {
+ return LibraryScope.PROVIDED;
+ } else if (ScopeType.PROVIDED.equals(scope)) {
+ return LibraryScope.PROVIDED;
+ } else if (ScopeType.SYSTEM.equals(scope)) {
+ return LibraryScope.CUSTOM;
+ } else if (ScopeType.IMPORT.equals(scope)) {
+ return LibraryScope.CUSTOM;
+ }
+
+ throw new IllegalStateException("Unsupported scope: " + scope);
+ }
+ }
+}
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/resources/spring-webmvc-pom.xml b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/resources/spring-webmvc-pom.xml
new file mode 100644
index 0000000000..3706e818cc
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxrs-tests/src/test/resources/spring-webmvc-pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <version>3.1.11</version>
+ <relativePath/> <!-- lookup parent from repository -->
+ </parent>
+ <groupId>org.apache.openejb.arquillian.tests</groupId>
+ <artifactId>spring-webmvc-deps</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>war</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.tomcat.embed</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-tomcat</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomee</groupId>
+ <artifactId>jakartaee-api</artifactId>
+ <version>10.0-M2</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java
index f8f78eb1b2..1035eca7fe 100644
--- a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java
+++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java
@@ -167,6 +167,12 @@ public class CxfRSService extends RESTService {
config = properties;
factoryByListener = "true".equalsIgnoreCase(properties.getProperty("openejb.cxf-rs.factoryByListener", "false"));
+ try {
+ Class.forName("org.apache.cxf.jaxrs.springmvc.SpringWebUtils");
+ } catch (Throwable t) {
+ // ignore
+ }
+
System.setProperty("org.apache.johnzon.max-string-length",
SystemInstance.get().getProperty("org.apache.johnzon.max-string-length",
properties.getProperty("org.apache.johnzon.max-string-length", "8192")));