Remove support for Jersey

Spring Boot 4 requires Jakarta EE 11. Jersey 4 will support EE 11 but
its release schedule is uncertain. Furthermore, Jersey does not yet
support Jackson 3 and there's no clear timeline for when Jackson 3
will be supported.

In light of the above, this commit removes support for Jersey.
Reinstating support can be considered once there's a Jersey GA that
supports Jakarta EE 11 or its clear that one will be available in
time for Boot's GA in November. Ideally, support for Jackson 3 would
also be available before reinstating Jersey support.

Closes gh-47017
This commit is contained in:
Andy Wilkinson 2025-08-27 12:27:05 +01:00
parent b52c55d633
commit 8bfb170ebc
118 changed files with 32 additions and 6967 deletions

View File

@ -86,7 +86,6 @@ def dependenciesOf(String version) {
"spring-boot-integration",
"spring-boot-jackson",
"spring-boot-jdbc",
"spring-boot-jersey",
"spring-boot-jetty",
"spring-boot-jms",
"spring-boot-jooq",
@ -133,19 +132,24 @@ def dependenciesOf(String version) {
"spring-boot-webservices",
"spring-boot-zipkin"
]
if (version.equals("4.0.0-M1")) {
if (version.equals("4.0.0-M1") || version.equals("4.0.0-M2")) {
modules += [
"spring-boot-metrics",
"spring-boot-observation",
"spring-boot-tracing"
]
}
else {
modules += [
"spring-boot-micrometer-metrics",
"spring-boot-micrometer-observation",
"spring-boot-micrometer-tracing"
"spring-boot-jersey"
]
if (version.equals("4.0.0-M1")) {
modules += [
"spring-boot-metrics",
"spring-boot-observation",
"spring-boot-tracing"
]
}
else {
modules += [
"spring-boot-micrometer-metrics",
"spring-boot-micrometer-observation",
"spring-boot-micrometer-tracing"
]
}
}
return modules
}

View File

@ -138,8 +138,6 @@ dependencies {
implementation("org.assertj:assertj-core")
implementation("org.cache2k:cache2k-spring")
implementation("org.apache.groovy:groovy")
implementation("org.glassfish.jersey.containers:jersey-container-servlet-core")
implementation("org.glassfish.jersey.core:jersey-server")
implementation("org.hibernate.orm:hibernate-jcache") {
exclude group: "javax.activation", module: "javax.activation-api"
exclude group: "javax.persistence", module: "javax.persistence-api"

View File

@ -63,7 +63,7 @@ xref:reference:features/index.adoc[The following content is for you]:
If you develop Spring Boot web applications, take a look at the following content:
* *Servlet Web Applications:* xref:reference:web/servlet.adoc[Spring MVC, Jersey, Embedded Servlet Containers]
* *Servlet Web Applications:* xref:reference:web/servlet.adoc[Spring MVC, Embedded Servlet Containers]
* *Reactive Web Applications:* xref:reference:web/reactive.adoc[Spring Webflux, Embedded Servlet Containers]
* *Graceful Shutdown:* xref:reference:web/graceful-shutdown.adoc[Graceful Shutdown]
* *Spring Security:* xref:reference:web/spring-security.adoc[Default Security Configuration, Auto-configuration for OAuth2, SAML]

View File

@ -566,12 +566,6 @@
* xref:how-to:index.adoc#howto[#howto]
* xref:how-to:index.adoc[#howto]
* xref:how-to:index.adoc[howto]
* xref:how-to:jersey.adoc#howto.jersey.alongside-another-web-framework[#howto-jersey-alongside-another-web-framework]
* xref:how-to:jersey.adoc#howto.jersey.alongside-another-web-framework[#howto.jersey.alongside-another-web-framework]
* xref:how-to:jersey.adoc#howto.jersey.spring-security[#howto-jersey-spring-security]
* xref:how-to:jersey.adoc#howto.jersey.spring-security[#howto.jersey.spring-security]
* xref:how-to:jersey.adoc#howto.jersey[#howto-jersey]
* xref:how-to:jersey.adoc#howto.jersey[#howto.jersey]
* xref:how-to:logging.adoc#howto.logging.log4j.composite-configuration[#howto.logging.log4j.composite-configuration]
* xref:how-to:logging.adoc#howto.logging.log4j.yaml-or-json-config[#howto-configure-log4j-for-logging-yaml-or-json-config]
* xref:how-to:logging.adoc#howto.logging.log4j.yaml-or-json-config[#howto.logging.log4j.yaml-or-json-config]
@ -1152,8 +1146,6 @@
* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.http-clients[#production-ready-metrics-http-clients]
* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jdbc[#actuator.metrics.supported.jdbc]
* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jdbc[#production-ready-metrics-jdbc]
* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jersey[#actuator.metrics.supported.jersey]
* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jersey[#production-ready-metrics-jersey-server]
* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jetty[#actuator.metrics.supported.jetty]
* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jms[#actuator.metrics.supported.jms]
* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jvm[#actuator.metrics.supported.jvm]
@ -2130,9 +2122,6 @@
* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#boot-features-embedded-container]
* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#features.developing-web-applications.embedded-container]
* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#web.servlet.embedded-container]
* xref:reference:web/servlet.adoc#web.servlet.jersey[#boot-features-jersey]
* xref:reference:web/servlet.adoc#web.servlet.jersey[#features.developing-web-applications.jersey]
* xref:reference:web/servlet.adoc#web.servlet.jersey[#web.servlet.jersey]
* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#boot-features-spring-mvc-auto-configuration]
* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#features.developing-web-applications.spring-mvc.auto-configuration]
* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#web.servlet.spring-mvc.auto-configuration]

View File

@ -1,26 +0,0 @@
[[howto.jersey]]
= Jersey
[[howto.jersey.spring-security]]
== Secure Jersey Endpoints with Spring Security
Spring Security can be used to secure a Jersey-based web application in much the same way as it can be used to secure a Spring MVC-based web application.
However, if you want to use Spring Security's method-level security with Jersey, you must configure Jersey to use `setStatus(int)` rather `sendError(int)`.
This prevents Jersey from committing the response before Spring Security has had an opportunity to report an authentication or authorization failure to the client.
The `jersey.config.server.response.setStatusOverSendError` property must be set to `true` on the application's javadoc:org.glassfish.jersey.server.ResourceConfig[] bean, as shown in the following example:
include-code::JerseySetStatusOverSendErrorConfig[]
[[howto.jersey.alongside-another-web-framework]]
== Use Jersey Alongside Another Web Framework
To use Jersey alongside another web framework, such as Spring MVC, it should be configured so that it will allow the other framework to handle requests that it cannot handle.
First, configure Jersey to use a filter rather than a servlet by configuring the configprop:spring.jersey.type[] application property with a value of `filter`.
Second, configure your javadoc:org.glassfish.jersey.server.ResourceConfig[] to forward requests that would have resulted in a 404, as shown in the following example.
include-code::JerseyConfig[]

View File

@ -4,7 +4,6 @@
** xref:how-to:properties-and-configuration.adoc[]
** xref:how-to:webserver.adoc[]
** xref:how-to:spring-mvc.adoc[]
** xref:how-to:jersey.adoc[]
** xref:how-to:http-clients.adoc[]
** xref:how-to:logging.adoc[]
** xref:how-to:data-access.adoc[]

View File

@ -95,7 +95,7 @@ Subject to xref:actuator/endpoints.adoc#actuator.endpoints.sanitization[sanitiza
| Performs a thread dump.
|===
If your application is a web application (Spring MVC, Spring WebFlux, or Jersey), you can use the following additional endpoints:
If your application is a web application (Spring MVC or Spring WebFlux), you can use the following additional endpoints:
[cols="2,5"]
|===
@ -388,8 +388,7 @@ TIP: See javadoc:org.springframework.boot.actuate.autoconfigure.endpoint.web.Cor
== Implementing Custom Endpoints
If you add a javadoc:org.springframework.context.annotation.Bean[format=annotation] annotated with javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation], any methods annotated with javadoc:org.springframework.boot.actuate.endpoint.annotation.ReadOperation[format=annotation], javadoc:org.springframework.boot.actuate.endpoint.annotation.WriteOperation[format=annotation], or javadoc:org.springframework.boot.actuate.endpoint.annotation.DeleteOperation[format=annotation] are automatically exposed over JMX and, in a web application, over HTTP as well.
Endpoints can be exposed over HTTP by using Jersey, Spring MVC, or Spring WebFlux.
If both Jersey and Spring MVC are available, Spring MVC is used.
Endpoints can be exposed over HTTP by using Spring MVC or Spring WebFlux.
The following example exposes a read operation that returns a custom object:
@ -451,8 +450,7 @@ Before calling an operation method, the input received over JMX or HTTP is conve
[[actuator.endpoints.implementing-custom.web]]
=== Custom Web Endpoints
Operations on an javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation], javadoc:org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint[format=annotation], or javadoc:org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension[format=annotation] are automatically exposed over HTTP using Jersey, Spring MVC, or Spring WebFlux.
If both Jersey and Spring MVC are available, Spring MVC is used.
Operations on an javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation], javadoc:org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint[format=annotation], or javadoc:org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension[format=annotation] are automatically exposed over HTTP using Spring MVC or Spring WebFlux.
@ -540,8 +538,6 @@ If an operation is invoked without a required parameter or with a parameter that
You can use an HTTP range request to request part of an HTTP resource.
When using Spring MVC or Spring Web Flux, operations that return a javadoc:org.springframework.core.io.Resource[] automatically support range requests.
NOTE: Range requests are not supported when using Jersey.
[[actuator.endpoints.implementing-custom.web.security]]

View File

@ -765,39 +765,6 @@ Applications can opt in and record exceptions by xref:web/reactive.adoc#web.reac
[[actuator.metrics.supported.jersey]]
=== Jersey Server Metrics
Auto-configuration enables the instrumentation of all requests handled by the Jersey JAX-RS implementation.
By default, metrics are generated with the name, `http.server.requests`.
You can customize the name by setting the configprop:management.observations.http.server.requests.name[] property.
By default, Jersey server metrics are tagged with the following information:
|===
| Tag | Description
| `exception`
| The simple class name of any exception that was thrown while handling the request.
| `method`
| The request's method (for example, `GET` or `POST`)
| `outcome`
| The request's outcome, based on the status code of the response.
1xx is `INFORMATIONAL`, 2xx is `SUCCESS`, 3xx is `REDIRECTION`, 4xx is `CLIENT_ERROR`, and 5xx is `SERVER_ERROR`
| `status`
| The response's HTTP status code (for example, `200` or `500`)
| `uri`
| The request's URI template prior to variable substitution, if possible (for example, `/api/person/\{id}`)
|===
To customize the tags, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements javadoc:io.micrometer.core.instrument.binder.jersey.server.JerseyObservationConvention[].
[[actuator.metrics.supported.ssl]]
=== SSL Bundle Metrics

View File

@ -5,8 +5,7 @@ If you are developing a web application, Spring Boot Actuator auto-configures al
The default convention is to use the `id` of the endpoint with a prefix of `/actuator` as the URL path.
For example, `health` is exposed as `/actuator/health`.
TIP: Actuator is supported natively with Spring MVC, Spring WebFlux, and Jersey.
If both Jersey and Spring MVC are available, Spring MVC is used.
TIP: Actuator is supported natively with Spring MVC and Spring WebFlux.
NOTE: Jackson is a required dependency in order to get the correct JSON responses as documented in the xref:api:rest/actuator/index.adoc[API documentation].

View File

@ -1,7 +1,7 @@
[[web.servlet]]
= Servlet Web Applications
If you want to build servlet-based web applications, you can take advantage of Spring Boot's auto-configuration for Spring MVC or Jersey.
If you want to build servlet-based web applications, you can take advantage of Spring Boot's auto-configuration for Spring MVC.
@ -497,43 +497,6 @@ See xref:io/rest-client.adoc#io.rest-client.apiversioning[] for details.
[[web.servlet.jersey]]
== JAX-RS and Jersey
If you prefer the JAX-RS programming model for REST endpoints, you can use one of the available implementations instead of Spring MVC.
https://jersey.github.io/[Jersey] and https://cxf.apache.org/[Apache CXF] work quite well out of the box.
CXF requires you to register its javadoc:jakarta.servlet.Servlet[] or javadoc:jakarta.servlet.Filter[] as a javadoc:org.springframework.context.annotation.Bean[format=annotation] in your application context.
Jersey has some native Spring support, so we also provide auto-configuration support for it in Spring Boot, together with a starter.
To get started with Jersey, include the `spring-boot-starter-jersey` as a dependency and then you need one javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.glassfish.jersey.server.ResourceConfig[] in which you register all the endpoints, as shown in the following example:
include-code::MyJerseyConfig[]
WARNING: Jersey's support for scanning executable archives is rather limited.
For example, it cannot scan for endpoints in a package found in a xref:how-to:deployment/installing.adoc[fully executable jar file] or in `WEB-INF/classes` when running an executable war file.
To avoid this limitation, the `packages` method should not be used, and endpoints should be registered individually by using the `register` method, as shown in the preceding example.
For more advanced customizations, you can also register an arbitrary number of beans that implement javadoc:org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer[].
All the registered endpoints should be a javadoc:org.springframework.stereotype.Component[format=annotation] with HTTP resource annotations (`@GET` and others), as shown in the following example:
include-code::MyEndpoint[]
Since the javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation] is a Spring javadoc:org.springframework.stereotype.Component[format=annotation], its lifecycle is managed by Spring and you can use the javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation] annotation to inject dependencies and use the javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] annotation to inject external configuration.
By default, the Jersey servlet is registered and mapped to `/*`.
You can change the mapping by adding javadoc:jakarta.ws.rs.ApplicationPath[format=annotation] to your javadoc:org.glassfish.jersey.server.ResourceConfig[].
By default, Jersey is set up as a servlet in a javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[] named `jerseyServletRegistration`.
By default, the servlet is initialized lazily, but you can customize that behavior by setting `spring.jersey.servlet.load-on-startup`.
You can disable or override that bean by creating one of your own with the same name.
You can also use a filter instead of a servlet by setting `spring.jersey.type=filter` (in which case, the javadoc:org.springframework.context.annotation.Bean[format=annotation] to replace or override is `jerseyFilterRegistration`).
The filter has an javadoc:org.springframework.core.annotation.Order[format=annotation], which you can set with `spring.jersey.filter.order`.
When using Jersey as a filter, a servlet that will handle any requests that are not intercepted by Jersey must be present.
If your application does not contain such a servlet, you may want to enable the default servlet by setting configprop:server.servlet.register-default-servlet[] to `true`.
Both the servlet and the filter registrations can be given init parameters by using `spring.jersey.init.*` to specify a map of properties.
[[web.servlet.embedded-container]]
== Embedded Servlet Container Support

View File

@ -1,21 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.howto.jersey.alongsideanotherwebframework;
class Endpoint {
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.howto.jersey.alongsideanotherwebframework;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletProperties;
import org.springframework.stereotype.Component;
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
property(ServletProperties.FILTER_FORWARD_ON_404, true);
}
}

View File

@ -1,21 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.howto.jersey.springsecurity;
class Endpoint {
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.howto.jersey.springsecurity;
import java.util.Collections;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
@Component
public class JerseySetStatusOverSendErrorConfig extends ResourceConfig {
public JerseySetStatusOverSendErrorConfig() {
register(Endpoint.class);
setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true));
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.web.servlet.jersey;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.springframework.stereotype.Component;
@Component
@Path("/hello")
public class MyEndpoint {
@GET
public String message() {
return "Hello";
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.web.servlet.jersey;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
@Component
public class MyJerseyConfig extends ResourceConfig {
public MyJerseyConfig() {
register(MyEndpoint.class);
}
}

View File

@ -28,7 +28,6 @@ dependencies {
testImplementation(project(":module:spring-boot-health"))
testImplementation(project(":module:spring-boot-http-converter"))
testImplementation(project(":module:spring-boot-jackson"))
testImplementation(project(":module:spring-boot-jersey"))
testImplementation(project(":module:spring-boot-micrometer-metrics"))
testImplementation(project(":module:spring-boot-reactor-netty"))
testImplementation(project(":core:spring-boot-test"))
@ -37,7 +36,6 @@ dependencies {
testImplementation(project(":module:spring-boot-web-server"))
testImplementation(project(":module:spring-boot-webflux"))
testImplementation(project(":module:spring-boot-webmvc"))
testImplementation(testFixtures(project(":module:spring-boot-jersey")))
testImplementation(testFixtures(project(":module:spring-boot-webflux")))
testImplementation(testFixtures(project(":module:spring-boot-webmvc")))
testImplementation("io.micrometer:micrometer-registry-prometheus")

View File

@ -1,172 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.jersey;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.ws.rs.ext.ContextResolver;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.servlet.ServletContainer;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.jersey.actuate.endpoint.web.JerseyEndpointResourceFactory;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Integration tests for web endpoints exposed using Jersey.
*
* @author Andy Wilkinson
* @see JerseyEndpointResourceFactory
*/
class JerseyWebEndpointIntegrationTests
extends AbstractWebEndpointIntegrationTests<AnnotationConfigServletWebServerApplicationContext> {
JerseyWebEndpointIntegrationTests() {
super(JerseyWebEndpointIntegrationTests::createApplicationContext,
JerseyWebEndpointIntegrationTests::applyAuthenticatedConfiguration);
}
private static AnnotationConfigServletWebServerApplicationContext createApplicationContext() {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
context.register(JerseyConfiguration.class);
return context;
}
private static void applyAuthenticatedConfiguration(AnnotationConfigServletWebServerApplicationContext context) {
context.register(AuthenticatedConfiguration.class);
}
@Override
protected int getPort(AnnotationConfigServletWebServerApplicationContext context) {
return context.getWebServer().getPort();
}
@Override
protected void validateErrorBody(WebTestClient.BodyContentSpec body, HttpStatus status, String path,
String message) {
// Jersey doesn't support the general error page handling
}
@Override
@Test
@Disabled("Jersey does not distinguish between /example and /example/")
protected void operationWithTrailingSlashShouldNotMatch() {
}
@Configuration(proxyBeanMethods = false)
static class JerseyConfiguration {
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
ServletRegistrationBean<ServletContainer> servletContainer(ResourceConfig resourceConfig) {
return new ServletRegistrationBean<>(new ServletContainer(resourceConfig), "/*");
}
@Bean
ResourceConfig resourceConfig(Environment environment, WebEndpointDiscoverer endpointDiscoverer,
EndpointMediaTypes endpointMediaTypes) {
ResourceConfig resourceConfig = new ResourceConfig();
String endpointPath = environment.getProperty("endpointPath");
Collection<Resource> resources = new JerseyEndpointResourceFactory().createEndpointResources(
new EndpointMapping(endpointPath), endpointDiscoverer.getEndpoints(), endpointMediaTypes,
new EndpointLinksResolver(endpointDiscoverer.getEndpoints()), StringUtils.hasText(endpointPath));
resourceConfig.registerResources(new HashSet<>(resources));
resourceConfig.register(JacksonFeature.class);
resourceConfig.register(new ObjectMapperContextResolver(new ObjectMapper()), ContextResolver.class);
return resourceConfig;
}
}
@Configuration(proxyBeanMethods = false)
static class AuthenticatedConfiguration {
@Bean
Filter securityFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(new UsernamePasswordAuthenticationToken("Alice", "secret",
Arrays.asList(new SimpleGrantedAuthority("ROLE_ACTUATOR"))));
SecurityContextHolder.setContext(context);
try {
filterChain.doFilter(new SecurityContextHolderAwareRequestWrapper(request, "ROLE_"), response);
}
finally {
SecurityContextHolder.clearContext();
}
}
};
}
}
private static final class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
private ObjectMapperContextResolver(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public ObjectMapper getContext(Class<?> type) {
return this.objectMapper;
}
}
}

View File

@ -46,15 +46,10 @@ public @interface WebEndpointTest {
* The infrastructure against which the test should run.
* @return the infrastructure to run the tests against
*/
Infrastructure[] infrastructure() default { Infrastructure.JERSEY, Infrastructure.MVC, Infrastructure.WEBFLUX };
Infrastructure[] infrastructure() default { Infrastructure.MVC, Infrastructure.WEBFLUX };
enum Infrastructure {
/**
* Actuator running on the Jersey-based infrastructure.
*/
JERSEY("Jersey"),
/**
* Actuator running on the WebMVC-based infrastructure.
*/

View File

@ -77,8 +77,8 @@ class WebEndpointTestInvocationContextProvider implements TestTemplateInvocation
.findFirst()
.ifPresent((provider) -> this.infrastructures.put(infrastructure,
provider.getInfrastructureConfiguration(infrastructure))));
this.contextFactories = Map.of(Infrastructure.JERSEY, this::createJerseyContext, Infrastructure.MVC,
this::createWebMvcContext, Infrastructure.WEBFLUX, this::createWebFluxContext);
this.contextFactories = Map.of(Infrastructure.MVC, this::createWebMvcContext, Infrastructure.WEBFLUX,
this::createWebFluxContext);
}
@Override
@ -100,14 +100,6 @@ class WebEndpointTestInvocationContextProvider implements TestTemplateInvocation
return infrastructure.createInvocationContext(this.contextFactories.get(infrastructure));
}
private ConfigurableApplicationContext createJerseyContext(List<Class<?>> classes) {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
classes.addAll(getEndpointInfrastructureConfiguration(Infrastructure.JERSEY));
context.register(ClassUtils.toClassArray(classes));
context.refresh();
return context;
}
private ConfigurableApplicationContext createWebMvcContext(List<Class<?>> classes) {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
classes.addAll(getEndpointInfrastructureConfiguration(Infrastructure.MVC));

View File

@ -136,9 +136,6 @@ dependencies {
api(project(":module:spring-boot-jdbc")) {
transitive = false
}
api(project(":module:spring-boot-jersey")) {
transitive = false
}
api(project(":module:spring-boot-jetty")) {
transitive = false
}

View File

@ -63,7 +63,6 @@ dependencies {
testImplementation(project(":core:spring-boot-test"))
testImplementation(project(":test-support:spring-boot-test-support"))
testImplementation(testFixtures(project(":core:spring-boot-autoconfigure")))
testImplementation(testFixtures(project(":module:spring-boot-jersey")))
testImplementation(testFixtures(project(":module:spring-boot-webmvc")))
testImplementation(testFixtures(project(":module:spring-boot-webflux")))

View File

@ -41,7 +41,6 @@ dependencies {
testImplementation(project(":module:spring-boot-flyway"))
testImplementation(project(":module:spring-boot-rsocket"))
testImplementation(project(":test-support:spring-boot-test-support"))
testImplementation(testFixtures(project(":module:spring-boot-jersey")))
testImplementation(testFixtures(project(":module:spring-boot-webflux")))
testImplementation(testFixtures(project(":module:spring-boot-webmvc")))
testImplementation("org.springframework:spring-web")

View File

@ -1,63 +0,0 @@
/*
* Copyright 2012-present 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.
*/
plugins {
id "java-library"
id "java-test-fixtures"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.deployed"
id "org.springframework.boot.optional-dependencies"
}
description = "Spring Boot Jersey"
dependencies {
api(project(":module:spring-boot-servlet"))
api("org.glassfish.jersey.containers:jersey-container-servlet-core")
api("org.glassfish.jersey.containers:jersey-container-servlet")
api("org.glassfish.jersey.core:jersey-server")
api("org.glassfish.jersey.ext:jersey-spring6")
api("org.glassfish.jersey.media:jersey-media-json-jackson")
compileOnly("jakarta.servlet:jakarta.servlet-api")
compileOnly("com.google.code.findbugs:jsr305")
implementation("org.springframework:spring-web")
optional(project(":core:spring-boot-autoconfigure"))
optional(project(":module:spring-boot-actuator-autoconfigure"))
optional(project(":module:spring-boot-health"))
optional(project(":module:spring-boot-jackson"))
optional(project(":module:spring-boot-micrometer-metrics"))
optional(project(":module:spring-boot-micrometer-observation"))
optional("io.projectreactor:reactor-core")
optional("org.glassfish.jersey.ext:jersey-micrometer")
testFixturesApi(testFixtures(project(":module:spring-boot-actuator")))
testFixturesImplementation(project(":module:spring-boot-tomcat"))
testImplementation(project(":core:spring-boot-test"))
testImplementation(project(":module:spring-boot-restclient"))
testImplementation(project(":module:spring-boot-tomcat"))
testImplementation(project(":test-support:spring-boot-test-support"))
testImplementation(project(":module:spring-boot-web-server-test"))
testImplementation(testFixtures(project(":module:spring-boot-actuator-autoconfigure")))
testImplementation("jakarta.servlet:jakarta.servlet-api")
testImplementation("org.springframework:spring-webflux")
testRuntimeOnly("ch.qos.logback:logback-classic")
}

View File

@ -1,362 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.actuate.endpoint.web;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import jakarta.ws.rs.HttpMethod;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import org.glassfish.jersey.process.Inflector;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.Resource.Builder;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.InvocationContext;
import org.springframework.boot.actuate.endpoint.OperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* A factory for creating Jersey {@link Resource Resources} for {@link WebOperation web
* endpoint operations}.
*
* @author Andy Wilkinson
* @author Phillip Webb
* @since 4.0.0
*/
public class JerseyEndpointResourceFactory {
/**
* Creates {@link Resource Resources} for the operations of the given
* {@code webEndpoints}.
* @param endpointMapping the base mapping for all endpoints
* @param endpoints the web endpoints
* @param endpointMediaTypes media types consumed and produced by the endpoints
* @param linksResolver resolver for determining links to available endpoints
* @param shouldRegisterLinks should register links
* @return the resources for the operations
*/
public Collection<Resource> createEndpointResources(EndpointMapping endpointMapping,
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
EndpointLinksResolver linksResolver, boolean shouldRegisterLinks) {
List<Resource> resources = new ArrayList<>();
endpoints.stream()
.flatMap((endpoint) -> endpoint.getOperations().stream())
.map((operation) -> createResource(endpointMapping, operation))
.forEach(resources::add);
if (shouldRegisterLinks) {
Resource resource = createEndpointLinksResource(endpointMapping.getPath(), endpointMediaTypes,
linksResolver);
resources.add(resource);
}
return resources;
}
protected Resource createResource(EndpointMapping endpointMapping, WebOperation operation) {
WebOperationRequestPredicate requestPredicate = operation.getRequestPredicate();
String path = requestPredicate.getPath();
String matchAllRemainingPathSegmentsVariable = requestPredicate.getMatchAllRemainingPathSegmentsVariable();
if (matchAllRemainingPathSegmentsVariable != null) {
path = path.replace("{*" + matchAllRemainingPathSegmentsVariable + "}",
"{" + matchAllRemainingPathSegmentsVariable + ": .*}");
}
return getResource(endpointMapping, operation, requestPredicate, path, null, null);
}
protected Resource getResource(EndpointMapping endpointMapping, WebOperation operation,
WebOperationRequestPredicate requestPredicate, String path, @Nullable WebServerNamespace serverNamespace,
@Nullable JerseyRemainingPathSegmentProvider remainingPathSegmentProvider) {
Builder resourceBuilder = Resource.builder()
.path(endpointMapping.getPath())
.path(endpointMapping.createSubPath(path));
resourceBuilder.addMethod(requestPredicate.getHttpMethod().name())
.consumes(StringUtils.toStringArray(requestPredicate.getConsumes()))
.produces(StringUtils.toStringArray(requestPredicate.getProduces()))
.handledBy(new OperationInflector(operation, !requestPredicate.getConsumes().isEmpty(), serverNamespace,
remainingPathSegmentProvider));
return resourceBuilder.build();
}
private Resource createEndpointLinksResource(String endpointPath, EndpointMediaTypes endpointMediaTypes,
EndpointLinksResolver linksResolver) {
Builder resourceBuilder = Resource.builder().path(endpointPath);
resourceBuilder.addMethod("GET")
.produces(StringUtils.toStringArray(endpointMediaTypes.getProduced()))
.handledBy(new EndpointLinksInflector(linksResolver));
return resourceBuilder.build();
}
/**
* {@link Inflector} to invoke the {@link WebOperation}.
*/
private static final class OperationInflector implements Inflector<ContainerRequestContext, Object> {
private static final String PATH_SEPARATOR = AntPathMatcher.DEFAULT_PATH_SEPARATOR;
private static final List<Function<@Nullable Object, @Nullable Object>> BODY_CONVERTERS;
static {
List<Function<@Nullable Object, @Nullable Object>> converters = new ArrayList<>();
converters.add(new ResourceBodyConverter());
if (ClassUtils.isPresent("reactor.core.publisher.Mono", OperationInflector.class.getClassLoader())) {
converters.add(new FluxBodyConverter());
converters.add(new MonoBodyConverter());
}
BODY_CONVERTERS = Collections.unmodifiableList(converters);
}
private final WebOperation operation;
private final boolean readBody;
private final @Nullable WebServerNamespace serverNamespace;
private final @Nullable JerseyRemainingPathSegmentProvider remainingPathSegmentProvider;
private OperationInflector(WebOperation operation, boolean readBody,
@Nullable WebServerNamespace serverNamespace,
@Nullable JerseyRemainingPathSegmentProvider remainingPathSegments) {
this.operation = operation;
this.readBody = readBody;
this.serverNamespace = serverNamespace;
this.remainingPathSegmentProvider = remainingPathSegments;
}
@Override
public Response apply(ContainerRequestContext data) {
Map<String, Object> arguments = new HashMap<>();
if (this.readBody) {
arguments.putAll(extractBodyArguments(data));
}
arguments.putAll(extractPathParameters(data));
arguments.putAll(extractQueryParameters(data));
try {
JerseySecurityContext securityContext = new JerseySecurityContext(data.getSecurityContext());
OperationArgumentResolver serverNamespaceArgumentResolver = OperationArgumentResolver
.of(WebServerNamespace.class, () -> this.serverNamespace);
InvocationContext invocationContext = new InvocationContext(securityContext, arguments,
serverNamespaceArgumentResolver,
new ProducibleOperationArgumentResolver(() -> data.getHeaders().get("Accept")));
Object response = this.operation.invoke(invocationContext);
return convertToJaxRsResponse(response, data.getRequest().getMethod());
}
catch (InvalidEndpointRequestException ex) {
return Response.status(Status.BAD_REQUEST).build();
}
}
@SuppressWarnings("unchecked")
private Map<String, String> extractBodyArguments(ContainerRequestContext data) {
Map<String, String> entity = ((ContainerRequest) data).readEntity(Map.class,
new ParameterizedTypeReference<Map<String, String>>() {
}.getType());
return (entity != null) ? entity : Collections.emptyMap();
}
private Map<String, Object> extractPathParameters(ContainerRequestContext requestContext) {
Map<String, Object> pathParameters = extract(requestContext.getUriInfo().getPathParameters());
String matchAllRemainingPathSegmentsVariable = this.operation.getRequestPredicate()
.getMatchAllRemainingPathSegmentsVariable();
if (matchAllRemainingPathSegmentsVariable != null) {
String remainingPathSegments = getRemainingPathSegments(requestContext, pathParameters,
matchAllRemainingPathSegmentsVariable);
pathParameters.put(matchAllRemainingPathSegmentsVariable, tokenizePathSegments(remainingPathSegments));
}
return pathParameters;
}
private @Nullable String getRemainingPathSegments(ContainerRequestContext requestContext,
Map<String, Object> pathParameters, String matchAllRemainingPathSegmentsVariable) {
if (this.remainingPathSegmentProvider != null) {
return this.remainingPathSegmentProvider.get(requestContext, matchAllRemainingPathSegmentsVariable);
}
return (String) pathParameters.get(matchAllRemainingPathSegmentsVariable);
}
private String[] tokenizePathSegments(@Nullable String path) {
String[] segments = StringUtils.tokenizeToStringArray(path, PATH_SEPARATOR, false, true);
for (int i = 0; i < segments.length; i++) {
if (segments[i].contains("%")) {
segments[i] = StringUtils.uriDecode(segments[i], StandardCharsets.UTF_8);
}
}
return segments;
}
private Map<String, Object> extractQueryParameters(ContainerRequestContext requestContext) {
return extract(requestContext.getUriInfo().getQueryParameters());
}
private Map<String, Object> extract(MultivaluedMap<String, String> multivaluedMap) {
Map<String, Object> result = new HashMap<>();
multivaluedMap.forEach((name, values) -> {
if (!CollectionUtils.isEmpty(values)) {
result.put(name, (values.size() != 1) ? values : values.get(0));
}
});
return result;
}
private Response convertToJaxRsResponse(@Nullable Object response, String httpMethod) {
if (response == null) {
boolean isGet = HttpMethod.GET.equals(httpMethod);
Status status = isGet ? Status.NOT_FOUND : Status.NO_CONTENT;
return Response.status(status).build();
}
if (!(response instanceof WebEndpointResponse<?> webEndpointResponse)) {
return Response.status(Status.OK).entity(convertIfNecessary(response)).build();
}
return Response.status(webEndpointResponse.getStatus())
.header("Content-Type", webEndpointResponse.getContentType())
.entity(convertIfNecessary(webEndpointResponse.getBody()))
.build();
}
private @Nullable Object convertIfNecessary(@Nullable Object body) {
for (Function<@Nullable Object, @Nullable Object> converter : BODY_CONVERTERS) {
body = converter.apply(body);
}
return body;
}
}
/**
* Body converter from {@link org.springframework.core.io.Resource} to
* {@link InputStream}.
*/
private static final class ResourceBodyConverter implements Function<Object, Object> {
@Override
public Object apply(Object body) {
if (body instanceof org.springframework.core.io.Resource) {
try {
return ((org.springframework.core.io.Resource) body).getInputStream();
}
catch (IOException ex) {
throw new IllegalStateException();
}
}
return body;
}
}
/**
* Body converter from {@link Mono} to {@link Mono#block()}.
*/
private static final class MonoBodyConverter implements Function<@Nullable Object, @Nullable Object> {
@Override
public @Nullable Object apply(@Nullable Object body) {
if (body instanceof Mono) {
return ((Mono<?>) body).block();
}
return body;
}
}
/**
* Body converter from {@link Flux} to {@link Flux#collectList Mono&lt;List&gt;}.
*/
private static final class FluxBodyConverter implements Function<@Nullable Object, @Nullable Object> {
@Override
public @Nullable Object apply(@Nullable Object body) {
if (body instanceof Flux) {
return ((Flux<?>) body).collectList();
}
return body;
}
}
/**
* {@link Inflector} to for endpoint links.
*/
private static final class EndpointLinksInflector implements Inflector<ContainerRequestContext, Response> {
private final EndpointLinksResolver linksResolver;
private EndpointLinksInflector(EndpointLinksResolver linksResolver) {
this.linksResolver = linksResolver;
}
@Override
public Response apply(ContainerRequestContext request) {
Map<String, Link> links = this.linksResolver
.resolveLinks(request.getUriInfo().getAbsolutePath().toString());
Map<String, Map<String, Link>> entity = OperationResponseBody.of(Collections.singletonMap("_links", links));
return Response.ok(entity).build();
}
}
private static final class JerseySecurityContext implements SecurityContext {
private final jakarta.ws.rs.core.SecurityContext securityContext;
private JerseySecurityContext(jakarta.ws.rs.core.SecurityContext securityContext) {
this.securityContext = securityContext;
}
@Override
public Principal getPrincipal() {
return this.securityContext.getUserPrincipal();
}
@Override
public boolean isUserInRole(String role) {
return this.securityContext.isUserInRole(role);
}
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.actuate.endpoint.web;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.glassfish.jersey.server.model.Resource;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
import org.springframework.boot.actuate.health.HealthEndpointGroup;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
/**
* A factory for creating Jersey {@link Resource Resources} for health groups with
* additional path.
*
* @author Madhura Bhave
* @since 2.6.0
*/
public final class JerseyHealthEndpointAdditionalPathResourceFactory {
private final JerseyEndpointResourceFactory delegate = new JerseyEndpointResourceFactory();
private final Set<HealthEndpointGroup> groups;
private final WebServerNamespace serverNamespace;
public JerseyHealthEndpointAdditionalPathResourceFactory(WebServerNamespace serverNamespace,
HealthEndpointGroups groups) {
this.serverNamespace = serverNamespace;
this.groups = groups.getAllWithAdditionalPath(serverNamespace);
}
public Collection<Resource> createEndpointResources(EndpointMapping endpointMapping,
Collection<ExposableWebEndpoint> endpoints) {
return endpoints.stream()
.flatMap((endpoint) -> endpoint.getOperations().stream())
.flatMap((operation) -> createResources(endpointMapping, operation))
.toList();
}
private Stream<Resource> createResources(EndpointMapping endpointMapping, WebOperation operation) {
WebOperationRequestPredicate requestPredicate = operation.getRequestPredicate();
String matchAllRemainingPathSegmentsVariable = requestPredicate.getMatchAllRemainingPathSegmentsVariable();
if (matchAllRemainingPathSegmentsVariable != null) {
List<Resource> resources = new ArrayList<>();
for (HealthEndpointGroup group : this.groups) {
AdditionalHealthEndpointPath additionalPath = group.getAdditionalPath();
if (additionalPath != null) {
resources.add(this.delegate.getResource(endpointMapping, operation, requestPredicate,
additionalPath.getValue(), this.serverNamespace,
(data, pathSegmentsVariable) -> data.getUriInfo().getPath()));
}
}
return resources.stream();
}
return Stream.empty();
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.actuate.endpoint.web;
import jakarta.ws.rs.container.ContainerRequestContext;
/**
* Strategy interface used to provide the remaining path segments for a Jersey actuator
* endpoint.
*
* @author Madhura Bhave
*/
interface JerseyRemainingPathSegmentProvider {
String get(ContainerRequestContext requestContext, String matchAllRemainingPathSegmentsVariable);
}

View File

@ -1,23 +0,0 @@
/*
* Copyright 2012-present 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.
*/
/**
* Jersey support for actuator endpoints.
*/
@NullMarked
package org.springframework.boot.jersey.actuate.endpoint.web;
import org.jspecify.annotations.NullMarked;

View File

@ -1,62 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import jakarta.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.util.StringUtils;
/**
* Default implementation of {@link JerseyApplicationPath} that derives the path from
* {@link JerseyProperties} or the {@code @ApplicationPath} annotation.
*
* @author Madhura Bhave
* @since 4.0.0
*/
public class DefaultJerseyApplicationPath implements JerseyApplicationPath {
private final @Nullable String applicationPath;
private final ResourceConfig config;
public DefaultJerseyApplicationPath(@Nullable String applicationPath, ResourceConfig config) {
this.applicationPath = applicationPath;
this.config = config;
}
@Override
public String getPath() {
return resolveApplicationPath();
}
private String resolveApplicationPath() {
if (StringUtils.hasLength(this.applicationPath)) {
return this.applicationPath;
}
// Jersey doesn't like to be the default servlet, so map to /* as a fallback
return MergedAnnotations.from(this.config.getApplication().getClass(), SearchStrategy.TYPE_HIERARCHY)
.get(ApplicationPath.class)
.getValue(MergedAnnotation.VALUE, String.class)
.orElse("/*");
}
}

View File

@ -1,90 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
/**
* Interface that can be used by auto-configurations that need path details Jersey's
* application path that serves as the base URI for the application.
*
* @author Madhura Bhave
* @since 4.0.0
*/
@FunctionalInterface
public interface JerseyApplicationPath {
/**
* Returns the configured path of the application.
* @return the configured path
*/
String getPath();
/**
* Return a form of the given path that's relative to the Jersey application path.
* @param path the path to make relative
* @return the relative path
*/
default String getRelativePath(String path) {
String prefix = getPrefix();
if (!path.startsWith("/")) {
path = "/" + path;
}
return prefix + path;
}
/**
* Return a cleaned up version of the path that can be used as a prefix for URLs. The
* resulting path will have path will not have a trailing slash.
* @return the prefix
* @see #getRelativePath(String)
*/
default String getPrefix() {
String result = getPath();
int index = result.indexOf('*');
if (index != -1) {
result = result.substring(0, index);
}
if (result.endsWith("/")) {
result = result.substring(0, result.length() - 1);
}
return result;
}
/**
* Return a URL mapping pattern that can be used with a
* {@link ServletRegistrationBean} to map Jersey's servlet.
* @return the path as a servlet URL mapping
*/
default String getUrlMapping() {
String path = getPath();
if (!path.startsWith("/")) {
path = "/" + path;
}
if (path.equals("/")) {
return "/*";
}
if (path.contains("*")) {
return path;
}
if (path.endsWith("/")) {
return path + "*";
}
return path + "/*";
}
}

View File

@ -1,232 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.util.Collections;
import java.util.EnumSet;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;
import jakarta.ws.rs.ext.ContextResolver;
import jakarta.xml.bind.annotation.XmlElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spring.SpringComponentProvider;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.DynamicRegistrationBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.ClassUtils;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.filter.RequestContextFilter;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Jersey.
*
* @author Dave Syer
* @author Andy Wilkinson
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 4.0.0
*/
@AutoConfiguration(afterName = "org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration")
@ConditionalOnClass({ SpringComponentProvider.class, ServletRegistration.class })
@ConditionalOnBean(type = "org.glassfish.jersey.server.ResourceConfig")
@ConditionalOnWebApplication(type = Type.SERVLET)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@EnableConfigurationProperties(JerseyProperties.class)
public final class JerseyAutoConfiguration implements ServletContextAware {
private static final Log logger = LogFactory.getLog(JerseyAutoConfiguration.class);
private final JerseyProperties jersey;
private final ResourceConfig config;
JerseyAutoConfiguration(JerseyProperties jersey, ResourceConfig config,
ObjectProvider<ResourceConfigCustomizer> customizers) {
this.jersey = jersey;
this.config = config;
customizers.orderedStream().forEach((customizer) -> customizer.customize(this.config));
}
@Bean
@ConditionalOnMissingFilterBean
FilterRegistrationBean<RequestContextFilter> requestContextFilter() {
FilterRegistrationBean<RequestContextFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new RequestContextFilter());
registration.setOrder(this.jersey.getFilter().getOrder() - 1);
registration.setName("requestContextFilter");
return registration;
}
@Bean
@ConditionalOnMissingBean
JerseyApplicationPath jerseyApplicationPath() {
return new DefaultJerseyApplicationPath(this.jersey.getApplicationPath(), this.config);
}
@Bean
@ConditionalOnMissingBean(name = "jerseyFilterRegistration")
@ConditionalOnProperty(name = "spring.jersey.type", havingValue = "filter")
FilterRegistrationBean<ServletContainer> jerseyFilterRegistration(JerseyApplicationPath applicationPath) {
FilterRegistrationBean<ServletContainer> registration = new FilterRegistrationBean<>();
registration.setFilter(new ServletContainer(this.config));
registration.setUrlPatterns(Collections.singletonList(applicationPath.getUrlMapping()));
registration.setOrder(this.jersey.getFilter().getOrder());
registration.addInitParameter(ServletProperties.FILTER_CONTEXT_PATH, stripPattern(applicationPath.getPath()));
addInitParameters(registration);
registration.setName("jerseyFilter");
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
private String stripPattern(String path) {
if (path.endsWith("/*")) {
path = path.substring(0, path.lastIndexOf("/*"));
}
return path;
}
@Bean
@ConditionalOnMissingBean(name = "jerseyServletRegistration")
@ConditionalOnProperty(name = "spring.jersey.type", havingValue = "servlet", matchIfMissing = true)
ServletRegistrationBean<ServletContainer> jerseyServletRegistration(JerseyApplicationPath applicationPath) {
ServletRegistrationBean<ServletContainer> registration = new ServletRegistrationBean<>(
new ServletContainer(this.config), applicationPath.getUrlMapping());
addInitParameters(registration);
registration.setName(getServletRegistrationName());
registration.setLoadOnStartup(this.jersey.getServlet().getLoadOnStartup());
registration.setIgnoreRegistrationFailure(true);
return registration;
}
private String getServletRegistrationName() {
return ClassUtils.getUserClass(this.config.getClass()).getName();
}
private void addInitParameters(DynamicRegistrationBean<?> registration) {
this.jersey.getInit().forEach(registration::addInitParameter);
}
@Override
public void setServletContext(ServletContext servletContext) {
String servletRegistrationName = getServletRegistrationName();
ServletRegistration registration = servletContext.getServletRegistration(servletRegistrationName);
if (registration != null) {
if (logger.isInfoEnabled()) {
logger.info("Configuring existing registration for Jersey servlet '" + servletRegistrationName + "'");
}
registration.setInitParameters(this.jersey.getInit());
}
}
@Order(Ordered.HIGHEST_PRECEDENCE)
public static final class JerseyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
if (ClassUtils.isPresent("org.glassfish.jersey.server.spring.SpringWebApplicationInitializer",
getClass().getClassLoader())) {
// We need to switch *off* the Jersey WebApplicationInitializer because it
// will try and register a ContextLoaderListener which we don't need
servletContext.setInitParameter("contextConfigLocation", "<NONE>");
}
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(JacksonFeature.class)
@ConditionalOnSingleCandidate(ObjectMapper.class)
static class JacksonResourceConfigCustomizer {
@Bean
ResourceConfigCustomizer jacksonResourceConfigCustomizer(ObjectMapper objectMapper) {
return (ResourceConfig config) -> {
config.register(JacksonFeature.class);
config.register(new ObjectMapperContextResolver(objectMapper), ContextResolver.class);
};
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JakartaXmlBindAnnotationIntrospector.class, XmlElement.class })
static class JaxbObjectMapperCustomizer {
@Autowired
void addJaxbAnnotationIntrospector(ObjectMapper objectMapper) {
JakartaXmlBindAnnotationIntrospector jaxbAnnotationIntrospector = new JakartaXmlBindAnnotationIntrospector(
objectMapper.getTypeFactory());
objectMapper.setAnnotationIntrospectors(
createPair(objectMapper.getSerializationConfig(), jaxbAnnotationIntrospector),
createPair(objectMapper.getDeserializationConfig(), jaxbAnnotationIntrospector));
}
private AnnotationIntrospector createPair(MapperConfig<?> config,
JakartaXmlBindAnnotationIntrospector jaxbAnnotationIntrospector) {
return AnnotationIntrospector.pair(config.getAnnotationIntrospector(), jaxbAnnotationIntrospector);
}
}
private static final class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
private ObjectMapperContextResolver(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public ObjectMapper getContext(Class<?> type) {
return this.objectMapper;
}
}
}
}

View File

@ -1,129 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.util.HashMap;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* {@link ConfigurationProperties @ConfigurationProperties} for Jersey.
*
* @author Dave Syer
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 4.0.0
*/
@ConfigurationProperties("spring.jersey")
public class JerseyProperties {
/**
* Jersey integration type.
*/
private Type type = Type.SERVLET;
/**
* Init parameters to pass to Jersey through the servlet or filter.
*/
private Map<String, String> init = new HashMap<>();
private final Filter filter = new Filter();
private final Servlet servlet = new Servlet();
/**
* Path that serves as the base URI for the application. If specified, overrides the
* value of "@ApplicationPath".
*/
private @Nullable String applicationPath;
public Filter getFilter() {
return this.filter;
}
public Servlet getServlet() {
return this.servlet;
}
public Type getType() {
return this.type;
}
public void setType(Type type) {
this.type = type;
}
public Map<String, String> getInit() {
return this.init;
}
public void setInit(Map<String, String> init) {
this.init = init;
}
public @Nullable String getApplicationPath() {
return this.applicationPath;
}
public void setApplicationPath(@Nullable String applicationPath) {
this.applicationPath = applicationPath;
}
public enum Type {
SERVLET, FILTER
}
public static class Filter {
/**
* Jersey filter chain order.
*/
private int order;
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
}
public static class Servlet {
/**
* Load on startup priority of the Jersey servlet.
*/
private int loadOnStartup = -1;
public int getLoadOnStartup() {
return this.loadOnStartup;
}
public void setLoadOnStartup(int loadOnStartup) {
this.loadOnStartup = loadOnStartup;
}
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import org.glassfish.jersey.server.ResourceConfig;
/**
* Callback interface that can be implemented by beans wishing to customize Jersey's
* {@link ResourceConfig} before it is used.
*
* @author Eddú Meléndez
* @since 4.0.0
*/
@FunctionalInterface
public interface ResourceConfigCustomizer {
/**
* Customize the resource config.
* @param config the {@link ResourceConfig} to customize
*/
void customize(ResourceConfig config);
}

View File

@ -1,148 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.servlet.ServletContainer;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jersey.actuate.endpoint.web.JerseyHealthEndpointAdditionalPathResourceFactory;
import org.springframework.boot.jersey.autoconfigure.DefaultJerseyApplicationPath;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.boot.jersey.autoconfigure.JerseyProperties;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Auto-Configuration for {@link HealthEndpoint} Jersey extension.
*
* @author Phillip Webb
* @author Madhura Bhave
* @since 4.0.0
* @see HealthEndpointAutoConfiguration
*/
@AutoConfiguration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnBean(HealthEndpoint.class)
@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
public final class HealthEndpointJerseyExtensionAutoConfiguration {
@Bean
JerseyAdditionalHealthEndpointPathsResourcesRegistrar jerseyAdditionalHealthEndpointPathsResourcesRegistrar(
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups healthEndpointGroups) {
ExposableWebEndpoint health = getHealthEndpoint(webEndpointsSupplier);
return new JerseyAdditionalHealthEndpointPathsResourcesRegistrar(health, healthEndpointGroups);
}
private static @Nullable ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
return webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.orElse(null);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ResourceConfig.class)
@EnableConfigurationProperties(JerseyProperties.class)
static class JerseyInfrastructureConfiguration {
@Bean
@ConditionalOnMissingBean
JerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) {
return new DefaultJerseyApplicationPath(properties.getApplicationPath(), config);
}
@Bean
ResourceConfig resourceConfig(ObjectProvider<ResourceConfigCustomizer> resourceConfigCustomizers) {
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfigCustomizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));
return resourceConfig;
}
@Bean
ServletRegistrationBean<ServletContainer> jerseyServletRegistration(JerseyApplicationPath jerseyApplicationPath,
ResourceConfig resourceConfig) {
return new ServletRegistrationBean<>(new ServletContainer(resourceConfig),
jerseyApplicationPath.getUrlMapping());
}
}
static class JerseyAdditionalHealthEndpointPathsResourcesRegistrar implements ResourceConfigCustomizer {
private final @Nullable ExposableWebEndpoint endpoint;
private final HealthEndpointGroups groups;
JerseyAdditionalHealthEndpointPathsResourcesRegistrar(@Nullable ExposableWebEndpoint endpoint,
HealthEndpointGroups groups) {
this.endpoint = endpoint;
this.groups = groups;
}
@Override
public void customize(ResourceConfig config) {
register(config);
}
private void register(ResourceConfig config) {
EndpointMapping mapping = new EndpointMapping("");
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
WebServerNamespace.SERVER, this.groups);
Collection<Resource> endpointResources = resourceFactory
.createEndpointResources(mapping,
(this.endpoint != null) ? Collections.singletonList(this.endpoint) : Collections.emptyList())
.stream()
.filter(Objects::nonNull)
.toList();
register(endpointResources, config);
}
private void register(Collection<Resource> resources, ResourceConfig config) {
config.registerResources(new HashSet<>(resources));
}
}
}

View File

@ -1,23 +0,0 @@
/*
* Copyright 2012-present 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.
*/
/**
* Auto-configuration for Jersey actuator web endpoint support.
*/
@NullMarked
package org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;
import org.jspecify.annotations.NullMarked;

View File

@ -1,59 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
/**
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jersey
* infrastructure when a separate management context with a web server running on a
* different port is required.
*
* @author Madhura Bhave
* @since 4.0.0
*/
@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)
@Import(JerseyManagementContextConfiguration.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ JerseyApplicationPath.class, ResourceConfig.class })
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
public class JerseyChildManagementContextConfiguration {
@Bean
public JerseyApplicationPath jerseyApplicationPath() {
return () -> "/";
}
@Bean
ResourceConfig resourceConfig(ObjectProvider<ManagementContextResourceConfigCustomizer> customizers) {
ResourceConfig resourceConfig = new ResourceConfig();
customizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));
return resourceConfig;
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.context.annotation.Bean;
/**
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jetty
* endpoints.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Madhura Bhave
* @since 4.0.0
*/
@ManagementContextConfiguration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
public class JerseyEndpointManagementContextConfiguration {
@Bean
@SuppressWarnings("removal")
public org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar servletEndpointRegistrar(
WebEndpointProperties properties,
org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,
JerseyApplicationPath jerseyApplicationPath, EndpointAccessResolver endpointAccessResolver) {
return new org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar(
jerseyApplicationPath.getRelativePath(properties.getBasePath()),
servletEndpointsSupplier.getEndpoints(), endpointAccessResolver);
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Shared configuration for Jersey-based actuators regardless of management context type.
*
* @author Madhura Bhave
*/
@Configuration(proxyBeanMethods = false)
class JerseyManagementContextConfiguration {
@Bean
ServletRegistrationBean<ServletContainer> jerseyServletRegistration(JerseyApplicationPath jerseyApplicationPath,
ResourceConfig resourceConfig) {
return new ServletRegistrationBean<>(new ServletContainer(resourceConfig),
jerseyApplicationPath.getUrlMapping());
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jersey.autoconfigure.DefaultJerseyApplicationPath;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.boot.jersey.autoconfigure.JerseyProperties;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jersey
* infrastructure when the management context is the same as the main application context.
*
* @author Madhura Bhave
* @since 4.0.0
*/
@ManagementContextConfiguration(value = ManagementContextType.SAME, proxyBeanMethods = false)
@EnableConfigurationProperties(JerseyProperties.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ JerseyApplicationPath.class, ResourceConfig.class })
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
public class JerseySameManagementContextConfiguration {
@Bean
ResourceConfigCustomizer managementResourceConfigCustomizerAdapter(
ObjectProvider<ManagementContextResourceConfigCustomizer> customizers) {
return (config) -> customizers.orderedStream().forEach((customizer) -> customizer.customize(config));
}
@Configuration(proxyBeanMethods = false)
@Import(JerseyManagementContextConfiguration.class)
@ConditionalOnMissingBean(ResourceConfig.class)
static class JerseyInfrastructureConfiguration {
@Bean
@ConditionalOnMissingBean
JerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) {
return new DefaultJerseyApplicationPath(properties.getApplicationPath(), config);
}
@Bean
ResourceConfig resourceConfig(ObjectProvider<ResourceConfigCustomizer> resourceConfigCustomizers) {
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfigCustomizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));
return resourceConfig;
}
}
}

View File

@ -1,243 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.ext.ContextResolver;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.jersey.actuate.endpoint.web.JerseyEndpointResourceFactory;
import org.springframework.boot.jersey.actuate.endpoint.web.JerseyHealthEndpointAdditionalPathResourceFactory;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
/**
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jersey
* {@link Endpoint @Endpoint} concerns.
*
* @author Andy Wilkinson
* @author Phillip Webb
* @author Michael Simons
* @author Madhura Bhave
* @author HaiTao Zhang
*/
@ManagementContextConfiguration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(ResourceConfig.class)
@ConditionalOnBean(WebEndpointsSupplier.class)
@ConditionalOnMissingBean(type = "org.springframework.web.servlet.DispatcherServlet")
class JerseyWebEndpointManagementContextConfiguration {
private static final EndpointId HEALTH_ENDPOINT_ID = EndpointId.of("health");
@Bean
@SuppressWarnings("removal")
JerseyWebEndpointsResourcesRegistrar jerseyWebEndpointsResourcesRegistrar(Environment environment,
WebEndpointsSupplier webEndpointsSupplier,
org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, WebEndpointProperties webEndpointProperties) {
String basePath = webEndpointProperties.getBasePath();
boolean shouldRegisterLinks = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
return new JerseyWebEndpointsResourcesRegistrar(webEndpointsSupplier, servletEndpointsSupplier,
endpointMediaTypes, basePath, shouldRegisterLinks);
}
@Bean
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
@ConditionalOnBean(HealthEndpoint.class)
@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)
JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar jerseyDifferentPortAdditionalHealthEndpointPathsResourcesRegistrar(
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups healthEndpointGroups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint healthEndpoint = webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HEALTH_ENDPOINT_ID))
.findFirst()
.orElse(null);
return new JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(healthEndpoint,
healthEndpointGroups);
}
@Bean
@ConditionalOnBean(EndpointObjectMapper.class)
ResourceConfigCustomizer endpointObjectMapperResourceConfigCustomizer(EndpointObjectMapper endpointObjectMapper) {
return (config) -> config.register(new EndpointObjectMapperContextResolver(endpointObjectMapper),
ContextResolver.class);
}
private boolean shouldRegisterLinksMapping(WebEndpointProperties properties, Environment environment,
String basePath) {
return properties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
}
/**
* Register endpoints with the {@link ResourceConfig} for the management context.
*/
@SuppressWarnings("removal")
static class JerseyWebEndpointsResourcesRegistrar implements ManagementContextResourceConfigCustomizer {
private final WebEndpointsSupplier webEndpointsSupplier;
private final org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier;
private final EndpointMediaTypes mediaTypes;
private final String basePath;
private final boolean shouldRegisterLinks;
JerseyWebEndpointsResourcesRegistrar(WebEndpointsSupplier webEndpointsSupplier,
org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, String basePath, boolean shouldRegisterLinks) {
this.webEndpointsSupplier = webEndpointsSupplier;
this.servletEndpointsSupplier = servletEndpointsSupplier;
this.mediaTypes = endpointMediaTypes;
this.basePath = basePath;
this.shouldRegisterLinks = shouldRegisterLinks;
}
@Override
public void customize(ResourceConfig config) {
register(config);
}
private void register(ResourceConfig config) {
Collection<ExposableWebEndpoint> webEndpoints = this.webEndpointsSupplier.getEndpoints();
Collection<org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint> servletEndpoints = this.servletEndpointsSupplier
.getEndpoints();
EndpointLinksResolver linksResolver = getLinksResolver(webEndpoints, servletEndpoints);
EndpointMapping mapping = new EndpointMapping(this.basePath);
Collection<Resource> endpointResources = new JerseyEndpointResourceFactory().createEndpointResources(
mapping, webEndpoints, this.mediaTypes, linksResolver, this.shouldRegisterLinks);
register(endpointResources, config);
}
private EndpointLinksResolver getLinksResolver(Collection<ExposableWebEndpoint> webEndpoints,
Collection<org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint> servletEndpoints) {
List<ExposableEndpoint<?>> endpoints = new ArrayList<>(webEndpoints.size() + servletEndpoints.size());
endpoints.addAll(webEndpoints);
endpoints.addAll(servletEndpoints);
return new EndpointLinksResolver(endpoints, this.basePath);
}
private void register(Collection<Resource> resources, ResourceConfig config) {
config.registerResources(new HashSet<>(resources));
}
}
class JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar
implements ManagementContextResourceConfigCustomizer {
private final @Nullable ExposableWebEndpoint healthEndpoint;
private final HealthEndpointGroups groups;
JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(@Nullable ExposableWebEndpoint healthEndpoint,
HealthEndpointGroups groups) {
this.healthEndpoint = healthEndpoint;
this.groups = groups;
}
@Override
public void customize(ResourceConfig config) {
if (this.healthEndpoint != null) {
register(config, this.healthEndpoint);
}
}
private void register(ResourceConfig config, ExposableWebEndpoint healthEndpoint) {
EndpointMapping mapping = new EndpointMapping("");
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
WebServerNamespace.MANAGEMENT, this.groups);
Collection<Resource> endpointResources = resourceFactory
.createEndpointResources(mapping, Collections.singletonList(healthEndpoint))
.stream()
.filter(Objects::nonNull)
.toList();
register(endpointResources, config);
}
private void register(Collection<Resource> resources, ResourceConfig config) {
config.registerResources(new HashSet<>(resources));
}
}
/**
* {@link ContextResolver} used to obtain the {@link ObjectMapper} that should be used
* for {@link OperationResponseBody} instances.
*/
@Priority(Priorities.USER - 100)
private static final class EndpointObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final EndpointObjectMapper endpointObjectMapper;
private EndpointObjectMapperContextResolver(EndpointObjectMapper endpointObjectMapper) {
this.endpointObjectMapper = endpointObjectMapper;
}
@Override
public @Nullable ObjectMapper getContext(Class<?> type) {
for (Class<?> supportedType : this.endpointObjectMapper.getSupportedTypes()) {
if (supportedType.isAssignableFrom(type)) {
return this.endpointObjectMapper.get();
}
}
return null;
}
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.glassfish.jersey.server.ResourceConfig;
/**
* Callback interface that can be implemented by beans wishing to customize Jersey's
* {@link ResourceConfig} in the management context before it is used.
*
* @author Andy Wilkinson
* @since 4.0.0
*/
public interface ManagementContextResourceConfigCustomizer {
/**
* Customize the resource config.
* @param config the {@link ResourceConfig} to customize
*/
void customize(ResourceConfig config);
}

View File

@ -1,23 +0,0 @@
/*
* Copyright 2012-present 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.
*/
/**
* Auto-configuration for Jersey actuator web concerns.
*/
@NullMarked
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.jspecify.annotations.NullMarked;

View File

@ -1,81 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.metrics;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.observation.ObservationRegistry;
import org.glassfish.jersey.micrometer.server.JerseyObservationConvention;
import org.glassfish.jersey.micrometer.server.ObservationApplicationEventListener;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.boot.micrometer.metrics.OnlyOnceLoggingDenyMeterFilter;
import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties;
import org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Jersey server instrumentation.
*
* @author Michael Weirauch
* @author Michael Simons
* @author Andy Wilkinson
* @author Moritz Halbritter
* @since 4.0.0
*/
@AutoConfiguration(
afterName = "org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration")
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ ResourceConfig.class, ObservationApplicationEventListener.class })
@ConditionalOnBean({ ResourceConfig.class, ObservationRegistry.class })
@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })
public final class JerseyServerMetricsAutoConfiguration {
private final ObservationProperties observationProperties;
JerseyServerMetricsAutoConfiguration(ObservationProperties observationProperties) {
this.observationProperties = observationProperties;
}
@Bean
ResourceConfigCustomizer jerseyServerObservationResourceConfigCustomizer(ObservationRegistry observationRegistry,
ObjectProvider<JerseyObservationConvention> jerseyObservationConvention) {
String metricName = this.observationProperties.getHttp().getServer().getRequests().getName();
return (config) -> config.register(new ObservationApplicationEventListener(observationRegistry, metricName,
jerseyObservationConvention.getIfAvailable()));
}
@Bean
@Order(0)
MeterFilter jerseyMetricsUriTagFilter(MetricsProperties metricsProperties) {
String metricName = this.observationProperties.getHttp().getServer().getRequests().getName();
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
() -> String.format("Reached the maximum number of URI tags for '%s'.", metricName));
return MeterFilter.maximumAllowableTags(metricName, "uri",
metricsProperties.getWeb().getServer().getMaxUriTags(), filter);
}
}

View File

@ -1,23 +0,0 @@
/*
* Copyright 2012-present 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.
*/
/**
* Auto-configuration for Jersey metrics.
*/
@NullMarked
package org.springframework.boot.jersey.autoconfigure.metrics;
import org.jspecify.annotations.NullMarked;

View File

@ -1,23 +0,0 @@
/*
* Copyright 2012-present 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.
*/
/**
* Auto-configuration for Jersey.
*/
@NullMarked
package org.springframework.boot.jersey.autoconfigure;
import org.jspecify.annotations.NullMarked;

View File

@ -1,4 +0,0 @@
org.springframework.boot.jersey.autoconfigure.actuate.web.JerseyChildManagementContextConfiguration
org.springframework.boot.jersey.autoconfigure.actuate.web.JerseyEndpointManagementContextConfiguration
org.springframework.boot.jersey.autoconfigure.actuate.web.JerseySameManagementContextConfiguration
org.springframework.boot.jersey.autoconfigure.actuate.web.JerseyWebEndpointManagementContextConfiguration

View File

@ -1,3 +0,0 @@
org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration
org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web.HealthEndpointJerseyExtensionAutoConfiguration
org.springframework.boot.jersey.autoconfigure.metrics.JerseyServerMetricsAutoConfiguration

View File

@ -1,83 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyApplicationPath}.
*
* @author Madhura Bhave
*/
class JerseyApplicationPathTests {
@Test
void getRelativePathReturnsRelativePath() {
assertThat(((JerseyApplicationPath) () -> "spring").getRelativePath("boot")).isEqualTo("spring/boot");
assertThat(((JerseyApplicationPath) () -> "spring/").getRelativePath("boot")).isEqualTo("spring/boot");
assertThat(((JerseyApplicationPath) () -> "spring").getRelativePath("/boot")).isEqualTo("spring/boot");
assertThat(((JerseyApplicationPath) () -> "spring/*").getRelativePath("/boot")).isEqualTo("spring/boot");
}
@Test
void getPrefixWhenHasSimplePathReturnPath() {
assertThat(((JerseyApplicationPath) () -> "spring").getPrefix()).isEqualTo("spring");
}
@Test
void getPrefixWhenHasPatternRemovesPattern() {
assertThat(((JerseyApplicationPath) () -> "spring/*.do").getPrefix()).isEqualTo("spring");
}
@Test
void getPrefixWhenPathEndsWithSlashRemovesSlash() {
assertThat(((JerseyApplicationPath) () -> "spring/").getPrefix()).isEqualTo("spring");
}
@Test
void getUrlMappingWhenPathIsEmptyReturnsSlash() {
assertThat(((JerseyApplicationPath) () -> "").getUrlMapping()).isEqualTo("/*");
}
@Test
void getUrlMappingWhenPathIsSlashReturnsSlash() {
assertThat(((JerseyApplicationPath) () -> "/").getUrlMapping()).isEqualTo("/*");
}
@Test
void getUrlMappingWhenPathContainsStarReturnsPath() {
assertThat(((JerseyApplicationPath) () -> "/spring/*.do").getUrlMapping()).isEqualTo("/spring/*.do");
}
@Test
void getUrlMappingWhenHasPathNotEndingSlashReturnsSlashStarPattern() {
assertThat(((JerseyApplicationPath) () -> "/spring/boot").getUrlMapping()).isEqualTo("/spring/boot/*");
}
@Test
void getUrlMappingWhenHasPathDoesNotStartWithSlashPrependsSlash() {
assertThat(((JerseyApplicationPath) () -> "spring/boot").getUrlMapping()).isEqualTo("/spring/boot/*");
}
@Test
void getUrlMappingWhenHasPathEndingWithSlashReturnsSlashStarPattern() {
assertThat(((JerseyApplicationPath) () -> "/spring/boot/").getUrlMapping()).isEqualTo("/spring/boot/*");
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Application;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using a custom {@link Application}.
*
* @author Stephane Nicoll
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
class JerseyAutoConfigurationCustomApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/test/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@ApplicationPath("/test")
static class TestApplication extends Application {
}
@Path("/hello")
public static class TestController {
@GET
public String message() {
return "Hello World";
}
}
@Configuration(proxyBeanMethods = false)
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
static class TestConfiguration {
@Configuration(proxyBeanMethods = false)
public class JerseyConfiguration {
@Bean
public TestApplication testApplication() {
return new TestApplication();
}
@Bean
public ResourceConfig conf(TestApplication app) {
ResourceConfig config = ResourceConfig.forApplication(app);
config.register(TestController.class);
return config;
}
}
}
}

View File

@ -1,100 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "spring.jersey.type=filter", "server.servlet.context-path=/app",
"server.servlet.register-default-servlet=true" })
@DirtiesContext
class JerseyAutoConfigurationCustomFilterContextPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/rest/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,99 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "spring.jersey.type=filter", "server.servlet.register-default-servlet=true" })
@DirtiesContext
class JerseyAutoConfigurationCustomFilterPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/rest/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@ApplicationPath("rest")
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,76 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom load on startup.
*
* @author Stephane Nicoll
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.jersey.servlet.load-on-startup=5")
@DirtiesContext
class JerseyAutoConfigurationCustomLoadOnStartupTests {
@Autowired
private ApplicationContext context;
@Test
void contextLoads() {
assertThat(this.context.getBean("jerseyServletRegistration")).hasFieldOrPropertyWithValue("loadOnStartup", 5);
}
@MinimalWebConfiguration
static class Application extends ResourceConfig {
Application() {
register(Application.class);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ JerseyAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,126 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom ObjectMapper.
*
* @author Eddú Meléndez
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = "spring.jackson.default-property-inclusion=non_null")
@DirtiesContext
class JerseyAutoConfigurationCustomObjectMapperProviderTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> response = this.restTemplate.getForEntity("/rest/message", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat("{\"subject\":\"Jersey\"}").isEqualTo(response.getBody());
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/message")
public static class Application extends ResourceConfig {
Application() {
register(Application.class);
}
@GET
public Message message() {
return new Message("Jersey", null);
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
public static class Message {
private String subject;
private String body;
Message(String subject, String body) {
this.subject = subject;
this.body = body;
}
public String getSubject() {
return this.subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return this.body;
}
public void setBody(String body) {
this.body = body;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JacksonAutoConfiguration.class,
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "server.servlet.contextPath=/app")
@DirtiesContext
class JerseyAutoConfigurationCustomServletContextPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/rest/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
class JerseyAutoConfigurationCustomServletPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/rest/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,97 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "spring.jersey.type=filter", "server.servlet.register-default-servlet=true" })
@DirtiesContext
class JerseyAutoConfigurationDefaultFilterPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,96 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using default servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
class JerseyAutoConfigurationDefaultServletPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,136 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.xml.bind.annotation.XmlTransient;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} with an ObjectMapper.
*
* @author Eddú Meléndez
* @author Andy Wilkinson
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = "spring.jackson.default-property-inclusion:non-null")
@DirtiesContext
class JerseyAutoConfigurationObjectMapperProviderTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void responseIsSerializedUsingAutoConfiguredObjectMapper() {
ResponseEntity<String> response = this.restTemplate.getForEntity("/rest/message", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo("{\"subject\":\"Jersey\"}");
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/message")
public static class Application extends ResourceConfig {
Application() {
register(Application.class);
}
@GET
public Message message() {
return new Message("Jersey", null);
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
public static class Message {
private String subject;
private String body;
Message() {
}
Message(String subject, String body) {
this.subject = subject;
this.body = body;
}
public String getSubject() {
return this.subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return this.body;
}
public void setBody(String body) {
this.body = body;
}
@XmlTransient
public String getFoo() {
return "foo";
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JacksonAutoConfiguration.class,
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,111 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.nio.charset.StandardCharsets;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.tomcat.util.buf.UDecoder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfigurationServletContainerTests.Application;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests that verify the behavior when deployed to a Servlet container where Jersey may
* have already initialized itself.
*
* @author Andy Wilkinson
*/
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
@ExtendWith(OutputCaptureExtension.class)
class JerseyAutoConfigurationServletContainerTests {
@Test
void existingJerseyServletIsAmended(CapturedOutput output) {
assertThat(output).contains("Configuring existing registration for Jersey servlet");
assertThat(output).contains("Servlet " + Application.class.getName() + " was not registered");
}
@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
@Import(ContainerConfiguration.class)
@Path("/hello")
@Configuration(proxyBeanMethods = false)
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
}
@Configuration(proxyBeanMethods = false)
static class ContainerConfiguration {
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
Wrapper jerseyServlet = context.createWrapper();
String servletName = Application.class.getName();
jerseyServlet.setName(servletName);
jerseyServlet.setServletClass(ServletContainer.class.getName());
jerseyServlet.setServlet(new ServletContainer());
jerseyServlet.setOverridable(false);
context.addChild(jerseyServlet);
String pattern = UDecoder.URLDecode("/*", StandardCharsets.UTF_8);
context.addServletMappingDecoded(pattern, servletName);
}
};
}
}
}

View File

@ -1,163 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.util.Collections;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration.JerseyWebApplicationInitializer;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.filter.RequestContextFilter;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration}.
*
* @author Andy Wilkinson
*/
class JerseyAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class))
.withUserConfiguration(ResourceConfigConfiguration.class);
@Test
void requestContextFilterRegistrationIsAutoConfigured() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(FilterRegistrationBean.class);
FilterRegistrationBean<?> registration = context.getBean(FilterRegistrationBean.class);
assertThat(registration.getFilter()).isInstanceOf(RequestContextFilter.class);
});
}
@Test
void whenUserDefinesARequestContextFilterTheAutoConfiguredRegistrationBacksOff() {
this.contextRunner.withUserConfiguration(RequestContextFilterConfiguration.class).run((context) -> {
assertThat(context).doesNotHaveBean(FilterRegistrationBean.class);
assertThat(context).hasSingleBean(RequestContextFilter.class);
});
}
@Test
void whenUserDefinesARequestContextFilterRegistrationTheAutoConfiguredRegistrationBacksOff() {
this.contextRunner.withUserConfiguration(RequestContextFilterRegistrationConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(FilterRegistrationBean.class);
assertThat(context).hasBean("customRequestContextFilterRegistration");
});
}
@Test
void whenJaxbIsAvailableTheObjectMapperIsCustomizedWithAnAnnotationIntrospector() {
this.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class)).run((context) -> {
ObjectMapper objectMapper = context.getBean(ObjectMapper.class);
assertThat(objectMapper.getSerializationConfig()
.getAnnotationIntrospector()
.allIntrospectors()
.stream()
.filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).hasSize(1);
});
}
@Test
void whenJaxbIsNotAvailableTheObjectMapperCustomizationBacksOff() {
this.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader("jakarta.xml.bind.annotation"))
.run((context) -> {
ObjectMapper objectMapper = context.getBean(ObjectMapper.class);
assertThat(objectMapper.getSerializationConfig()
.getAnnotationIntrospector()
.allIntrospectors()
.stream()
.filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).isEmpty();
});
}
@Test
void whenJacksonJaxbModuleIsNotAvailableTheObjectMapperCustomizationBacksOff() {
this.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(JakartaXmlBindAnnotationIntrospector.class))
.run((context) -> {
ObjectMapper objectMapper = context.getBean(ObjectMapper.class);
assertThat(objectMapper.getSerializationConfig()
.getAnnotationIntrospector()
.allIntrospectors()
.stream()
.filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).isEmpty();
});
}
@Test
void webApplicationInitializerDisablesJerseyWebApplicationInitializer() throws ServletException {
ServletContext context = new MockServletContext();
new JerseyWebApplicationInitializer().onStartup(context);
assertThat(context.getInitParameter("contextConfigLocation")).isEqualTo("<NONE>");
}
@Test
@ClassPathExclusions("jersey-spring6-*.jar")
void webApplicationInitializerHasNoEffectWhenJerseyIsAbsent() throws ServletException {
ServletContext context = new MockServletContext();
new JerseyWebApplicationInitializer().onStartup(context);
assertThat(Collections.list(context.getInitParameterNames())).isEmpty();
}
@Configuration(proxyBeanMethods = false)
static class ResourceConfigConfiguration {
@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}
}
@Configuration(proxyBeanMethods = false)
static class RequestContextFilterConfiguration {
@Bean
RequestContextFilter requestContextFilter() {
return new RequestContextFilter();
}
}
@Configuration(proxyBeanMethods = false)
static class RequestContextFilterRegistrationConfiguration {
@Bean
FilterRegistrationBean<RequestContextFilter> customRequestContextFilterRegistration() {
return new FilterRegistrationBean<>(new RequestContextFilter());
}
}
}

View File

@ -1,96 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom application path.
*
* @author Eddú Meléndez
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.jersey.application-path=/api")
@DirtiesContext
class JerseyAutoConfigurationWithoutApplicationPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/api/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@ -1,92 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTestEndpointOutcomeExposureContributor;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
import org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;
import org.springframework.boot.health.contributor.Health;
import org.springframework.boot.health.contributor.HealthIndicator;
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
import org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web.HealthEndpointJerseyExtensionAutoConfiguration.JerseyAdditionalHealthEndpointPathsResourcesRegistrar;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link HealthEndpointJerseyExtensionAutoConfiguration}.
*
* @author Stephane Nicoll
*/
class HealthEndpointJerseyExtensionAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withUserConfiguration(HealthIndicatorsConfiguration.class)
.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,
HealthContributorRegistryAutoConfiguration.class, HealthEndpointAutoConfiguration.class,
HealthEndpointJerseyExtensionAutoConfiguration.class));
@Test
@WithTestEndpointOutcomeExposureContributor
void additionalJerseyHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {
this.contextRunner
.withConfiguration(
AutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))
.withPropertyValues("management.endpoints.web.exposure.exclude=*",
"management.endpoints.test.exposure.include=*")
.run((context) -> {
assertThat(context).hasNotFailed();
assertThat(context).hasSingleBean(HealthEndpoint.class);
assertThat(context).hasSingleBean(HealthEndpointWebExtension.class);
assertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();
assertThat(context).hasSingleBean(JerseyAdditionalHealthEndpointPathsResourcesRegistrar.class);
});
}
@Configuration(proxyBeanMethods = false)
static class HealthIndicatorsConfiguration {
@Bean
HealthIndicator simpleHealthIndicator() {
return () -> Health.up().withDetail("counter", 42).build();
}
@Bean
HealthIndicator additionalHealthIndicator() {
return () -> Health.up().build();
}
@Bean
ReactiveHealthIndicator reactiveHealthIndicator() {
return () -> Mono.just(Health.up().build());
}
}
}

View File

@ -1,191 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;
import java.io.IOException;
import java.time.Duration;
import java.util.function.Supplier;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.reactive.server.EntityExchangeResult;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for controlling access to endpoints exposed by Jersey.
*
* @author Andy Wilkinson
*/
class JerseyEndpointAccessIntegrationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, JerseyAutoConfiguration.class,
EndpointAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,
WebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,
BeansEndpointAutoConfiguration.class))
.withUserConfiguration(CustomServletEndpoint.class)
.withPropertyValues("server.port:0");
@Test
void accessIsUnrestrictedByDefault() {
this.contextRunner.withPropertyValues("management.endpoints.web.exposure.include=*").run((context) -> {
WebTestClient client = createClient(context);
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isTrue();
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isTrue();
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isTrue();
});
}
@Test
void accessCanBeReadOnlyByDefault() {
this.contextRunner
.withPropertyValues("management.endpoints.web.exposure.include=*",
"management.endpoints.access.default=READ_ONLY")
.run((context) -> {
WebTestClient client = createClient(context);
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isTrue();
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isTrue();
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
});
}
@Test
void accessCanBeNoneByDefault() {
this.contextRunner
.withPropertyValues("management.endpoints.web.exposure.include=*",
"management.endpoints.access.default=NONE")
.run((context) -> {
WebTestClient client = createClient(context);
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isFalse();
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isFalse();
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
});
}
@Test
void accessForOneEndpointCanOverrideTheDefaultAccess() {
this.contextRunner
.withPropertyValues("management.endpoints.web.exposure.include=*",
"management.endpoints.access.default=NONE", "management.endpoint.customservlet.access=READ_ONLY")
.run((context) -> {
WebTestClient client = createClient(context);
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isFalse();
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isTrue();
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
});
}
@Test
void accessCanBeCappedAtReadOnly() {
this.contextRunner
.withPropertyValues("management.endpoints.web.exposure.include=*",
"management.endpoints.access.default=UNRESTRICTED",
"management.endpoints.access.max-permitted=READ_ONLY")
.run((context) -> {
WebTestClient client = createClient(context);
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isTrue();
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isTrue();
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
});
}
@Test
void accessCanBeCappedAtNone() {
this.contextRunner.withPropertyValues("management.endpoints.web.exposure.include=*",
"management.endpoints.access.default=UNRESTRICTED", "management.endpoints.access.max-permitted=NONE")
.run((context) -> {
WebTestClient client = createClient(context);
assertThat(isAccessible(client, HttpMethod.GET, "beans")).isFalse();
assertThat(isAccessible(client, HttpMethod.GET, "customservlet")).isFalse();
assertThat(isAccessible(client, HttpMethod.POST, "customservlet")).isFalse();
});
}
private WebTestClient createClient(AssertableWebApplicationContext context) {
int port = context.getSourceApplicationContext(ServletWebServerApplicationContext.class)
.getWebServer()
.getPort();
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
.codecs((configurer) -> configurer.defaultCodecs().maxInMemorySize(-1))
.build();
return WebTestClient.bindToServer()
.baseUrl("http://localhost:" + port)
.exchangeStrategies(exchangeStrategies)
.responseTimeout(Duration.ofMinutes(5))
.build();
}
private boolean isAccessible(WebTestClient client, HttpMethod method, String path) {
path = "/actuator/" + path;
EntityExchangeResult<byte[]> result = client.method(method).uri(path).exchange().expectBody().returnResult();
if (result.getStatus() == HttpStatus.OK) {
return true;
}
if (result.getStatus() == HttpStatus.NOT_FOUND || result.getStatus() == HttpStatus.METHOD_NOT_ALLOWED) {
return false;
}
throw new IllegalStateException(
String.format("Unexpected %s HTTP status for endpoint %s", result.getStatus(), path));
}
@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = "customservlet")
@SuppressWarnings({ "deprecation", "removal" })
static class CustomServletEndpoint
implements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {
@Override
public org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {
return new org.springframework.boot.actuate.endpoint.web.EndpointServlet(new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
});
}
}
}

View File

@ -1,228 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for the Jersey actuator endpoints.
*
* @author Andy Wilkinson
* @author Madhura Bhave
*/
class JerseyEndpointIntegrationTests {
@Test
void linksAreProvidedToAllEndpointTypes() {
testJerseyEndpoints(new Class<?>[] { EndpointsConfiguration.class, ResourceConfigConfiguration.class });
}
@Test
void linksPageIsNotAvailableWhenDisabled() {
getContextRunner(new Class<?>[] { EndpointsConfiguration.class, ResourceConfigConfiguration.class })
.withPropertyValues("management.endpoints.web.discovery.enabled:false")
.run((context) -> {
int port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)
.getWebServer()
.getPort();
WebTestClient client = WebTestClient.bindToServer()
.baseUrl("http://localhost:" + port)
.responseTimeout(Duration.ofMinutes(5))
.build();
client.get().uri("/actuator").exchange().expectStatus().isNotFound();
});
}
@Test
void actuatorEndpointsWhenUserProvidedResourceConfigBeanNotAvailable() {
testJerseyEndpoints(new Class<?>[] { EndpointsConfiguration.class });
}
@Test
void endpointObjectMapperCanBeApplied() {
WebApplicationContextRunner contextRunner = getContextRunner(new Class<?>[] { EndpointsConfiguration.class,
ResourceConfigConfiguration.class, EndpointObjectMapperConfiguration.class });
contextRunner.run((context) -> {
int port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)
.getWebServer()
.getPort();
WebTestClient client = WebTestClient.bindToServer()
.baseUrl("http://localhost:" + port)
.responseTimeout(Duration.ofMinutes(5))
.build();
client.get().uri("/actuator/beans").exchange().expectStatus().isOk().expectBody().consumeWith((result) -> {
String json = new String(result.getResponseBody(), StandardCharsets.UTF_8);
assertThat(json).contains("\"scope\":\"notelgnis\"");
});
});
}
protected void testJerseyEndpoints(Class<?>[] userConfigurations) {
getContextRunner(userConfigurations).run((context) -> {
int port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)
.getWebServer()
.getPort();
WebTestClient client = WebTestClient.bindToServer()
.baseUrl("http://localhost:" + port)
.responseTimeout(Duration.ofMinutes(5))
.build();
client.get()
.uri("/actuator")
.exchange()
.expectStatus()
.isOk()
.expectBody()
.jsonPath("_links.beans")
.isNotEmpty()
.jsonPath("_links.restcontroller")
.doesNotExist()
.jsonPath("_links.controller")
.doesNotExist();
});
}
WebApplicationContextRunner getContextRunner(Class<?>[] userConfigurations,
Class<?>... additionalAutoConfigurations) {
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(getAutoconfigurations(additionalAutoConfigurations)))
.withUserConfiguration(userConfigurations)
.withPropertyValues("management.endpoints.web.exposure.include:*", "server.port:0");
}
private Class<?>[] getAutoconfigurations(Class<?>... additional) {
List<Class<?>> autoconfigurations = new ArrayList<>(Arrays.asList(JacksonAutoConfiguration.class,
JerseyAutoConfiguration.class, EndpointAutoConfiguration.class,
TomcatServletWebServerAutoConfiguration.class, WebEndpointAutoConfiguration.class,
ManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class));
autoconfigurations.addAll(Arrays.asList(additional));
return autoconfigurations.toArray(new Class<?>[0]);
}
@org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint(id = "controller")
@SuppressWarnings("removal")
static class TestControllerEndpoint {
}
@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = "restcontroller")
@SuppressWarnings("removal")
static class TestRestControllerEndpoint {
}
@Configuration(proxyBeanMethods = false)
static class EndpointsConfiguration {
@Bean
TestControllerEndpoint testControllerEndpoint() {
return new TestControllerEndpoint();
}
@Bean
TestRestControllerEndpoint testRestControllerEndpoint() {
return new TestRestControllerEndpoint();
}
}
@Configuration(proxyBeanMethods = false)
static class ResourceConfigConfiguration {
@Bean
ResourceConfig testResourceConfig() {
return new ResourceConfig();
}
}
@Configuration
@SuppressWarnings({ "deprecation", "removal" })
static class EndpointObjectMapperConfiguration {
@Bean
EndpointObjectMapper endpointObjectMapper() {
SimpleModule module = new SimpleModule();
module.addSerializer(String.class, new ReverseStringSerializer());
ObjectMapper objectMapper = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json()
.modules(module)
.build();
return () -> objectMapper;
}
static class ReverseStringSerializer extends StdScalarSerializer<Object> {
ReverseStringSerializer() {
super(String.class, false);
}
@Override
public boolean isEmpty(SerializerProvider prov, Object value) {
return ((String) value).isEmpty();
}
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
serialize(value, gen);
}
@Override
public final void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider,
TypeSerializer typeSer) throws IOException {
serialize(value, gen);
}
private void serialize(Object value, JsonGenerator gen) throws IOException {
StringBuilder builder = new StringBuilder((String) value);
gen.writeString(builder.reverse().toString());
}
}
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link JerseyChildManagementContextConfiguration}.
*
* @author Andy Wilkinson
* @author Madhura Bhave
*/
@ClassPathExclusions("spring-webmvc-*")
class JerseyChildManagementContextConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withUserConfiguration(JerseyChildManagementContextConfiguration.class);
@Test
void autoConfigurationIsConditionalOnServletWebApplication() {
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class));
contextRunner
.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));
}
@Test
void autoConfigurationIsConditionalOnClassResourceConfig() {
this.contextRunner.withClassLoader(new FilteredClassLoader(ResourceConfig.class))
.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));
}
@Test
void jerseyApplicationPathIsAutoConfigured() {
this.contextRunner.run((context) -> {
JerseyApplicationPath bean = context.getBean(JerseyApplicationPath.class);
assertThat(bean.getPath()).isEqualTo("/");
});
}
@Test
@SuppressWarnings("unchecked")
void servletRegistrationBeanIsAutoConfigured() {
this.contextRunner.run((context) -> {
ServletRegistrationBean<ServletContainer> bean = context.getBean(ServletRegistrationBean.class);
assertThat(bean.getUrlMappings()).containsExactly("/*");
});
}
@Test
void resourceConfigCustomizerBeanIsNotRequired() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ResourceConfig.class));
}
@Test
void resourceConfigIsCustomizedWithResourceConfigCustomizerBean() {
this.contextRunner.withUserConfiguration(CustomizerConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ResourceConfig.class);
ResourceConfig config = context.getBean(ResourceConfig.class);
ManagementContextResourceConfigCustomizer customizer = context
.getBean(ManagementContextResourceConfigCustomizer.class);
then(customizer).should().customize(config);
});
}
@Configuration(proxyBeanMethods = false)
static class CustomizerConfiguration {
@Bean
ManagementContextResourceConfigCustomizer resourceConfigCustomizer() {
return mock(ManagementContextResourceConfigCustomizer.class);
}
}
}

View File

@ -1,86 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyEndpointManagementContextConfiguration}.
*
* @author Stephane Nicoll
*/
@SuppressWarnings("removal")
class JerseyEndpointManagementContextConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withUserConfiguration(TestConfig.class);
@Test
void contextShouldContainServletEndpointRegistrar() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(ServletEndpointRegistrar.class);
ServletEndpointRegistrar bean = context.getBean(ServletEndpointRegistrar.class);
assertThat(bean).hasFieldOrPropertyWithValue("basePath", "/test/actuator");
});
}
@Test
void contextWhenNotServletBasedShouldNotContainServletEndpointRegistrar() {
new ApplicationContextRunner().withUserConfiguration(TestConfig.class)
.run((context) -> assertThat(context).doesNotHaveBean(ServletEndpointRegistrar.class));
}
@Configuration(proxyBeanMethods = false)
@Import(JerseyEndpointManagementContextConfiguration.class)
@EnableConfigurationProperties(WebEndpointProperties.class)
static class TestConfig {
@Bean
ServletEndpointsSupplier servletEndpointsSupplier() {
return Collections::emptyList;
}
@Bean
JerseyApplicationPath jerseyApplicationPath() {
return () -> "/test";
}
@Bean
EndpointAccessResolver endpointAccessResolver() {
return (endpointId, defaultAccess) -> Access.UNRESTRICTED;
}
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.integrationtest.AbstractHealthEndpointAdditionalPathIntegrationTests;
import org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web.HealthEndpointJerseyExtensionAutoConfiguration;
import org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatServletManagementContextAutoConfiguration;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.web.context.ConfigurableWebApplicationContext;
/**
* Integration tests for health groups on an additional path on Jersey.
*
* @author Madhura Bhave
*/
class JerseyHealthEndpointAdditionalPathIntegrationTests extends
AbstractHealthEndpointAdditionalPathIntegrationTests<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {
JerseyHealthEndpointAdditionalPathIntegrationTests() {
super(new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, JerseyAutoConfiguration.class,
EndpointAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,
TomcatServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,
JerseyAutoConfiguration.class, ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class, HealthEndpointAutoConfiguration.class,
HealthContributorRegistryAutoConfiguration.class,
HealthEndpointJerseyExtensionAutoConfiguration.class,
DiskSpaceHealthContributorAutoConfiguration.class))
.withInitializer(new ServerPortInfoApplicationContextInitializer())
.withPropertyValues("server.port=0"));
}
}

View File

@ -1,136 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jersey.autoconfigure.DefaultJerseyApplicationPath;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link JerseySameManagementContextConfiguration}.
*
* @author Madhura Bhave
*/
@ClassPathExclusions("spring-webmvc-*")
class JerseySameManagementContextConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class));
@Test
void autoConfigurationIsConditionalOnServletWebApplication() {
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class));
contextRunner
.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));
}
@Test
void autoConfigurationIsConditionalOnClassResourceConfig() {
this.contextRunner.withClassLoader(new FilteredClassLoader(ResourceConfig.class))
.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));
}
@Test
void jerseyApplicationPathIsAutoConfiguredWhenNeeded() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(DefaultJerseyApplicationPath.class));
}
@Test
void jerseyApplicationPathIsConditionalOnMissingBean() {
this.contextRunner.withUserConfiguration(ConfigWithJerseyApplicationPath.class).run((context) -> {
assertThat(context).hasSingleBean(JerseyApplicationPath.class);
assertThat(context).hasBean("testJerseyApplicationPath");
});
}
@Test
void existingResourceConfigBeanShouldNotAutoConfigureRelatedBeans() {
this.contextRunner.withUserConfiguration(ConfigWithResourceConfig.class).run((context) -> {
assertThat(context).hasSingleBean(ResourceConfig.class);
assertThat(context).doesNotHaveBean(JerseyApplicationPath.class);
assertThat(context).doesNotHaveBean(ServletRegistrationBean.class);
assertThat(context).hasBean("customResourceConfig");
});
}
@Test
@SuppressWarnings("unchecked")
void servletRegistrationBeanIsAutoConfiguredWhenNeeded() {
this.contextRunner.withPropertyValues("spring.jersey.application-path=/jersey").run((context) -> {
ServletRegistrationBean<ServletContainer> bean = context.getBean(ServletRegistrationBean.class);
assertThat(bean.getUrlMappings()).containsExactly("/jersey/*");
});
}
@Test
void resourceConfigIsCustomizedWithResourceConfigCustomizerBean() {
this.contextRunner.withUserConfiguration(CustomizerConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ResourceConfig.class);
ResourceConfig config = context.getBean(ResourceConfig.class);
ManagementContextResourceConfigCustomizer customizer = context
.getBean(ManagementContextResourceConfigCustomizer.class);
then(customizer).should().customize(config);
});
}
@Configuration(proxyBeanMethods = false)
static class ConfigWithJerseyApplicationPath {
@Bean
JerseyApplicationPath testJerseyApplicationPath() {
return mock(JerseyApplicationPath.class);
}
}
@Configuration(proxyBeanMethods = false)
static class ConfigWithResourceConfig {
@Bean
ResourceConfig customResourceConfig() {
return new ResourceConfig();
}
}
@Configuration(proxyBeanMethods = false)
static class CustomizerConfiguration {
@Bean
ManagementContextResourceConfigCustomizer resourceConfigCustomizer() {
return mock(ManagementContextResourceConfigCustomizer.class);
}
}
}

View File

@ -1,72 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import java.util.Set;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for web endpoints running on Jersey.
*
* @author Andy Wilkinson
*/
class JerseyWebEndpointIntegrationTests {
@Test
void whenJerseyIsConfiguredToUseAFilterThenResourceRegistrationSucceeds() {
new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(
AutoConfigurations.of(JerseySameManagementContextConfiguration.class, JerseyAutoConfiguration.class,
TomcatServletWebServerAutoConfiguration.class, EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class, JerseyWebEndpointManagementContextConfiguration.class))
.withUserConfiguration(ResourceConfigConfiguration.class)
.withPropertyValues("spring.jersey.type=filter", "server.port=0")
.run((context) -> {
assertThat(context).hasNotFailed();
Set<Resource> resources = context.getBean(ResourceConfig.class).getResources();
assertThat(resources).hasSize(1);
Resource resource = resources.iterator().next();
assertThat(resource.getPath()).isEqualTo("/actuator");
});
}
@Configuration(proxyBeanMethods = false)
static class ResourceConfigConfiguration {
@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.actuate.web;
import java.util.Collections;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jersey.autoconfigure.actuate.web.JerseyWebEndpointManagementContextConfiguration.JerseyWebEndpointsResourcesRegistrar;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyWebEndpointManagementContextConfiguration}.
*
* @author Michael Simons
* @author Madhura Bhave
*/
class JerseyWebEndpointManagementContextConfigurationTests {
private final WebApplicationContextRunner runner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(WebEndpointAutoConfiguration.class,
JerseyWebEndpointManagementContextConfiguration.class))
.withBean(WebEndpointsSupplier.class, () -> Collections::emptyList)
.withBean(EndpointAccessResolver.class, () -> (endpointId, defaultAccess) -> Access.UNRESTRICTED);
@Test
void jerseyWebEndpointsResourcesRegistrarForEndpointsIsAutoConfigured() {
this.runner.run((context) -> assertThat(context).hasSingleBean(JerseyWebEndpointsResourcesRegistrar.class));
}
@Test
void autoConfigurationIsConditionalOnServletWebApplication() {
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class));
contextRunner
.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));
}
@Test
void autoConfigurationIsConditionalOnClassResourceConfig() {
this.runner.withClassLoader(new FilteredClassLoader(ResourceConfig.class))
.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));
}
}

View File

@ -1,143 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.autoconfigure.metrics;
import java.net.URI;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
import io.micrometer.core.instrument.observation.MeterObservationHandler;
import io.micrometer.observation.Observation.Context;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import org.glassfish.jersey.micrometer.server.ObservationApplicationEventListener;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;
import org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyServerMetricsAutoConfiguration}.
*
* @author Michael Weirauch
* @author Michael Simons
* @author Moritz Halbritter
*/
class JerseyServerMetricsAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JerseyServerMetricsAutoConfiguration.class));
private final WebApplicationContextRunner webContextRunner = new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class,
JerseyServerMetricsAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,
TomcatServletWebServerAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class,
ObservationAutoConfiguration.class, MetricsAutoConfiguration.class))
.withUserConfiguration(ResourceConfiguration.class)
.withPropertyValues("server.port:0");
@Test
void shouldOnlyBeActiveInWebApplicationContext() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ResourceConfigCustomizer.class));
}
@Test
void shouldProvideAllNecessaryBeans() {
this.webContextRunner.run((context) -> assertThat(context).hasBean("jerseyMetricsUriTagFilter")
.hasSingleBean(ResourceConfigCustomizer.class));
}
@Test
void httpRequestsAreTimed() {
this.webContextRunner.withUserConfiguration(MetricsConfiguration.class).run((context) -> {
doRequest(context);
Thread.sleep(500);
MeterRegistry registry = context.getBean(MeterRegistry.class);
Timer timer = registry.get("http.server.requests").tag("uri", "/users/{id}").timer();
assertThat(timer.count()).isOne();
});
}
@Test
void noHttpRequestsTimedWhenJerseyInstrumentationMissingFromClasspath() {
this.webContextRunner.withClassLoader(new FilteredClassLoader(ObservationApplicationEventListener.class))
.run((context) -> {
doRequest(context);
MeterRegistry registry = context.getBean(MeterRegistry.class);
assertThat(registry.find("http.server.requests").timer()).isNull();
});
}
private static void doRequest(AssertableWebApplicationContext context) {
int port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)
.getWebServer()
.getPort();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getForEntity(URI.create("http://localhost:" + port + "/users/3"), String.class);
}
@Configuration(proxyBeanMethods = false)
static class ResourceConfiguration {
@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig().register(new TestResource());
}
@Path("/users")
public static class TestResource {
@GET
@Path("/{id}")
public String getUser(@PathParam("id") String id) {
return id;
}
}
}
@Configuration(proxyBeanMethods = false)
static class MetricsConfiguration {
@Bean
MeterObservationHandler<Context> meterObservationHandler(MeterRegistry registry) {
return new DefaultMeterObservationHandler(registry);
}
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.actuate.endpoint.web.test;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.jersey.actuate.endpoint.web.JerseyEndpointResourceFactory;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Endpoint configuration for Jersey.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, JerseyAutoConfiguration.class })
class JerseyEndpointConfiguration {
private final ApplicationContext applicationContext;
JerseyEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}
@Bean
ResourceConfigCustomizer webEndpointRegistrar() {
return this::customize;
}
private void customize(ResourceConfig config) {
EndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
new ConversionServiceParameterValueMapper(), endpointMediaTypes, null, Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
Collection<Resource> resources = new JerseyEndpointResourceFactory().createEndpointResources(
new EndpointMapping("/actuator"), discoverer.getEndpoints(), endpointMediaTypes,
new EndpointLinksResolver(discoverer.getEndpoints()), true);
config.registerResources(new HashSet<>(resources));
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jersey.actuate.endpoint.web.test;
import java.util.List;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;
/**
* {@link WebEndpointInfrastructureProvider} for Jersey.
*
* @author Stephane Nicoll
*/
class JerseyWebEndpointInfrastructureProvider implements WebEndpointInfrastructureProvider {
@Override
public boolean supports(Infrastructure infrastructure) {
return infrastructure == Infrastructure.JERSEY;
}
@Override
public List<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure) {
return List.of(JerseyEndpointConfiguration.class);
}
}

View File

@ -1,2 +0,0 @@
org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider=\
org.springframework.boot.jersey.actuate.endpoint.web.test.JerseyWebEndpointInfrastructureProvider

View File

@ -38,7 +38,6 @@ dependencies {
testImplementation(project(":module:spring-boot-flyway"))
testImplementation(project(":module:spring-boot-liquibase"))
testImplementation(project(":test-support:spring-boot-test-support"))
testImplementation(testFixtures(project(":module:spring-boot-jersey")))
testImplementation(testFixtures(project(":module:spring-boot-webflux")))
testImplementation(testFixtures(project(":module:spring-boot-webmvc")))
testImplementation("net.minidev:json-smart")

View File

@ -32,7 +32,6 @@ dependencies {
optional(project(":core:spring-boot-autoconfigure"))
optional(project(":module:spring-boot-actuator-autoconfigure"))
optional(project(":module:spring-boot-h2console"))
optional(project(":module:spring-boot-jersey"))
optional(project(":module:spring-boot-reactor"))
optional(project(":module:spring-boot-rsocket"))
optional(project(":module:spring-boot-webmvc"))

View File

@ -16,16 +16,12 @@
package org.springframework.boot.security.autoconfigure.actuate.servlet;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -58,17 +54,4 @@ public class SecurityRequestMatchersManagementContextConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ResourceConfig.class)
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
@ConditionalOnBean(JerseyApplicationPath.class)
public static class JerseyRequestMatcherConfiguration {
@Bean
public RequestMatcherProvider requestMatcherProvider(JerseyApplicationPath applicationPath) {
return new PathPatternRequestMatcherProvider(applicationPath::getRelativePath);
}
}
}

View File

@ -1,156 +0,0 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.security.autoconfigure.actuate.servlet;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
* Integration tests for {@link EndpointRequest} with Jersey.
*
* @author Madhura Bhave
*/
class JerseyEndpointRequestIntegrationTests extends AbstractEndpointRequestIntegrationTests {
@Test
void toLinksWhenApplicationPathSetShouldMatch() {
getContextRunner().withPropertyValues("spring.jersey.application-path=/admin").run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get()
.uri("/admin/actuator/")
.exchange()
.expectStatus()
.isEqualTo(expectedStatusWithTrailingSlash());
webTestClient.get().uri("/admin/actuator").exchange().expectStatus().isOk();
});
}
@Test
void toEndpointWhenApplicationPathSetShouldMatch() {
getContextRunner().withPropertyValues("spring.jersey.application-path=/admin").run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/admin/actuator/e1").exchange().expectStatus().isOk();
});
}
@Test
void toAnyEndpointWhenApplicationPathSetShouldMatch() {
getContextRunner()
.withPropertyValues("spring.jersey.application-path=/admin", "spring.security.user.password=password")
.run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/admin/actuator/e2").exchange().expectStatus().isUnauthorized();
webTestClient.get()
.uri("/admin/actuator/e2")
.header("Authorization", getBasicAuth())
.exchange()
.expectStatus()
.isOk();
});
}
@Test
void toAnyEndpointShouldMatchServletEndpoint() {
getContextRunner()
.withPropertyValues("spring.security.user.password=password",
"management.endpoints.web.exposure.include=se1")
.run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/actuator/se1").exchange().expectStatus().isUnauthorized();
webTestClient.get()
.uri("/actuator/se1")
.header("Authorization", getBasicAuth())
.exchange()
.expectStatus()
.isOk();
webTestClient.get().uri("/actuator/se1/list").exchange().expectStatus().isUnauthorized();
webTestClient.get()
.uri("/actuator/se1/list")
.header("Authorization", getBasicAuth())
.exchange()
.expectStatus()
.isOk();
});
}
@Test
void toAnyEndpointWhenApplicationPathSetShouldMatchServletEndpoint() {
getContextRunner()
.withPropertyValues("spring.jersey.application-path=/admin", "spring.security.user.password=password",
"management.endpoints.web.exposure.include=se1")
.run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/admin/actuator/se1").exchange().expectStatus().isUnauthorized();
webTestClient.get()
.uri("/admin/actuator/se1")
.header("Authorization", getBasicAuth())
.exchange()
.expectStatus()
.isOk();
webTestClient.get().uri("/admin/actuator/se1/list").exchange().expectStatus().isUnauthorized();
webTestClient.get()
.uri("/admin/actuator/se1/list")
.header("Authorization", getBasicAuth())
.exchange()
.expectStatus()
.isOk();
});
}
@Override
protected HttpStatus expectedStatusWithTrailingSlash() {
return HttpStatus.OK;
}
@Override
protected WebApplicationContextRunner createContextRunner() {
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
.withUserConfiguration(JerseyEndpointConfiguration.class)
.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class));
}
@Configuration
@EnableConfigurationProperties(WebEndpointProperties.class)
static class JerseyEndpointConfiguration {
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}
}
}

View File

@ -19,7 +19,6 @@ package org.springframework.boot.security.autoconfigure.actuate.servlet;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@ -67,19 +66,6 @@ class SecurityRequestMatchersManagementContextConfigurationTests {
});
}
@Test
void registersRequestMatcherForJerseyProviderIfJerseyPresentAndMvcAbsent() {
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
.withUserConfiguration(TestJerseyConfiguration.class)
.run((context) -> {
PathPatternRequestMatcherProvider matcherProvider = context
.getBean(PathPatternRequestMatcherProvider.class);
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example", null);
assertThat(requestMatcher).extracting("pattern")
.isEqualTo(PathPatternParser.defaultInstance.parse("/admin/example"));
});
}
@Test
void mvcRequestMatcherProviderConditionalOnDispatcherServletClass() {
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
@ -117,14 +103,4 @@ class SecurityRequestMatchersManagementContextConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
static class TestJerseyConfiguration {
@Bean
JerseyApplicationPath jerseyApplicationPath() {
return () -> "/admin";
}
}
}

View File

@ -48,7 +48,6 @@ dependencies {
testImplementation(project(":module:spring-boot-tomcat"))
testImplementation(project(":test-support:spring-boot-test-support"))
testImplementation(project(":module:spring-boot-webflux"))
testImplementation(testFixtures(project(":module:spring-boot-jersey")))
testImplementation(testFixtures(project(":module:spring-boot-webflux")))
testImplementation(testFixtures(project(":module:spring-boot-webmvc")))
testImplementation(testFixtures(project(":module:spring-boot-web-server")))

View File

@ -33,8 +33,7 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Integration tests for {@link SessionsEndpoint} exposed by Jersey, Spring MVC, and
* WebFlux.
* Integration tests for {@link SessionsEndpoint} exposed by Spring MVC and WebFlux.
*
* @author Vedran Pavic
*/
@ -46,7 +45,7 @@ class SessionsEndpointWebIntegrationTests {
private static final FindByIndexNameSessionRepository<Session> repository = mock(
FindByIndexNameSessionRepository.class);
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
@WebEndpointTest(infrastructure = Infrastructure.MVC)
void sessionsForUsernameWithoutUsernameParam(WebTestClient client) {
client.get()
.uri((builder) -> builder.path("/actuator/sessions").build())
@ -55,7 +54,7 @@ class SessionsEndpointWebIntegrationTests {
.isBadRequest();
}
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
@WebEndpointTest(infrastructure = Infrastructure.MVC)
void sessionsForUsernameNoResults(WebTestClient client) {
given(repository.findByPrincipalName("user")).willReturn(Collections.emptyMap());
client.get()
@ -68,7 +67,7 @@ class SessionsEndpointWebIntegrationTests {
.isEmpty();
}
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
@WebEndpointTest(infrastructure = Infrastructure.MVC)
void sessionsForUsernameFound(WebTestClient client) {
given(repository.findByPrincipalName("user")).willReturn(Collections.singletonMap(session.getId(), session));
client.get()
@ -81,7 +80,7 @@ class SessionsEndpointWebIntegrationTests {
.isEqualTo(new JSONArray().appendElement(session.getId()));
}
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
@WebEndpointTest(infrastructure = Infrastructure.MVC)
void sessionForIdNotFound(WebTestClient client) {
client.get()
.uri((builder) -> builder.path("/actuator/sessions/session-id-not-found").build())
@ -90,7 +89,7 @@ class SessionsEndpointWebIntegrationTests {
.isNotFound();
}
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
@WebEndpointTest(infrastructure = Infrastructure.MVC)
void deleteSession(WebTestClient client) {
client.delete()
.uri((builder) -> builder.path("/actuator/sessions/{id}").build(session.getId()))

View File

@ -48,6 +48,7 @@ dependencies {
testFixturesApi(testFixtures(project(":module:spring-boot-actuator")))
testFixturesImplementation(project(":module:spring-boot-http-converter"))
testFixturesImplementation(project(":module:spring-boot-jackson"))
testFixturesImplementation(project(":module:spring-boot-tomcat"))
testImplementation(project(":core:spring-boot-test"))
testImplementation(project(":module:spring-boot-freemarker"))

View File

@ -988,16 +988,6 @@ bom {
releaseNotes("https://github.com/redis/jedis/releases/tag/v{version}")
}
}
library("Jersey", "4.0.0-M2") {
group("org.glassfish.jersey") {
bom("jersey-bom")
}
links {
site("https://github.com/eclipse-ee4j/jersey")
javadoc("https://javadoc.io/doc/org.glassfish.jersey.core/jersey-server/{version}", "org.glassfish.jersey.server")
releaseNotes("https://github.com/eclipse-ee4j/jersey/releases/tag/{version}")
}
}
library("Jetty Reactive HTTPClient", "4.0.11") {
group("org.eclipse.jetty") {
modules = [
@ -2031,7 +2021,6 @@ bom {
"spring-boot-jackson",
"spring-boot-jarmode-tools",
"spring-boot-jdbc",
"spring-boot-jersey",
"spring-boot-jetty",
"spring-boot-jms",
"spring-boot-jooq",
@ -2112,7 +2101,6 @@ bom {
"spring-boot-starter-integration",
"spring-boot-starter-jackson",
"spring-boot-starter-jdbc",
"spring-boot-starter-jersey",
"spring-boot-starter-jetty",
"spring-boot-starter-jms",
"spring-boot-starter-jooq",

View File

@ -117,7 +117,6 @@ include "module:spring-boot-http-converter"
include "module:spring-boot-integration"
include "module:spring-boot-jackson"
include "module:spring-boot-jdbc"
include "module:spring-boot-jersey"
include "module:spring-boot-jetty"
include "module:spring-boot-jms"
include "module:spring-boot-jooq"
@ -208,7 +207,6 @@ include "starter:spring-boot-starter-hazelcast"
include "starter:spring-boot-starter-integration"
include "starter:spring-boot-starter-jackson"
include "starter:spring-boot-starter-jdbc"
include "starter:spring-boot-starter-jersey"
include "starter:spring-boot-starter-jetty"
include "starter:spring-boot-starter-jms"
include "starter:spring-boot-starter-jooq"
@ -312,7 +310,6 @@ include ":smoke-test:spring-boot-smoke-test-graphql"
include ":smoke-test:spring-boot-smoke-test-hateoas"
include ":smoke-test:spring-boot-smoke-test-hibernate"
include ":smoke-test:spring-boot-smoke-test-integration"
include ":smoke-test:spring-boot-smoke-test-jersey"
include ":smoke-test:spring-boot-smoke-test-jetty"
include ":smoke-test:spring-boot-smoke-test-jetty-jsp"
include ":smoke-test:spring-boot-smoke-test-jetty-ssl"
@ -333,7 +330,6 @@ include ":smoke-test:spring-boot-smoke-test-reactive-oauth2-resource-server"
include ":smoke-test:spring-boot-smoke-test-rsocket"
include ":smoke-test:spring-boot-smoke-test-saml2-service-provider"
include ":smoke-test:spring-boot-smoke-test-secure"
include ":smoke-test:spring-boot-smoke-test-secure-jersey"
include ":smoke-test:spring-boot-smoke-test-secure-webflux"
include ":smoke-test:spring-boot-smoke-test-servlet"
include ":smoke-test:spring-boot-smoke-test-session-hazelcast"

View File

@ -1,32 +0,0 @@
/*
* Copyright 2012-present 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.
*/
plugins {
id "java"
}
description = "Spring Boot Jersey smoke test"
dependencies {
implementation(project(":starter:spring-boot-starter-actuator"))
implementation(project(":starter:spring-boot-starter-jersey"))
implementation(project(":starter:spring-boot-starter-tomcat"))
runtimeOnly("jakarta.xml.bind:jakarta.xml.bind-api")
testImplementation(project(":starter:spring-boot-starter-restclient"))
testImplementation(project(":starter:spring-boot-starter-test"))
}

View File

@ -1,39 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.springframework.stereotype.Component;
@Component
@Path("/hello")
public class Endpoint {
private final Service service;
public Endpoint(Service service) {
this.service = service;
}
@GET
public String message() {
return "Hello " + this.service.message();
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
register(ReverseEndpoint.class);
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import org.springframework.stereotype.Component;
@Component
@Path("/reverse")
public class ReverseEndpoint {
@GET
public String reverse(@QueryParam("input") @NotNull String input) {
return new StringBuilder(input).reverse().toString();
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class SampleJerseyApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
new SampleJerseyApplication()
.configure(new SpringApplicationBuilder(SampleJerseyApplication.class)
.applicationStartup(new BufferingApplicationStartup(2048)))
.run(args);
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Service {
@Value("${message:World}")
@SuppressWarnings("NullAway.Init")
private String msg;
public String message() {
return this.msg;
}
}

View File

@ -1,20 +0,0 @@
/*
* Copyright 2012-present 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.
*/
@NullMarked
package smoketest.jersey;
import org.jspecify.annotations.NullMarked;

View File

@ -1,3 +0,0 @@
management.endpoints.web.exposure.include=*
management.endpoints.jackson.isolated-object-mapper=true
spring.jackson.visibility.field=any

View File

@ -1,62 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "logging.level.root=debug")
abstract class AbstractJerseyApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
void reverse() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/reverse?input=olleh", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).isEqualTo("hello");
}
@Test
void validation() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/reverse", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
}
@Test
void actuatorStatus() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/actuator/health", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).isEqualTo("{\"status\":\"UP\"}");
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.junit.jupiter.api.Test;
import smoketest.jersey.AbstractJerseyManagementPortTests.ResourceConfigConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.web.server.test.LocalManagementPort;
import org.springframework.boot.web.server.test.LocalServerPort;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Base class for integration tests for Jersey using separate management and main service
* ports.
*
* @author Madhura Bhave
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "management.server.port=0")
@Import(ResourceConfigConfiguration.class)
class AbstractJerseyManagementPortTests {
@LocalServerPort
private int port;
@LocalManagementPort
private int managementPort;
@Autowired
private TestRestTemplate testRestTemplate;
@Test
void resourceShouldBeAvailableOnMainPort() {
ResponseEntity<String> entity = this.testRestTemplate.getForEntity("http://localhost:" + this.port + "/test",
String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("test");
}
@Test
void resourceShouldNotBeAvailableOnManagementPort() {
ResponseEntity<String> entity = this.testRestTemplate
.getForEntity("http://localhost:" + this.managementPort + "/test", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
}
@Test
void actuatorShouldBeAvailableOnManagementPort() {
ResponseEntity<String> entity = this.testRestTemplate
.getForEntity("http://localhost:" + this.managementPort + "/actuator/health", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
void actuatorShouldNotBeAvailableOnMainPort() {
ResponseEntity<String> entity = this.testRestTemplate
.getForEntity("http://localhost:" + this.port + "/actuator/health", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
}
@TestConfiguration
static class ResourceConfigConfiguration {
@Bean
ResourceConfigCustomizer customizer() {
return (config) -> config.register(TestEndpoint.class);
}
@Path("/test")
public static class TestEndpoint {
@GET
public String test() {
return "test";
}
}
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.boot.test.context.SpringBootContextLoader;
class ApplicationStartupSpringBootContextLoader extends SpringBootContextLoader {
@Override
protected SpringApplication getSpringApplication() {
SpringApplication application = new SpringApplication();
application.setApplicationStartup(new BufferingApplicationStartup(1024));
return application;
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.test.LocalManagementPort;
import org.springframework.boot.web.server.test.LocalServerPort;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ContextConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test for Jersey actuator when not using an isolated {@link ObjectMapper}.
*
* @author Phillip Webb
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = "management.endpoints.jackson.isolated-object-mapper=false")
@ContextConfiguration(loader = ApplicationStartupSpringBootContextLoader.class)
class JerseyActuatorIsolatedObjectMapperFalseTests {
@LocalServerPort
private int port;
@LocalManagementPort
private int managementPort;
@Autowired
private TestRestTemplate testRestTemplate;
@Test
void resourceShouldBeAvailableOnMainPort() {
ResponseEntity<String> entity = this.testRestTemplate
.getForEntity("http://localhost:" + this.port + "/actuator/startup", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
assertThat(entity.getBody())
.contains("Java 8 date/time type `java.time.Clock$SystemClock` not supported by default");
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.test.LocalManagementPort;
import org.springframework.boot.web.server.test.LocalServerPort;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ContextConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test for Jersey actuator when using an isolated {@link ObjectMapper}.
*
* @author Phillip Webb
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = "management.endpoints.jackson.isolated-object-mapper=true")
@ContextConfiguration(loader = ApplicationStartupSpringBootContextLoader.class)
class JerseyActuatorIsolatedObjectMapperTrueTests {
@LocalServerPort
private int port;
@LocalManagementPort
private int managementPort;
@Autowired
private TestRestTemplate testRestTemplate;
@Test
void resourceShouldBeAvailableOnMainPort() {
ResponseEntity<String> entity = this.testRestTemplate
.getForEntity("http://localhost:" + this.port + "/actuator/startup", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("\"timeline\":");
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.test.LocalManagementPort;
import org.springframework.boot.web.server.test.LocalServerPort;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for separate management and main service ports with custom
* application path.
*
* @author Madhura Bhave
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = { "management.server.port=0", "spring.jersey.application-path=/app" })
class JerseyApplicationPathAndManagementPortTests {
@LocalServerPort
private int port;
@LocalManagementPort
private int managementPort;
@Autowired
private TestRestTemplate testRestTemplate;
@Test
void applicationPathShouldNotAffectActuators() {
ResponseEntity<String> entity = this.testRestTemplate
.getForEntity("http://localhost:" + this.managementPort + "/actuator/health", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
}
}

View File

@ -1,54 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.test.LocalManagementPort;
import org.springframework.boot.web.server.test.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for separate management and main service ports with empty base path
* for endpoints.
*
* @author HaiTao Zhang
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = { "management.server.port=0", "management.endpoints.web.base-path=/" })
class JerseyDifferentPortSampleActuatorApplicationTests {
@LocalManagementPort
private int managementPort;
@Test
void linksEndpointShouldBeAvailable() {
ResponseEntity<String> entity = new TestRestTemplate("user", getPassword())
.getForEntity("http://localhost:" + this.managementPort + "/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("\"_links\"");
}
private String getPassword() {
return "password";
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright 2012-present 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 smoketest.jersey;
import org.springframework.test.context.TestPropertySource;
/**
* Smoke tests for Jersey configured as a Filter.
*
* @author Andy Wilkinson
*/
@TestPropertySource(properties = { "spring.jersey.type=filter", "server.servlet.register-default-servlet=true" })
class JerseyFilterApplicationTests extends AbstractJerseyApplicationTests {
}

Some files were not shown because too many files have changed in this diff Show More