Browse Source
Restore support for Jersey now that it supports JAX-RS 4. Closes gh-47967 Co-authored-by: Andy Wilkinson <andy.wilkinson@broadcom.com>pull/47991/head
120 changed files with 7035 additions and 17 deletions
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
[[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[] |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
/* |
||||
* 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 { |
||||
|
||||
} |
||||
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
/* |
||||
* 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 { |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* |
||||
* 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)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* |
||||
* 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"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,172 @@
@@ -0,0 +1,172 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/* |
||||
* 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") |
||||
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-jackson2")) |
||||
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")) |
||||
testFixturesRuntimeOnly(project(":module:spring-boot-jackson2")) |
||||
|
||||
testImplementation(project(":core:spring-boot-test")) |
||||
testImplementation(project(":module:spring-boot-restclient")) |
||||
testImplementation(project(":module:spring-boot-resttestclient")) |
||||
testImplementation(project(":module:spring-boot-tomcat")) |
||||
testImplementation(project(":test-support:spring-boot-test-support")) |
||||
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") |
||||
} |
||||
@ -0,0 +1,362 @@
@@ -0,0 +1,362 @@
|
||||
/* |
||||
* 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<List>}. |
||||
*/ |
||||
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); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
/* |
||||
* 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.health.actuate.endpoint.AdditionalHealthEndpointPath; |
||||
import org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup; |
||||
import org.springframework.boot.health.actuate.endpoint.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(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
/* |
||||
* 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); |
||||
|
||||
} |
||||
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
/* |
||||
* 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; |
||||
@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
|
||||
/* |
||||
* 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("/*"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
/* |
||||
* 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 + "/*"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,233 @@
@@ -0,0 +1,233 @@
|
||||
/* |
||||
* 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 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.jackson2.autoconfigure.Jackson2AutoConfiguration" }) |
||||
@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(com.fasterxml.jackson.databind.ObjectMapper.class) |
||||
static class Jackson2ResourceConfigCustomizerConfiguration { |
||||
|
||||
@Bean |
||||
ResourceConfigCustomizer jacksonResourceConfigCustomizer( |
||||
com.fasterxml.jackson.databind.ObjectMapper objectMapper) { |
||||
return (ResourceConfig config) -> { |
||||
config.register(JacksonFeature.class); |
||||
config.register(new ObjectMapperContextResolver(objectMapper), ContextResolver.class); |
||||
}; |
||||
} |
||||
|
||||
@Configuration(proxyBeanMethods = false) |
||||
@ConditionalOnClass({ com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector.class, |
||||
XmlElement.class }) |
||||
static class JaxbJackson2ObjectMapperCustomizerConfiguration { |
||||
|
||||
@Autowired |
||||
void addJaxbAnnotationIntrospector(com.fasterxml.jackson.databind.ObjectMapper objectMapper) { |
||||
com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector jaxbAnnotationIntrospector = new com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector( |
||||
objectMapper.getTypeFactory()); |
||||
objectMapper.setAnnotationIntrospectors( |
||||
createPair(objectMapper.getSerializationConfig(), jaxbAnnotationIntrospector), |
||||
createPair(objectMapper.getDeserializationConfig(), jaxbAnnotationIntrospector)); |
||||
} |
||||
|
||||
private com.fasterxml.jackson.databind.AnnotationIntrospector createPair( |
||||
com.fasterxml.jackson.databind.cfg.MapperConfig<?> config, |
||||
com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector jaxbAnnotationIntrospector) { |
||||
return com.fasterxml.jackson.databind.AnnotationIntrospector.pair(config.getAnnotationIntrospector(), |
||||
jaxbAnnotationIntrospector); |
||||
} |
||||
|
||||
} |
||||
|
||||
private static final class ObjectMapperContextResolver |
||||
implements ContextResolver<com.fasterxml.jackson.databind.ObjectMapper> { |
||||
|
||||
private final com.fasterxml.jackson.databind.ObjectMapper objectMapper; |
||||
|
||||
private ObjectMapperContextResolver(com.fasterxml.jackson.databind.ObjectMapper objectMapper) { |
||||
this.objectMapper = objectMapper; |
||||
} |
||||
|
||||
@Override |
||||
public com.fasterxml.jackson.databind.ObjectMapper getContext(Class<?> type) { |
||||
return this.objectMapper; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,129 @@
@@ -0,0 +1,129 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/* |
||||
* 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); |
||||
|
||||
} |
||||
@ -0,0 +1,148 @@
@@ -0,0 +1,148 @@
|
||||
/* |
||||
* 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.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.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.health.actuate.endpoint.HealthEndpoint; |
||||
import org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups; |
||||
import org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration; |
||||
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)); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
/* |
||||
* 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; |
||||
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
/* |
||||
* 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()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,242 @@
@@ -0,0 +1,242 @@
|
||||
/* |
||||
* 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.EndpointJackson2ObjectMapper; |
||||
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.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.health.actuate.endpoint.HealthEndpoint; |
||||
import org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups; |
||||
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(EndpointJackson2ObjectMapper.class) |
||||
@SuppressWarnings("removal") |
||||
ResourceConfigCustomizer endpointJackson2ObjectMapperResourceConfigCustomizer( |
||||
org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper endpointJackson2ObjectMapper) { |
||||
return (config) -> config.register( |
||||
new EndpointJackson2ObjectMapperContextResolver(endpointJackson2ObjectMapper), 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. |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Priority(Priorities.USER - 100) |
||||
private static final class EndpointJackson2ObjectMapperContextResolver implements ContextResolver<ObjectMapper> { |
||||
|
||||
private final org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper mapper; |
||||
|
||||
private EndpointJackson2ObjectMapperContextResolver( |
||||
org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper mapper) { |
||||
this.mapper = mapper; |
||||
} |
||||
|
||||
@Override |
||||
public @Nullable ObjectMapper getContext(Class<?> type) { |
||||
return OperationResponseBody.class.isAssignableFrom(type) ? this.mapper.get() : null; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
/* |
||||
* 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); |
||||
|
||||
} |
||||
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
/* |
||||
* 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; |
||||
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
/* |
||||
* 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.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.MaximumAllowableTagsMeterFilter; |
||||
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) |
||||
MaximumAllowableTagsMeterFilter jerseyMetricsUriTagFilter(MetricsProperties metricsProperties) { |
||||
String meterNamePrefix = this.observationProperties.getHttp().getServer().getRequests().getName(); |
||||
int maxUriTags = metricsProperties.getWeb().getServer().getMaxUriTags(); |
||||
return new MaximumAllowableTagsMeterFilter(meterNamePrefix, "uri", maxUriTags); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
/* |
||||
* 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; |
||||
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
/* |
||||
* 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; |
||||
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
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 |
||||
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration |
||||
org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web.HealthEndpointJerseyExtensionAutoConfiguration |
||||
org.springframework.boot.jersey.autoconfigure.metrics.JerseyServerMetricsAutoConfiguration |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
/* |
||||
* 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/*"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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) |
||||
@AutoConfigureTestRestTemplate |
||||
@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; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,102 @@
@@ -0,0 +1,102 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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" }) |
||||
@AutoConfigureTestRestTemplate |
||||
@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 { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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" }) |
||||
@AutoConfigureTestRestTemplate |
||||
@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 { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
/* |
||||
* 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 { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,129 @@
@@ -0,0 +1,129 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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.jackson2.default-property-inclusion=non_null") |
||||
@AutoConfigureTestRestTemplate |
||||
@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; |
||||
} |
||||
|
||||
} |
||||
|
||||
@SuppressWarnings("removal") |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
@Configuration |
||||
@Import({ TomcatServletWebServerAutoConfiguration.class, |
||||
org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class, |
||||
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class }) |
||||
protected @interface MinimalWebConfiguration { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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") |
||||
@AutoConfigureTestRestTemplate |
||||
@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 { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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) |
||||
@AutoConfigureTestRestTemplate |
||||
@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 { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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" }) |
||||
@AutoConfigureTestRestTemplate |
||||
@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 { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,98 @@
@@ -0,0 +1,98 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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) |
||||
@AutoConfigureTestRestTemplate |
||||
@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 { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,139 @@
@@ -0,0 +1,139 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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.jackson2.default-property-inclusion:non-null") |
||||
@AutoConfigureTestRestTemplate |
||||
@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 |
||||
@SuppressWarnings("removal") |
||||
@Import({ TomcatServletWebServerAutoConfiguration.class, |
||||
org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class, |
||||
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class }) |
||||
protected @interface MinimalWebConfiguration { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,111 @@
@@ -0,0 +1,111 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
}; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,172 @@
@@ -0,0 +1,172 @@
|
||||
/* |
||||
* 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.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 |
||||
@SuppressWarnings("removal") |
||||
void whenJaxbIsAvailableTheObjectMapperIsCustomizedWithAnAnnotationIntrospector() { |
||||
this.contextRunner |
||||
.withConfiguration(AutoConfigurations |
||||
.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class)) |
||||
.run((context) -> { |
||||
ObjectMapper objectMapper = context.getBean(ObjectMapper.class); |
||||
assertThat(objectMapper.getSerializationConfig() |
||||
.getAnnotationIntrospector() |
||||
.allIntrospectors() |
||||
.stream() |
||||
.filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).hasSize(1); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
@SuppressWarnings("removal") |
||||
void whenJaxbIsNotAvailableTheObjectMapperCustomizationBacksOff() { |
||||
this.contextRunner |
||||
.withConfiguration(AutoConfigurations |
||||
.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.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 |
||||
@SuppressWarnings("removal") |
||||
void whenJacksonJaxbModuleIsNotAvailableTheObjectMapperCustomizationBacksOff() { |
||||
this.contextRunner |
||||
.withConfiguration(AutoConfigurations |
||||
.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.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()); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,98 @@
@@ -0,0 +1,98 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
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.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") |
||||
@AutoConfigureTestRestTemplate |
||||
@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 { |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
/* |
||||
* 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.endpoint.web.WebEndpointsSupplier; |
||||
import org.springframework.boot.autoconfigure.AutoConfigurations; |
||||
import org.springframework.boot.health.actuate.endpoint.HealthEndpoint; |
||||
import org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension; |
||||
import org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration; |
||||
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()); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,192 @@
@@ -0,0 +1,192 @@
|
||||
/* |
||||
* 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.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 { |
||||
|
||||
@SuppressWarnings("removal") |
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner( |
||||
AnnotationConfigServletWebServerApplicationContext::new) |
||||
.withConfiguration( |
||||
AutoConfigurations.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.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 { |
||||
} |
||||
|
||||
}); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,227 @@
@@ -0,0 +1,227 @@
|
||||
/* |
||||
* 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.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 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"); |
||||
} |
||||
|
||||
@SuppressWarnings("removal") |
||||
private Class<?>[] getAutoconfigurations(Class<?>... additional) { |
||||
List<Class<?>> autoconfigurations = new ArrayList<>( |
||||
Arrays.asList(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.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 |
||||
org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper endpointJackson2ObjectMapper() { |
||||
SimpleModule module = new SimpleModule(); |
||||
module.addSerializer(String.class, new ReverseStringSerializer()); |
||||
ObjectMapper objectMapper = new ObjectMapper(); |
||||
objectMapper.registerModule(module); |
||||
return () -> objectMapper; |
||||
} |
||||
|
||||
static class ReverseStringSerializer extends StdScalarSerializer<Object> { |
||||
|
||||
ReverseStringSerializer() { |
||||
super(String.class, false); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty(SerializerProvider provider, 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()); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/* |
||||
* 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.integrationtest.AbstractHealthEndpointAdditionalPathIntegrationTests; |
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.AutoConfigurations; |
||||
import org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration; |
||||
import org.springframework.boot.health.autoconfigure.application.DiskSpaceHealthContributorAutoConfiguration; |
||||
import org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration; |
||||
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> { |
||||
|
||||
@SuppressWarnings("removal") |
||||
JerseyHealthEndpointAdditionalPathIntegrationTests() { |
||||
super(new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new) |
||||
.withConfiguration(AutoConfigurations.of( |
||||
org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.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")); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,136 @@
@@ -0,0 +1,136 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
/* |
||||
* 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)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,143 @@
@@ -0,0 +1,143 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
/* |
||||
* 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.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 |
||||
*/ |
||||
@SuppressWarnings("removal") |
||||
@Configuration(proxyBeanMethods = false) |
||||
@ImportAutoConfiguration({ org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.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)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider=\ |
||||
org.springframework.boot.jersey.actuate.endpoint.web.test.JerseyWebEndpointInfrastructureProvider |
||||
@ -0,0 +1,156 @@
@@ -0,0 +1,156 @@
|
||||
/* |
||||
* 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.web.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(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
/* |
||||
* 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-jersey-test")) |
||||
} |
||||
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
/* |
||||
* 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; |
||||
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
management.endpoints.web.exposure.include=* |
||||
management.endpoints.jackson.isolated-object-mapper=true |
||||
spring.jackson2.visibility.field=any |
||||
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseEntity; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
@AutoConfigureTestRestTemplate |
||||
@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\",\"groups\":[\"liveness\",\"readiness\"]}"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,108 @@
@@ -0,0 +1,108 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.test.context.TestConfiguration; |
||||
import org.springframework.boot.test.web.server.LocalManagementPort; |
||||
import org.springframework.boot.test.web.server.LocalServerPort; |
||||
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 |
||||
*/ |
||||
@AutoConfigureTestRestTemplate |
||||
@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"; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |
||||
import org.springframework.boot.test.web.server.LocalManagementPort; |
||||
import org.springframework.boot.test.web.server.LocalServerPort; |
||||
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 |
||||
*/ |
||||
@AutoConfigureTestRestTemplate |
||||
@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); |
||||
System.out.println(entity.getBody()); |
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); |
||||
assertThat(entity.getBody()) |
||||
.contains("Java 8 date/time type `java.time.Clock$SystemClock` not supported by default"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; |
||||
import org.springframework.boot.test.web.server.LocalManagementPort; |
||||
import org.springframework.boot.test.web.server.LocalServerPort; |
||||
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 |
||||
*/ |
||||
@AutoConfigureTestRestTemplate |
||||
@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\":"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.test.web.server.LocalManagementPort; |
||||
import org.springframework.boot.test.web.server.LocalServerPort; |
||||
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 |
||||
*/ |
||||
@AutoConfigureTestRestTemplate |
||||
@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\""); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* 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.resttestclient.TestRestTemplate; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.boot.test.web.server.LocalManagementPort; |
||||
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"; |
||||
} |
||||
|
||||
} |
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue