Restore support for Jersey

Closes gh-28637
This commit is contained in:
Andy Wilkinson
2022-08-08 15:45:20 +01:00
parent fb2f7c1e38
commit ba93e6c0ed
105 changed files with 5974 additions and 18 deletions

View File

@@ -0,0 +1,232 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
import java.util.Collections;
import java.util.EnumSet;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;
import jakarta.ws.rs.ext.ContextResolver;
import jakarta.xml.bind.annotation.XmlElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spring.SpringComponentProvider;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.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.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ConditionalOnMissingFilterBean;
import org.springframework.boot.autoconfigure.web.servlet.DefaultJerseyApplicationPath;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.JerseyApplicationPath;
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 1.2.0
*/
@AutoConfiguration(before = DispatcherServletAutoConfiguration.class, after = JacksonAutoConfiguration.class)
@ConditionalOnClass({ SpringComponentProvider.class, ServletRegistration.class })
@ConditionalOnBean(type = "org.glassfish.jersey.server.ResourceConfig")
@ConditionalOnWebApplication(type = Type.SERVLET)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@EnableConfigurationProperties(JerseyProperties.class)
public class JerseyAutoConfiguration implements ServletContextAware {
private static final Log logger = LogFactory.getLog(JerseyAutoConfiguration.class);
private final JerseyProperties jersey;
private final ResourceConfig config;
public JerseyAutoConfiguration(JerseyProperties jersey, ResourceConfig config,
ObjectProvider<ResourceConfigCustomizer> customizers) {
this.jersey = jersey;
this.config = config;
customizers.orderedStream().forEach((customizer) -> customizer.customize(this.config));
}
@Bean
@ConditionalOnMissingFilterBean(RequestContextFilter.class)
public 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
public JerseyApplicationPath jerseyApplicationPath() {
return new DefaultJerseyApplicationPath(this.jersey.getApplicationPath(), this.config);
}
@Bean
@ConditionalOnMissingBean(name = "jerseyFilterRegistration")
@ConditionalOnProperty(prefix = "spring.jersey", name = "type", havingValue = "filter")
public 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(prefix = "spring.jersey", name = "type", havingValue = "servlet", matchIfMissing = true)
public 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());
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 {
// We need to switch *off* the Jersey WebApplicationInitializer because it
// will try and register a ContextLoaderListener which we don't need
servletContext.setInitParameter("contextConfigLocation", "<NONE>");
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(JacksonFeature.class)
@ConditionalOnSingleCandidate(ObjectMapper.class)
static class JacksonResourceConfigCustomizer {
@Bean
ResourceConfigCustomizer resourceConfigCustomizer(final ObjectMapper objectMapper) {
return (ResourceConfig config) -> {
config.register(JacksonFeature.class);
config.register(new ObjectMapperContextResolver(objectMapper), ContextResolver.class);
};
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JakartaXmlBindAnnotationIntrospector.class, XmlElement.class })
static class JaxbObjectMapperCustomizer {
@Autowired
void addJaxbAnnotationIntrospector(ObjectMapper objectMapper) {
JakartaXmlBindAnnotationIntrospector jaxbAnnotationIntrospector = new JakartaXmlBindAnnotationIntrospector(
objectMapper.getTypeFactory());
objectMapper.setAnnotationIntrospectors(
createPair(objectMapper.getSerializationConfig(), jaxbAnnotationIntrospector),
createPair(objectMapper.getDeserializationConfig(), jaxbAnnotationIntrospector));
}
private AnnotationIntrospector createPair(MapperConfig<?> config,
JakartaXmlBindAnnotationIntrospector jaxbAnnotationIntrospector) {
return AnnotationIntrospector.pair(config.getAnnotationIntrospector(), jaxbAnnotationIntrospector);
}
}
private static final class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
private ObjectMapperContextResolver(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public ObjectMapper getContext(Class<?> type) {
return this.objectMapper;
}
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* {@link ConfigurationProperties @ConfigurationProperties} for Jersey.
*
* @author Dave Syer
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 1.2.0
*/
@ConfigurationProperties(prefix = "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 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 String getApplicationPath() {
return this.applicationPath;
}
public void setApplicationPath(String applicationPath) {
this.applicationPath = applicationPath;
}
public enum Type {
SERVLET, FILTER
}
public static class Filter {
/**
* Jersey filter chain order.
*/
private int order;
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
}
public static class Servlet {
/**
* Load on startup priority of the Jersey servlet.
*/
private int loadOnStartup = -1;
public int getLoadOnStartup() {
return this.loadOnStartup;
}
public void setLoadOnStartup(int loadOnStartup) {
this.loadOnStartup = loadOnStartup;
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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 1.4.0
*/
@FunctionalInterface
public interface ResourceConfigCustomizer {
/**
* Customize the resource config.
* @param config the {@link ResourceConfig} to customize
*/
void customize(ResourceConfig config);
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2022 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.
*/
package org.springframework.boot.autoconfigure.jersey;

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2012-2022 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.autoconfigure.web.servlet;
import jakarta.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.autoconfigure.jersey.JerseyProperties;
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 2.1.0
*/
public class DefaultJerseyApplicationPath implements JerseyApplicationPath {
private final String applicationPath;
private final ResourceConfig config;
public DefaultJerseyApplicationPath(String applicationPath, ResourceConfig config) {
this.applicationPath = applicationPath;
this.config = config;
}
@Override
public String getPath() {
return resolveApplicationPath();
}
private String resolveApplicationPath() {
if (StringUtils.hasLength(this.applicationPath)) {
return this.applicationPath;
}
// Jersey doesn't like to be the default servlet, so map to /* as a fallback
return MergedAnnotations.from(this.config.getApplication().getClass(), SearchStrategy.TYPE_HIERARCHY)
.get(ApplicationPath.class).getValue(MergedAnnotation.VALUE, String.class).orElse("/*");
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2012-2022 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.autoconfigure.web.servlet;
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 2.0.7
*/
@FunctionalInterface
public interface JerseyApplicationPath {
/**
* Returns the configured path of the application.
* @return the configured path
*/
String getPath();
/**
* Return a form of the given path that's relative to the Jersey application path.
* @param path the path to make relative
* @return the relative path
*/
default String getRelativePath(String path) {
String prefix = getPrefix();
if (!path.startsWith("/")) {
path = "/" + path;
}
return prefix + path;
}
/**
* Return a cleaned up version of the path that can be used as a prefix for URLs. The
* resulting path will have path will not have a trailing slash.
* @return the prefix
* @see #getRelativePath(String)
*/
default String getPrefix() {
String result = getPath();
int index = result.indexOf('*');
if (index != -1) {
result = result.substring(0, index);
}
if (result.endsWith("/")) {
result = result.substring(0, result.length() - 1);
}
return result;
}
/**
* Return a URL mapping pattern that can be used with a
* {@link ServletRegistrationBean} to map Jersey's servlet.
* @return the path as a servlet URL mapping
*/
default String getUrlMapping() {
String path = getPath();
if (!path.startsWith("/")) {
path = "/" + path;
}
if (path.equals("/")) {
return "/*";
}
if (path.contains("*")) {
return path;
}
if (path.endsWith("/")) {
return path + "*";
}
return path + "/*";
}
}

View File

@@ -1550,6 +1550,10 @@
"level": "error"
}
},
{
"name": "spring.jersey.type",
"defaultValue": "servlet"
},
{
"name": "spring.jpa.hibernate.use-new-id-generator-mappings",
"type": "java.lang.Boolean",

View File

@@ -72,6 +72,7 @@ org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using a custom {@link Application}.
*
* @author Stephane Nicoll
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
class JerseyAutoConfigurationCustomApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/test/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@ApplicationPath("/test")
static class TestApplication extends Application {
}
@Path("/hello")
public static class TestController {
@GET
public String message() {
return "Hello World";
}
}
@Configuration(proxyBeanMethods = false)
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
static class TestConfiguration {
@Configuration(proxyBeanMethods = false)
public class JerseyConfiguration {
@Bean
public TestApplication testApplication() {
return new TestApplication();
}
@Bean
public ResourceConfig conf(TestApplication app) {
ResourceConfig config = ResourceConfig.forApplication(app);
config.register(TestController.class);
return config;
}
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "spring.jersey.type=filter", "server.servlet.context-path=/app",
"server.servlet.register-default-servlet=true" })
@DirtiesContext
class JerseyAutoConfigurationCustomFilterContextPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/rest/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "spring.jersey.type=filter", "server.servlet.register-default-servlet=true" })
@DirtiesContext
class JerseyAutoConfigurationCustomFilterPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/rest/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@ApplicationPath("rest")
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
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({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom ObjectMapper.
*
* @author Eddú Meléndez
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = "spring.jackson.default-property-inclusion=non_null")
@DirtiesContext
class JerseyAutoConfigurationCustomObjectMapperProviderTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> response = this.restTemplate.getForEntity("/rest/message", String.class);
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode());
assertThat("{\"subject\":\"Jersey\"}").isEqualTo(response.getBody());
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/message")
public static class Application extends ResourceConfig {
Application() {
register(Application.class);
}
@GET
public Message message() {
return new Message("Jersey", null);
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
public static class Message {
private String subject;
private String body;
Message(String subject, String body) {
this.subject = subject;
this.body = body;
}
public String getSubject() {
return this.subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return this.body;
}
public void setBody(String body) {
this.body = body;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JacksonAutoConfiguration.class,
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "server.servlet.contextPath=/app")
@DirtiesContext
class JerseyAutoConfigurationCustomServletContextPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/rest/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
class JerseyAutoConfigurationCustomServletPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/rest/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "spring.jersey.type=filter", "server.servlet.register-default-servlet=true" })
@DirtiesContext
class JerseyAutoConfigurationDefaultFilterPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using default servlet paths.
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
class JerseyAutoConfigurationDefaultServletPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} with an ObjectMapper.
*
* @author Eddú Meléndez
* @author Andy Wilkinson
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = "spring.jackson.default-property-inclusion:non-null")
@DirtiesContext
class JerseyAutoConfigurationObjectMapperProviderTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void responseIsSerializedUsingAutoConfiguredObjectMapper() {
ResponseEntity<String> response = this.restTemplate.getForEntity("/rest/message", String.class);
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode());
assertThat(response.getBody()).isEqualTo("{\"subject\":\"Jersey\"}");
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/message")
public static class Application extends ResourceConfig {
Application() {
register(Application.class);
}
@GET
public Message message() {
return new Message("Jersey", null);
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
public static class Message {
private String subject;
private String body;
Message() {
}
Message(String subject, String body) {
this.subject = subject;
this.body = body;
}
public String getSubject() {
return this.subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return this.body;
}
public void setBody(String body) {
this.body = body;
}
@XmlTransient
public String getFoo() {
return "foo";
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JacksonAutoConfiguration.class,
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.jersey.JerseyAutoConfigurationServletContainerTests.Application;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
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.web.embedded.tomcat.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({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
@Import(ContainerConfiguration.class)
@Path("/hello")
@Configuration(proxyBeanMethods = false)
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
}
@Configuration(proxyBeanMethods = false)
static class ContainerConfiguration {
@Bean
TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
Wrapper jerseyServlet = context.createWrapper();
String servletName = Application.class.getName();
jerseyServlet.setName(servletName);
jerseyServlet.setServletClass(ServletContainer.class.getName());
jerseyServlet.setServlet(new ServletContainer());
jerseyServlet.setOverridable(false);
context.addChild(jerseyServlet);
String pattern = UDecoder.URLDecode("/*", StandardCharsets.UTF_8);
context.addServletMappingDecoded(pattern, servletName);
}
};
}
}
}

View File

@@ -0,0 +1,130 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.RequestContextFilter;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration}.
*
* @author Andy Wilkinson
*/
class JerseyAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class))
.withUserConfiguration(ResourceConfigConfiguration.class);
@Test
void requestContextFilterRegistrationIsAutoConfigured() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(FilterRegistrationBean.class);
FilterRegistrationBean<?> registration = context.getBean(FilterRegistrationBean.class);
assertThat(registration.getFilter()).isInstanceOf(RequestContextFilter.class);
});
}
@Test
void whenUserDefinesARequestContextFilterTheAutoConfiguredRegistrationBacksOff() {
this.contextRunner.withUserConfiguration(RequestContextFilterConfiguration.class).run((context) -> {
assertThat(context).doesNotHaveBean(FilterRegistrationBean.class);
assertThat(context).hasSingleBean(RequestContextFilter.class);
});
}
@Test
void whenUserDefinesARequestContextFilterRegistrationTheAutoConfiguredRegistrationBacksOff() {
this.contextRunner.withUserConfiguration(RequestContextFilterRegistrationConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(FilterRegistrationBean.class);
assertThat(context).hasBean("customRequestContextFilterRegistration");
});
}
@Test
void whenJaxbIsAvailableTheObjectMapperIsCustomizedWithAnAnnotationIntrospector() {
this.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class)).run((context) -> {
ObjectMapper objectMapper = context.getBean(ObjectMapper.class);
assertThat(objectMapper.getSerializationConfig().getAnnotationIntrospector().allIntrospectors().stream()
.filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).hasSize(1);
});
}
@Test
void whenJaxbIsNotAvailableTheObjectMapperCustomizationBacksOff() {
this.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader("jakarta.xml.bind.annotation")).run((context) -> {
ObjectMapper objectMapper = context.getBean(ObjectMapper.class);
assertThat(objectMapper.getSerializationConfig().getAnnotationIntrospector().allIntrospectors()
.stream().filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).isEmpty();
});
}
@Test
void whenJacksonJaxbModuleIsNotAvailableTheObjectMapperCustomizationBacksOff() {
this.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(JakartaXmlBindAnnotationIntrospector.class)).run((context) -> {
ObjectMapper objectMapper = context.getBean(ObjectMapper.class);
assertThat(objectMapper.getSerializationConfig().getAnnotationIntrospector().allIntrospectors()
.stream().filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).isEmpty();
});
}
@Configuration(proxyBeanMethods = false)
static class ResourceConfigConfiguration {
@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}
}
@Configuration(proxyBeanMethods = false)
static class RequestContextFilterConfiguration {
@Bean
RequestContextFilter requestContextFilter() {
return new RequestContextFilter();
}
}
@Configuration(proxyBeanMethods = false)
static class RequestContextFilterRegistrationConfiguration {
@Bean
FilterRegistrationBean<RequestContextFilter> customRequestContextFilterRegistration() {
return new FilterRegistrationBean<>(new RequestContextFilter());
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2012-2022 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.autoconfigure.jersey;
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JerseyAutoConfiguration} when using custom application path.
*
* @author Eddú Meléndez
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.jersey.application-path=/api")
@DirtiesContext
class JerseyAutoConfigurationWithoutApplicationPathTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/api/hello", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@MinimalWebConfiguration
@Path("/hello")
public static class Application extends ResourceConfig {
@Value("${message:World}")
private String msg;
Application() {
register(Application.class);
}
@GET
public String message() {
return "Hello " + this.msg;
}
static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class, JerseyAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2012-2022 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.autoconfigure.web.servlet;
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/*");
}
}