├── .gitignore ├── README.md ├── pom.xml ├── spring-boot-resteasy-parent └── pom.xml ├── spring-boot-resteasy ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── boot │ │ │ └── resteasy │ │ │ └── autoconfigure │ │ │ └── ResteasyAutoConfiguration.java │ └── resources │ │ └── META-INF │ │ └── spring.factories │ └── test │ └── java │ └── org │ └── springframework │ └── boot │ └── resteasy │ └── autoconfigure │ └── ResteasyAutoConfigurationTests.java └── spring-boot-sample-resteasy ├── pom.xml └── src ├── main ├── java │ └── sample │ │ └── resteasy │ │ ├── Endpoint.java │ │ └── SampleResteasyApplication.java └── resources │ └── application.properties └── test └── java └── sample └── resteasy └── SampleResteasyApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | target -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project provides RESTEasy auto-configuration for a Spring Boot application. 2 | 3 | # Getting started 4 | 5 | Build this project and install it into your Maven repository: 6 | 7 | ``` 8 | $ mvn install 9 | ``` 10 | 11 | You should then add a dependency on `org.springframework.boot:spring-boot-resteasy:1.0.0.BUILD-SNAPSHOT` 12 | in your application's `build.gradle` or `pom.xml`. 13 | 14 | Now create a Spring Boot application with auto-configuration and component scanning enabled: 15 | 16 | ```java 17 | import org.springframework.boot.SpringApplication; 18 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 19 | import org.springframework.context.annotation.ComponentScan; 20 | 21 | @ComponentScan 22 | @EnableAutoConfiguration 23 | public class Application { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(Application.class, args); 27 | } 28 | 29 | } 30 | ``` 31 | 32 | Next, create a REST endpoint Spring bean annotated using JAX-RS. For example: 33 | 34 | ```java 35 | import javax.ws.rs.GET; 36 | import javax.ws.rs.Path; 37 | 38 | import org.springframework.stereotype.Component; 39 | 40 | @Component 41 | @Path("/hello") 42 | public class Endpoint { 43 | 44 | private String msg; 45 | 46 | @GET 47 | public String message() { 48 | return "Hello " + msg; 49 | } 50 | 51 | } 52 | ``` 53 | 54 | That's it! Since `Endpoint` is a Spring `@Component` its lifecycle is managed by Spring and you can 55 | use `@Autowired` dependencies and inject external configuration with `@Value`. Refer to 56 | `spring-boot-sample-resteasy` for a detailed example. It's an executable jar that can be built with 57 | `mvn package` and run with `java -jar`. 58 | 59 | # Limitations 60 | 61 | There's [a bug][1] in RESTEasy 3.0.10.Final that breaks its integration with Spring. The latest working 62 | version of RESTEasy is 3.0.9.Final. 63 | 64 | [1]: https://github.com/resteasy/Resteasy/pull/615 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.springframework.boot 7 | spring-boot-parent 8 | 1.2.1.RELEASE 9 | 10 | 11 | spring-boot-resteasy-build 12 | 1.0.0.BUILD-SNAPSHOT 13 | pom 14 | Spring Boot RESTEasy build 15 | Spring Boot RESTEasy build 16 | 17 | 18 | 3.0.0 19 | 20 | 21 | 22 | ${basedir} 23 | 24 | 25 | 26 | spring-boot-resteasy 27 | spring-boot-resteasy-parent 28 | spring-boot-sample-resteasy 29 | 30 | 31 | -------------------------------------------------------------------------------- /spring-boot-resteasy-parent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 1.2.1.RELEASE 10 | 11 | 12 | 13 | spring-boot-resteasy-parent 14 | 1.0.0.BUILD-SNAPSHOT 15 | pom 16 | Spring Boot RESTEasy parent 17 | Spring Boot RESTEasy parent 18 | 19 | 20 | 1.6 21 | 3.0.9.Final 22 | 23 | 24 | 25 | 26 | 27 | org.jboss.resteasy 28 | resteasy-spring 29 | ${resteasy.version} 30 | 31 | 32 | 33 | 34 | http://spring.io 35 | 36 | Pivotal 37 | http://spring.io 38 | 39 | 40 | 41 | Apache 2.0 42 | http://www.apache.org/licenses/LICENSE-2.0.txt 43 | 44 | 45 | 46 | 47 | http://github.com/wilkinsona/spring-boot-resteasy 48 | scm:git:git://github.com/wilkinsona/spring-boot-resteasy.git 49 | scm:git:ssh://git@github.com/wilkinsona/spring-boot-resteasy.git 50 | 51 | 52 | 53 | 54 | wilkinsona 55 | Andy Wilkinson 56 | awilkinson@pivotal.io 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /spring-boot-resteasy/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-resteasy-parent 9 | 1.0.0.BUILD-SNAPSHOT 10 | ../spring-boot-resteasy-parent 11 | 12 | 13 | spring-boot-resteasy 14 | Spring Boot RESTEasy 15 | Spring Boot auto-configuration for RESTEasy 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter 21 | 22 | 23 | org.springframework 24 | spring-webmvc 25 | 26 | 27 | org.jboss.resteasy 28 | resteasy-spring 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-web 33 | test 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | test 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /spring-boot-resteasy/src/main/java/org/springframework/boot/resteasy/autoconfigure/ResteasyAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.boot.resteasy.autoconfigure; 18 | 19 | import org.jboss.resteasy.plugins.spring.SpringBeanProcessor; 20 | import org.jboss.resteasy.spi.ResteasyDeployment; 21 | import org.jboss.resteasy.spi.ResteasyProviderFactory; 22 | import org.jboss.resteasy.springmvc.ResteasyHandlerAdapter; 23 | import org.jboss.resteasy.springmvc.ResteasyHandlerMapping; 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 26 | import org.springframework.boot.context.properties.ConfigurationProperties; 27 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 28 | import org.springframework.context.annotation.Bean; 29 | import org.springframework.context.annotation.Configuration; 30 | import org.springframework.core.Ordered; 31 | 32 | @ConditionalOnClass(ResteasyHandlerMapping.class) 33 | @EnableConfigurationProperties 34 | @Configuration 35 | public class ResteasyAutoConfiguration { 36 | 37 | @ConditionalOnMissingBean(ResteasyDeployment.class) 38 | @ConfigurationProperties(prefix="resteasy.deployment") 39 | @Bean(initMethod="start", destroyMethod="stop") 40 | public ResteasyDeployment resteasyDeployment(final SpringBeanProcessor springBeanProcessor) { 41 | ResteasyDeployment resteasyDeployment = new ResteasyDeployment() { 42 | public void start() { 43 | super.start(); 44 | if (springBeanProcessor.getRegistry() == null) { 45 | springBeanProcessor.setRegistry(this.getRegistry()); 46 | } 47 | } 48 | }; 49 | resteasyDeployment.setProviderFactory(springBeanProcessor.getProviderFactory()); 50 | return resteasyDeployment; 51 | } 52 | 53 | @ConditionalOnMissingBean(SpringBeanProcessor.class) 54 | @Bean 55 | public SpringBeanProcessor springBeanProcessor() { 56 | SpringBeanProcessor springBeanProcessor = new SpringBeanProcessor(); 57 | springBeanProcessor.setProviderFactory(new ResteasyProviderFactory()); 58 | return springBeanProcessor; 59 | } 60 | 61 | @ConditionalOnMissingBean(ResteasyHandlerMapping.class) 62 | @Bean 63 | public ResteasyHandlerMapping resteasyHandlerMapper(ResteasyDeployment deployment) { 64 | ResteasyHandlerMapping handlerMapping = new ResteasyHandlerMapping(deployment); 65 | handlerMapping.setOrder(Ordered.LOWEST_PRECEDENCE - 10); 66 | return handlerMapping; 67 | } 68 | 69 | @ConditionalOnMissingBean(ResteasyHandlerAdapter.class) 70 | @Bean 71 | public ResteasyHandlerAdapter resteasyHandlerAdapter(ResteasyDeployment deployment) { 72 | return new ResteasyHandlerAdapter(deployment); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /spring-boot-resteasy/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | org.springframework.boot.resteasy.autoconfigure.ResteasyAutoConfiguration -------------------------------------------------------------------------------- /spring-boot-resteasy/src/test/java/org/springframework/boot/resteasy/autoconfigure/ResteasyAutoConfigurationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.boot.resteasy.autoconfigure; 18 | 19 | import static org.junit.Assert.assertTrue; 20 | 21 | import org.jboss.resteasy.spi.ResteasyDeployment; 22 | import org.jboss.resteasy.springmvc.ResteasyHandlerAdapter; 23 | import org.jboss.resteasy.springmvc.ResteasyHandlerMapping; 24 | import org.junit.After; 25 | import org.junit.Test; 26 | import org.springframework.boot.test.EnvironmentTestUtils; 27 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 28 | 29 | public class ResteasyAutoConfigurationTests { 30 | 31 | private AnnotationConfigApplicationContext context; 32 | 33 | @After 34 | public void tearDown() { 35 | if (this.context != null) { 36 | this.context.close(); 37 | } 38 | } 39 | 40 | @Test 41 | public void defaultBeanCreation() { 42 | this.context = new AnnotationConfigApplicationContext(ResteasyAutoConfiguration.class); 43 | 44 | this.context.getBean(ResteasyDeployment.class); 45 | this.context.getBean(ResteasyHandlerAdapter.class); 46 | this.context.getBean(ResteasyHandlerMapping.class); 47 | } 48 | 49 | @Test 50 | public void customizedDeploymentConfiguration() { 51 | this.context = new AnnotationConfigApplicationContext(); 52 | this.context.register(ResteasyAutoConfiguration.class); 53 | EnvironmentTestUtils.addEnvironment(this.context, "resteasy.deployment.async_job_service_enabled:true"); 54 | this.context.refresh(); 55 | 56 | ResteasyDeployment deployment = this.context.getBean(ResteasyDeployment.class); 57 | assertTrue(deployment.isAsyncJobServiceEnabled()); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /spring-boot-sample-resteasy/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 1.2.1.RELEASE 10 | 11 | 12 | 13 | spring-boot-sample-resteasy 14 | 1.0.0.BUILD-SNAPSHOT 15 | Spring Boot RESTEasy sample 16 | Spring Boot RESTEasy sample 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-resteasy 22 | 1.0.0.BUILD-SNAPSHOT 23 | 24 | 25 | org.jboss.resteasy 26 | resteasy-spring 27 | 3.0.9.Final 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-web 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | 40 | 41 | sample.resteasy.SampleResteasyApplication 42 | 1.6 43 | 44 | 45 | -------------------------------------------------------------------------------- /spring-boot-sample-resteasy/src/main/java/sample/resteasy/Endpoint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package sample.resteasy; 18 | 19 | import javax.ws.rs.GET; 20 | import javax.ws.rs.Path; 21 | 22 | import org.springframework.beans.factory.annotation.Value; 23 | import org.springframework.stereotype.Component; 24 | 25 | @Component 26 | @Path("/hello") 27 | public class Endpoint { 28 | 29 | @Value("${message:World}") 30 | private String msg; 31 | 32 | @GET 33 | public String message() { 34 | return "Hello " + msg; 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /spring-boot-sample-resteasy/src/main/java/sample/resteasy/SampleResteasyApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package sample.resteasy; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 21 | import org.springframework.context.annotation.ComponentScan; 22 | 23 | @ComponentScan 24 | @EnableAutoConfiguration 25 | public class SampleResteasyApplication { 26 | 27 | public static void main(String[] args) { 28 | SpringApplication.run(SampleResteasyApplication.class, args); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /spring-boot-sample-resteasy/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | resteasy.deployment.async_job_service_enabled=true -------------------------------------------------------------------------------- /spring-boot-sample-resteasy/src/test/java/sample/resteasy/SampleResteasyApplicationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package sample.resteasy; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import java.net.URI; 22 | 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.springframework.beans.factory.annotation.Value; 26 | import org.springframework.boot.test.IntegrationTest; 27 | import org.springframework.boot.test.SpringApplicationConfiguration; 28 | import org.springframework.boot.test.TestRestTemplate; 29 | import org.springframework.http.HttpStatus; 30 | import org.springframework.http.ResponseEntity; 31 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 32 | import org.springframework.test.context.web.WebAppConfiguration; 33 | 34 | 35 | @RunWith(SpringJUnit4ClassRunner.class) 36 | @SpringApplicationConfiguration(classes = SampleResteasyApplication.class) 37 | @WebAppConfiguration 38 | @IntegrationTest("server.port:0") 39 | public class SampleResteasyApplicationTests { 40 | 41 | @Value("${local.server.port}") 42 | private int port; 43 | 44 | @Test 45 | public void synchronousRequest() { 46 | ResponseEntity response = new TestRestTemplate() 47 | .getForEntity("http://localhost:" + port + "/hello", String.class); 48 | assertEquals(HttpStatus.OK, response.getStatusCode()); 49 | assertEquals("Hello World", response.getBody()); 50 | 51 | } 52 | 53 | @Test 54 | public void asynchronousRequest() { 55 | TestRestTemplate rest = new TestRestTemplate(); 56 | ResponseEntity response = rest 57 | .getForEntity("http://localhost:" + port + "/hello?asynch=true", String.class); 58 | assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); 59 | 60 | URI jobLocation = response.getHeaders().getLocation(); 61 | 62 | HttpStatus jobStatus = HttpStatus.ACCEPTED; 63 | ResponseEntity jobResponse = null; 64 | 65 | while (jobStatus == HttpStatus.ACCEPTED) { 66 | jobResponse = rest.getForEntity(jobLocation, String.class); 67 | jobStatus = jobResponse.getStatusCode(); 68 | } 69 | 70 | assertEquals(HttpStatus.OK, jobResponse.getStatusCode()); 71 | assertEquals("Hello World", jobResponse.getBody()); 72 | 73 | rest.delete(jobLocation); 74 | 75 | } 76 | 77 | } 78 | --------------------------------------------------------------------------------