From 9d5e4a10623d19daa723c4681a03fdaf2df6c2a1 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 5 May 2014 23:08:32 +0200 Subject: [PATCH 01/11] - added xsd and classes generation - developed countries repository and endpoint - updated readme --- README.adoc | 94 +++++++++++++++++-- complete/build.gradle | 44 +++++++++ complete/pom.xml | 24 +++++ .../main/java/hello/CountriesEndpoint.java | 30 ++++++ .../main/java/hello/CountryRepository.java | 56 +++++++++++ .../main/java/hello/GreetingController.java | 14 --- .../src/main/java/hello/WebServiceConfig.java | 47 ++++++++++ complete/src/main/resources/countries.xsd | 36 +++++++ 8 files changed, 322 insertions(+), 23 deletions(-) create mode 100644 complete/src/main/java/hello/CountriesEndpoint.java create mode 100644 complete/src/main/java/hello/CountryRepository.java delete mode 100644 complete/src/main/java/hello/GreetingController.java create mode 100644 complete/src/main/java/hello/WebServiceConfig.java create mode 100644 complete/src/main/resources/countries.xsd diff --git a/README.adoc b/README.adoc index 629de97..54e2d3b 100644 --- a/README.adoc +++ b/README.adoc @@ -4,21 +4,33 @@ projects: [] --- :spring_version: current :spring_boot_version: 1.0.1.RELEASE +:spring_ws_version: 2.0 :Component: http://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/stereotype/Component.html :Controller: http://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/stereotype/Controller.html :DispatcherServlet: http://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/web/servlet/DispatcherServlet.html :SpringApplication: http://docs.spring.io/spring-boot/docs/{spring_boot_version}/api/org/springframework/boot/SpringApplication.html :ResponseBody: http://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html :EnableAutoConfiguration: http://docs.spring.io/spring-boot/docs/{spring_boot_version}/api/org/springframework/boot/autoconfigure/EnableAutoConfiguration.html +:Endpoint: http://docs.spring.io/spring-ws/sites/{spring_ws_version}/apidocs/org/springframework/ws/server/endpoint/annotation/Endpoint.html +:PayloadRoot: http://docs.spring.io/spring-ws/sites/{spring_ws_version}/apidocs/org/springframework/ws/server/endpoint/annotation/PayloadRoot.html +:RequestPayload: http://docs.spring.io/spring-ws/sites/{spring_ws_version}/apidocs/org/springframework/ws/server/endpoint/annotation/RequestPayload.html +:ResponsePayload: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/server/endpoint/annotation/ResponsePayload.html +:MessageDispatcherServlet: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/transport/http/MessageDispatcherServlet.html +:DefaultMethodEndpointAdapter: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/server/endpoint/adapter/DefaultMethodEndpointAdapter.html +:WebApplicationContext: http://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/web/context/WebApplicationContext.html +:DefaultWsdl11Definition: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/wsdl/wsdl11/DefaultWsdl11Definition.html +:XsdSchema: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/xml/xsd/XsdSchema.html :toc: :icons: font :source-highlighter: prettify :project_id: draft-gs-template -This guide walks you through the process of creating a Spring application. +This guide walks you through the process of creating a SOAP-based web service server with Spring. == What you'll build -You'll build a Spring application. +You will build a server that exposes European countries data using WSDL-based SOAP web service. + +In order to simplify the example we will use hardcoded data for couple of countries only: United Kingdom, Spain and Poland. == What you'll need @@ -48,18 +60,82 @@ include::https://raw.github.com/spring-guides/getting-started-macros/master/spri [[initial]] -== Create a resource controller +== Create XSD -Create a new controller for your Spring application: +Web service domain is defined in XSD file that is later on wrapped with WSDL. Create XSD file describing our domain, which is a service exposing one method returning basic information about requested country: name, population, capital and currency. -`src/main/java/hello/GreetingController.java` -[source,java] +`src/main/resources/countries.xsd` +[source,xml] +---- +include::complete/src/main/resources/countries.xsd[] +---- + +== Generate domain objects based on a XSD + +XSD is just the beginning. The next step is to generate Java classes from it. The right approach is go generate classes during build time using Maven or Gradle plugin. + +Plugin configuration for Maven: + +[source,xml,indent=0] +---- +include::complete/pom.xml[tags=xsd] +---- + +Generated classes are placed in `target/generated-sources/jaxb/` directory. + +To do the same with gradle, you will need the following in your build file: + +[source,java,indent=0] +---- +include::complete/build.gradle[tags=xsd] +---- + +As gradle does not have a JAXB plugin (yet), it involves an ant task, which makes it a bit more complex than in maven. + +In both cases, the JAXB domain object generation process has been wired into the build tool’s lifecycle so there are no extra steps to run. + +== Create countries repository + +In order to provide data to web service, create country repository. In this guide we create dummy country repository implementation with hardcoded data. + +[source,java,indent=0] +---- +include::complete/src/main/java/hello/CountryRepository.java[] +---- + +== Create countries service endpoint + +To create service endpoint, you have to create POJO class and annotate it with Spring WS annotations. + +[source,java,indent=0] +---- +include::complete/src/main/java/hello/CountriesEndpoint.java[] +---- + +When Spring WS receives SOAP message it searches all defined endpoints for methods matching namespace and localPart. An endpoint is created typically by annotating class with the {Endpoint}[`@Endpoint`] annotation. + +In order to route incoming XML message to correct method we use {PayloadRoot}[`@PayloadRoot`] annotation that indicates that all messages with namespace `http://spring.io/guides/gs-soap-service` and containing local name `getCountryRequest` will be routed to this method. + +{RequestPayload}[`@RequestPayload`] indicates that message will be mapped to `request` parameter. + +Analogously, {ResponsePayload}[`@ResponsePayload`] annotation makes Spring WS map returned value to response payload. + +== Configure web service components + +There are 2 efficient ways of configuring Spring WS beans: using XML namespaces or using Java config. In this tutorial we create beans using plain Java. + +Create a new class with Spring WS related beans configuration: + +[source,java,indent=0] ---- -include::complete/src/main/java/hello/GreetingController.java[] +include::complete/src/main/java/hello/WebServiceConfig.java[] ---- -NOTE: The above example does not specify `GET` vs. `PUT`, `POST`, and so forth, because `@RequestMapping` maps all HTTP operations by default. Use `@RequestMapping(method=GET)` to narrow this mapping. +* Spring WS uses different servlet type for handling SOAP messages: {MessageDispatcherServlet}[`MessageDispatcherServlet`]. Because we want to have one application context in whole application we inject {WebApplicationContext}[`WebApplicationContext`] created by Spring Boot into {MessageDispatcherServlet}[`MessageDispatcherServlet`] +* {DefaultMethodEndpointAdapter}[`DefaultMethodEndpointAdapter`] configures annotation driven Spring WS programming model - makes possible to use for example {Endpoint}[`@Endpoint`] annotation +* define bean {DefaultWsdl11Definition}[`DefaultWsdl11Definition`] for exposing WSDL using {XsdSchema}[`XsdSchema`] +It's important to notice that you need to specify bean names for {MessageDispatcherServlet}[`MessageDispatcherServlet`] and {DefaultWsdl11Definition}[`DefaultWsdl11Definition`]. Bean names determine the URL under which web service and generated WSDL file is available. In this case, WSDL will be available under `http://:/ws/countries.wsdl` == Make the application executable @@ -74,7 +150,7 @@ include::complete/src/main/java/hello/Application.java[] The `main()` method defers to the {SpringApplication}[`SpringApplication`] helper class, providing `Application.class` as an argument to its `run()` method. This tells Spring to read the annotation metadata from `Application` and to manage it as a component in the link:/understanding/application-context[Spring application context]. -The `@ComponentScan` annotation tells Spring to search recursively through the `hello` package and its children for classes marked directly or indirectly with Spring's {Component}[`@Component`] annotation. This directive ensures that Spring finds and registers the `GreetingController`, because it is marked with `@Controller`, which in turn is a kind of `@Component` annotation. +The `@ComponentScan` annotation tells Spring to search recursively through the `hello` package and its children for classes marked directly or indirectly with Spring's {Component}[`@Component`] annotation. This directive ensures that Spring finds and registers the `CountryRepository` and `CountriesEndpoint`, because they are marked marked with `@Component` and `@Endpoint`, which in turn is a kind of `@Component` annotation. The {EnableAutoConfiguration}[`@EnableAutoConfiguration`] annotation switches on reasonable default behaviors based on the content of your classpath. For example, because the application depends on the embeddable version of Tomcat (tomcat-embed-core.jar), a Tomcat server is set up and configured with reasonable defaults on your behalf. And because the application also depends on Spring MVC (spring-webmvc.jar), a Spring MVC {DispatcherServlet}[`DispatcherServlet`] is configured and registered for you — no `web.xml` necessary! Auto-configuration is a powerful, flexible mechanism. See the {EnableAutoConfiguration}[API documentation] for further details. diff --git a/complete/build.gradle b/complete/build.gradle index 18bb75e..535f178 100644 --- a/complete/build.gradle +++ b/complete/build.gradle @@ -23,9 +23,53 @@ repositories { maven { url "http://repo.spring.io/libs-milestone" } } +// tag::xsd[] +configurations { + jaxb +} + dependencies { compile("org.springframework.boot:spring-boot-starter-web") + compile("org.springframework.ws:spring-ws-core:2.1.4.RELEASE") + jaxb group: 'com.sun.xml.bind', name: 'jaxb-xjc', version: '2.2.4-1' +} + +task genJaxb { + ext.sourcesDir = "${buildDir}/generated-sources/jaxb" + ext.classesDir = "${buildDir}/classes/jaxb" + ext.schema = "src/main/resources/countries.xsd" + + outputs.dir classesDir + + doLast() { + project.ant { + taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask", + classpath: configurations.jaxb.asPath + mkdir(dir: sourcesDir) + mkdir(dir: classesDir) + + xjc(destdir: sourcesDir, schema: schema) { + arg(value: "-wsdl") + produces(dir: sourcesDir, includes: "**/*.java") + } + + javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true, + debugLevel: "lines,vars,source", + classpath: configurations.jaxb.asPath) { + src(path: sourcesDir) + include(name: "**/*.java") + include(name: "*.java") + } + + copy(todir: classesDir) { + fileset(dir: sourcesDir, erroronmissingdir: false) { + exclude(name: "**/*.java") + } + } + } + } } +// end::xsd[] task wrapper(type: Wrapper) { gradleVersion = '1.11' diff --git a/complete/pom.xml b/complete/pom.xml index ec3697c..679640c 100644 --- a/complete/pom.xml +++ b/complete/pom.xml @@ -18,6 +18,11 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.ws + spring-ws-core + 2.1.4.RELEASE + @@ -36,6 +41,25 @@ org.springframework.boot spring-boot-maven-plugin + + + + org.codehaus.mojo + jaxb2-maven-plugin + 1.6 + + + xjc + + xjc + + + + + ${project.basedir}/src/main/resources/ + + + diff --git a/complete/src/main/java/hello/CountriesEndpoint.java b/complete/src/main/java/hello/CountriesEndpoint.java new file mode 100644 index 0000000..483d3bc --- /dev/null +++ b/complete/src/main/java/hello/CountriesEndpoint.java @@ -0,0 +1,30 @@ +package hello; + +import io.spring.guides.gs_soap_service.GetCountryRequest; +import io.spring.guides.gs_soap_service.GetCountryResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.ws.server.endpoint.annotation.Endpoint; +import org.springframework.ws.server.endpoint.annotation.PayloadRoot; +import org.springframework.ws.server.endpoint.annotation.RequestPayload; +import org.springframework.ws.server.endpoint.annotation.ResponsePayload; + +@Endpoint +public class CountriesEndpoint { + private static final String NAMESPACE_URI = "http://spring.io/guides/gs-soap-service"; + + private CountryRepository countryRepository; + + @Autowired + public CountriesEndpoint(CountryRepository countryRepository) { + this.countryRepository = countryRepository; + } + + @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest") + @ResponsePayload + public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) { + GetCountryResponse response = new GetCountryResponse(); + response.setCountry(countryRepository.findCountry(request.getName())); + + return response; + } +} diff --git a/complete/src/main/java/hello/CountryRepository.java b/complete/src/main/java/hello/CountryRepository.java new file mode 100644 index 0000000..0b1cf46 --- /dev/null +++ b/complete/src/main/java/hello/CountryRepository.java @@ -0,0 +1,56 @@ +package hello; + +import io.spring.guides.gs_soap_service.Country; +import io.spring.guides.gs_soap_service.Currency; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.List; + +@Component +public class CountryRepository { + private static final List countries = new ArrayList(); + + @PostConstruct + public void initData() { + Country spain = new Country(); + spain.setName("Spain"); + spain.setCapital("Madrid"); + spain.setCurrency(Currency.EUR); + spain.setPopulation(100000); + + countries.add(spain); + + Country poland = new Country(); + poland.setName("Poland"); + poland.setCapital("Warsaw"); + poland.setCurrency(Currency.PLN); + poland.setPopulation(200000); + + countries.add(poland); + + Country uk = new Country(); + uk.setName("United Kingdom"); + uk.setCapital("London"); + uk.setCurrency(Currency.GBP); + uk.setPopulation(300000); + + countries.add(uk); + } + + public Country findCountry(String name) { + Assert.notNull(name); + + Country result = null; + + for (Country country : countries) { + if (name.equals(country.getName())) { + result = country; + } + } + + return result; + } +} diff --git a/complete/src/main/java/hello/GreetingController.java b/complete/src/main/java/hello/GreetingController.java deleted file mode 100644 index 3d85f1a..0000000 --- a/complete/src/main/java/hello/GreetingController.java +++ /dev/null @@ -1,14 +0,0 @@ -package hello; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -@Controller -public class GreetingController { - - @RequestMapping("/greeting") - public @ResponseBody String greeting() { - return "Hello World"; - } -} diff --git a/complete/src/main/java/hello/WebServiceConfig.java b/complete/src/main/java/hello/WebServiceConfig.java new file mode 100644 index 0000000..7ba1bed --- /dev/null +++ b/complete/src/main/java/hello/WebServiceConfig.java @@ -0,0 +1,47 @@ +package hello; + +import org.springframework.boot.context.embedded.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.io.ClassPathResource; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter; +import org.springframework.ws.transport.http.MessageDispatcherServlet; +import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; +import org.springframework.xml.xsd.SimpleXsdSchema; +import org.springframework.xml.xsd.XsdSchema; + +@Configuration +public class WebServiceConfig { + @Bean(name = "ws") + public ServletRegistrationBean messageDispatcherServlet(@Lazy WebApplicationContext applicationContext) { + MessageDispatcherServlet servlet = new MessageDispatcherServlet(applicationContext); + servlet.setTransformWsdlLocations(true); + servlet.setTransformSchemaLocations(true); + + ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(servlet, "/ws/*"); + + return servletRegistrationBean; + } + + @Bean + public DefaultMethodEndpointAdapter defaultMethodEndpointAdapter() { + return new DefaultMethodEndpointAdapter(); + } + + @Bean(name = "countries") + public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) { + DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition(); + wsdl11Definition.setPortTypeName("CountriesPort"); + wsdl11Definition.setLocationUri("/countries/"); + wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-soap-service"); + wsdl11Definition.setSchema(countriesSchema); + return wsdl11Definition; + } + + @Bean + public XsdSchema countriesSchema() { + return new SimpleXsdSchema(new ClassPathResource("countries.xsd")); + } +} diff --git a/complete/src/main/resources/countries.xsd b/complete/src/main/resources/countries.xsd new file mode 100644 index 0000000..e3a68e5 --- /dev/null +++ b/complete/src/main/resources/countries.xsd @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e5cd32ab6c9b7f794066afe74ed2df55eb6740e9 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 5 May 2014 23:40:39 +0200 Subject: [PATCH 02/11] - updated testing section - refactored MessageDispatcherServlet creation --- README.adoc | 29 +++++++++++++++++-- complete/build.gradle | 4 +-- .../src/main/java/hello/WebServiceConfig.java | 12 ++++---- initial/build.gradle | 6 ++++ initial/pom.xml | 4 +-- 5 files changed, 41 insertions(+), 14 deletions(-) diff --git a/README.adoc b/README.adoc index 54e2d3b..a62b9e9 100644 --- a/README.adoc +++ b/README.adoc @@ -17,7 +17,7 @@ projects: [] :ResponsePayload: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/server/endpoint/annotation/ResponsePayload.html :MessageDispatcherServlet: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/transport/http/MessageDispatcherServlet.html :DefaultMethodEndpointAdapter: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/server/endpoint/adapter/DefaultMethodEndpointAdapter.html -:WebApplicationContext: http://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/web/context/WebApplicationContext.html +:ApplicationContext: http://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/web/context/ApplicationContext.html :DefaultWsdl11Definition: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/wsdl/wsdl11/DefaultWsdl11Definition.html :XsdSchema: http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/xml/xsd/XsdSchema.html :toc: @@ -131,7 +131,7 @@ Create a new class with Spring WS related beans configuration: include::complete/src/main/java/hello/WebServiceConfig.java[] ---- -* Spring WS uses different servlet type for handling SOAP messages: {MessageDispatcherServlet}[`MessageDispatcherServlet`]. Because we want to have one application context in whole application we inject {WebApplicationContext}[`WebApplicationContext`] created by Spring Boot into {MessageDispatcherServlet}[`MessageDispatcherServlet`] +* Spring WS uses different servlet type for handling SOAP messages: {MessageDispatcherServlet}[`MessageDispatcherServlet`]. It is important to inject and set {ApplicationContext}[`ApplicationContext`] to {MessageDispatcherServlet}[`MessageDispatcherServlet`]. Without that, Spring WS will not detect Spring Beans automatically. * {DefaultMethodEndpointAdapter}[`DefaultMethodEndpointAdapter`] configures annotation driven Spring WS programming model - makes possible to use for example {Endpoint}[`@Endpoint`] annotation * define bean {DefaultWsdl11Definition}[`DefaultWsdl11Definition`] for exposing WSDL using {XsdSchema}[`XsdSchema`] @@ -166,8 +166,31 @@ Logging output is displayed. The service should be up and running within a few s == Test the application -Now that the application is running, you can test it. +Now that the application is running, you can test it. Create a file `request.xml` containing example SOAP request: +[source,xml] +---- +include::complete/request.txt[] +---- + +Execute from command line `curl --header "content-type: text/xml" -d @request.xml "http://localhost:8080/ws/"`. As a result you should see: + +[source,xml] +---- + + + + + + Spain + 100000 + Madrid + EUR + + + + +---- == Summary diff --git a/complete/build.gradle b/complete/build.gradle index 535f178..5dc57e2 100644 --- a/complete/build.gradle +++ b/complete/build.gradle @@ -23,7 +23,6 @@ repositories { maven { url "http://repo.spring.io/libs-milestone" } } -// tag::xsd[] configurations { jaxb } @@ -31,9 +30,10 @@ configurations { dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.ws:spring-ws-core:2.1.4.RELEASE") - jaxb group: 'com.sun.xml.bind', name: 'jaxb-xjc', version: '2.2.4-1' + jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1") } +// tag::xsd[] task genJaxb { ext.sourcesDir = "${buildDir}/generated-sources/jaxb" ext.classesDir = "${buildDir}/classes/jaxb" diff --git a/complete/src/main/java/hello/WebServiceConfig.java b/complete/src/main/java/hello/WebServiceConfig.java index 7ba1bed..10ec129 100644 --- a/complete/src/main/java/hello/WebServiceConfig.java +++ b/complete/src/main/java/hello/WebServiceConfig.java @@ -1,6 +1,7 @@ package hello; import org.springframework.boot.context.embedded.ServletRegistrationBean; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; @@ -15,14 +16,11 @@ @Configuration public class WebServiceConfig { @Bean(name = "ws") - public ServletRegistrationBean messageDispatcherServlet(@Lazy WebApplicationContext applicationContext) { - MessageDispatcherServlet servlet = new MessageDispatcherServlet(applicationContext); - servlet.setTransformWsdlLocations(true); - servlet.setTransformSchemaLocations(true); + public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { + MessageDispatcherServlet servlet = new MessageDispatcherServlet(); + servlet.setApplicationContext(applicationContext); - ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(servlet, "/ws/*"); - - return servletRegistrationBean; + return new ServletRegistrationBean(servlet, "/ws/*"); } @Bean diff --git a/initial/build.gradle b/initial/build.gradle index 18bb75e..472b2d6 100644 --- a/initial/build.gradle +++ b/initial/build.gradle @@ -23,8 +23,14 @@ repositories { maven { url "http://repo.spring.io/libs-milestone" } } +configurations { + jaxb +} + dependencies { compile("org.springframework.boot:spring-boot-starter-web") + compile("org.springframework.ws:spring-ws-core:2.1.4.RELEASE") + jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1") } task wrapper(type: Wrapper) { diff --git a/initial/pom.xml b/initial/pom.xml index ec3697c..f4a67dd 100644 --- a/initial/pom.xml +++ b/initial/pom.xml @@ -29,8 +29,8 @@ - - maven-compiler-plugin + + maven-compiler-plugin org.springframework.boot From d6d3aed5978a46f0a1c5b1ace1580fd6d13b37cd Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 5 May 2014 23:42:45 +0200 Subject: [PATCH 03/11] - updated congratulations section --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index a62b9e9..3162f81 100644 --- a/README.adoc +++ b/README.adoc @@ -194,7 +194,7 @@ Execute from command line `curl --header "content-type: text/xml" -d @request.xm == Summary -Congratulations! You've just developed a Spring application! +Congratulations! You've just developed first Spring WS based SOAP service! All without single line of XML configuration! From 876e93655981caf886558203dd60604e32c1310a Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 5 May 2014 23:46:23 +0200 Subject: [PATCH 04/11] - updated population in countries repository --- README.adoc | 4 ++-- complete/src/main/java/hello/CountryRepository.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.adoc b/README.adoc index 3162f81..84229cd 100644 --- a/README.adoc +++ b/README.adoc @@ -173,7 +173,7 @@ Now that the application is running, you can test it. Create a file `request.xml include::complete/request.txt[] ---- -Execute from command line `curl --header "content-type: text/xml" -d @request.xml "http://localhost:8080/ws/"`. As a result you should see: +Execute from command line `curl --header "content-type: text/xml" -d @request.xml "http://localhost:8080/ws/"`. As a result you should see the response: [source,xml] ---- @@ -183,7 +183,7 @@ Execute from command line `curl --header "content-type: text/xml" -d @request.xm Spain - 100000 + 46704314 Madrid EUR diff --git a/complete/src/main/java/hello/CountryRepository.java b/complete/src/main/java/hello/CountryRepository.java index 0b1cf46..3fe343b 100644 --- a/complete/src/main/java/hello/CountryRepository.java +++ b/complete/src/main/java/hello/CountryRepository.java @@ -19,7 +19,7 @@ public void initData() { spain.setName("Spain"); spain.setCapital("Madrid"); spain.setCurrency(Currency.EUR); - spain.setPopulation(100000); + spain.setPopulation(46704314); countries.add(spain); @@ -27,7 +27,7 @@ public void initData() { poland.setName("Poland"); poland.setCapital("Warsaw"); poland.setCurrency(Currency.PLN); - poland.setPopulation(200000); + poland.setPopulation(38186860); countries.add(poland); @@ -35,7 +35,7 @@ public void initData() { uk.setName("United Kingdom"); uk.setCapital("London"); uk.setCurrency(Currency.GBP); - uk.setPopulation(300000); + uk.setPopulation(63705000); countries.add(uk); } From db0486ce34484faa8d770b4d26ca0afb5189e094 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 5 May 2014 23:57:20 +0200 Subject: [PATCH 05/11] - fixed jaxb configuration for gradle - updated project name --- complete/build.gradle | 15 ++++++++------- complete/pom.xml | 2 +- initial/pom.xml | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/complete/build.gradle b/complete/build.gradle index 5dc57e2..e16ad50 100644 --- a/complete/build.gradle +++ b/complete/build.gradle @@ -14,8 +14,9 @@ apply plugin: 'idea' apply plugin: 'spring-boot' jar { - baseName = 'draft-gs-template' + baseName = 'gs-soap-service' version = '0.1.0' + from genJaxb.classesDir } repositories { @@ -27,12 +28,6 @@ configurations { jaxb } -dependencies { - compile("org.springframework.boot:spring-boot-starter-web") - compile("org.springframework.ws:spring-ws-core:2.1.4.RELEASE") - jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1") -} - // tag::xsd[] task genJaxb { ext.sourcesDir = "${buildDir}/generated-sources/jaxb" @@ -71,6 +66,12 @@ task genJaxb { } // end::xsd[] +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") + compile("org.springframework.ws:spring-ws-core:2.1.4.RELEASE") + jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1") + compile(files(genJaxb.classesDir).builtBy(genJaxb)) +} task wrapper(type: Wrapper) { gradleVersion = '1.11' } diff --git a/complete/pom.xml b/complete/pom.xml index 679640c..1a9eeca 100644 --- a/complete/pom.xml +++ b/complete/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.springframework - draft-gs-template + gs-soap-service 0.1.0 diff --git a/initial/pom.xml b/initial/pom.xml index f4a67dd..dcf8edf 100644 --- a/initial/pom.xml +++ b/initial/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.springframework - draft-gs-template + gs-soap-service 0.1.0 From 7a36a029d3e24e041f41950190a5bc876477dee8 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 6 May 2014 00:21:33 +0200 Subject: [PATCH 06/11] added tags & projects --- README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index 84229cd..91ac2fe 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,6 @@ --- -tags: [] -projects: [] +tags: [SOAP] +projects: [spring-ws] --- :spring_version: current :spring_boot_version: 1.0.1.RELEASE From dd2be504057375d3974362d9774be86ed67f243b Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 6 May 2014 00:31:28 +0200 Subject: [PATCH 07/11] added request.xml for testing web service --- README.adoc | 2 +- test/request.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 test/request.xml diff --git a/README.adoc b/README.adoc index 452a700..5b6d384 100644 --- a/README.adoc +++ b/README.adoc @@ -170,7 +170,7 @@ Now that the application is running, you can test it. Create a file `request.xml [source,xml] ---- -include::complete/request.txt[] +include::complete/test/request.txt[] ---- Execute from command line `curl --header "content-type: text/xml" -d @request.xml "http://localhost:8080/ws/"`. As a result you should see the response: diff --git a/test/request.xml b/test/request.xml new file mode 100644 index 0000000..7d30795 --- /dev/null +++ b/test/request.xml @@ -0,0 +1,8 @@ + + + + + Spain + + + From cb131f61040c1f54d1a63a0803976b6f944ea5dd Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 6 May 2014 00:38:37 +0200 Subject: [PATCH 08/11] objects -> classes --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 5b6d384..36245c6 100644 --- a/README.adoc +++ b/README.adoc @@ -70,7 +70,7 @@ Web service domain is defined in XSD file that is later on wrapped with WSDL. Cr include::complete/src/main/resources/countries.xsd[] ---- -== Generate domain objects based on a XSD +== Generate domain classes based on a XSD XSD is just the beginning. The next step is to generate Java classes from it. The right approach is go generate classes during build time using Maven or Gradle plugin. From 43dbe0717ae0293e471e16a68e1edc08101bf729 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 6 May 2014 13:44:45 +0200 Subject: [PATCH 09/11] - updated readme with setting up Jaxb configuration, adding spring-ws dependency - CountriesEndpoint renamed to CountryEndpoint --- README.adoc | 34 +++++++++++++++---- complete/build.gradle | 25 ++++++++------ complete/pom.xml | 2 ++ ...riesEndpoint.java => CountryEndpoint.java} | 4 +-- initial/build.gradle | 6 ---- 5 files changed, 47 insertions(+), 24 deletions(-) rename complete/src/main/java/hello/{CountriesEndpoint.java => CountryEndpoint.java} (91%) diff --git a/README.adoc b/README.adoc index 36245c6..0f8e64c 100644 --- a/README.adoc +++ b/README.adoc @@ -60,6 +60,21 @@ include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/ [[initial]] +== Add Spring-WS dependency + +Project you create will be based on Spring WS. You need to add dependency to Spring WS in your build file. For Maven: + +[source,xml,indent=0] +---- +include::complete/pom.xml[tags=springws] +---- + +If you use gradle, make sure to have dependency to `spring-ws-core` added: +[source,java] +---- +include::complete/build.gradle[tags=dependencies] +---- + == Create XSD Web service domain is defined in XSD file that is later on wrapped with WSDL. Create XSD file describing our domain, which is a service exposing one method returning basic information about requested country: name, population, capital and currency. @@ -83,7 +98,14 @@ include::complete/pom.xml[tags=xsd] Generated classes are placed in `target/generated-sources/jaxb/` directory. -To do the same with gradle, you will need the following in your build file: +To do the same with gradle, first you need to configure JAXB in your build file: + +[source,java,indent=0] +---- +include::complete/build.gradle[tags=jaxb] +---- + +Next step is to add task `genJaxb` used by gradle to generate Java classes: [source,java,indent=0] ---- @@ -94,7 +116,7 @@ As gradle does not have a JAXB plugin (yet), it involves an ant task, which make In both cases, the JAXB domain object generation process has been wired into the build tool’s lifecycle so there are no extra steps to run. -== Create countries repository +== Create country repository In order to provide data to web service, create country repository. In this guide we create dummy country repository implementation with hardcoded data. @@ -103,13 +125,13 @@ In order to provide data to web service, create country repository. In this guid include::complete/src/main/java/hello/CountryRepository.java[] ---- -== Create countries service endpoint +== Create country service endpoint To create service endpoint, you have to create POJO class and annotate it with Spring WS annotations. [source,java,indent=0] ---- -include::complete/src/main/java/hello/CountriesEndpoint.java[] +include::complete/src/main/java/hello/CountryEndpoint.java[] ---- When Spring WS receives SOAP message it searches all defined endpoints for methods matching namespace and localPart. An endpoint is created typically by annotating class with the {Endpoint}[`@Endpoint`] annotation. @@ -122,7 +144,7 @@ Analogously, {ResponsePayload}[`@ResponsePayload`] annotation makes Spring WS ma == Configure web service components -There are 2 efficient ways of configuring Spring WS beans: using XML namespaces or using Java config. In this tutorial we create beans using plain Java. +There are two efficient ways of configuring Spring WS beans: using XML namespaces or using Java config. In this tutorial we create beans using plain Java. Create a new class with Spring WS related beans configuration: @@ -170,7 +192,7 @@ Now that the application is running, you can test it. Create a file `request.xml [source,xml] ---- -include::complete/test/request.txt[] +include::test/request.xml[] ---- Execute from command line `curl --header "content-type: text/xml" -d @request.xml "http://localhost:8080/ws/"`. As a result you should see the response: diff --git a/complete/build.gradle b/complete/build.gradle index 6189832..50a5d2c 100644 --- a/complete/build.gradle +++ b/complete/build.gradle @@ -13,21 +13,11 @@ apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'spring-boot' -jar { - baseName = 'gs-soap-service' - version = '0.1.0' - from genJaxb.classesDir -} - repositories { mavenCentral() maven { url "http://repo.spring.io/libs-milestone" } } -configurations { - jaxb -} - // tag::xsd[] task genJaxb { ext.sourcesDir = "${buildDir}/generated-sources/jaxb" @@ -66,12 +56,27 @@ task genJaxb { } // end::xsd[] +// tag::jaxb[] +configurations { + jaxb +} + +jar { + baseName = 'gs-soap-service' + version = '0.1.0' + from genJaxb.classesDir +} + +// tag::dependencies[] dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.ws:spring-ws-core:2.1.4.RELEASE") jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1") compile(files(genJaxb.classesDir).builtBy(genJaxb)) } +// end::dependencies[] +// end::jaxb[] + task wrapper(type: Wrapper) { gradleVersion = '1.11' } diff --git a/complete/pom.xml b/complete/pom.xml index ec8ba86..8d91774 100644 --- a/complete/pom.xml +++ b/complete/pom.xml @@ -18,11 +18,13 @@ org.springframework.boot spring-boot-starter-web + org.springframework.ws spring-ws-core 2.1.4.RELEASE + diff --git a/complete/src/main/java/hello/CountriesEndpoint.java b/complete/src/main/java/hello/CountryEndpoint.java similarity index 91% rename from complete/src/main/java/hello/CountriesEndpoint.java rename to complete/src/main/java/hello/CountryEndpoint.java index 483d3bc..5aff9b9 100644 --- a/complete/src/main/java/hello/CountriesEndpoint.java +++ b/complete/src/main/java/hello/CountryEndpoint.java @@ -9,13 +9,13 @@ import org.springframework.ws.server.endpoint.annotation.ResponsePayload; @Endpoint -public class CountriesEndpoint { +public class CountryEndpoint { private static final String NAMESPACE_URI = "http://spring.io/guides/gs-soap-service"; private CountryRepository countryRepository; @Autowired - public CountriesEndpoint(CountryRepository countryRepository) { + public CountryEndpoint(CountryRepository countryRepository) { this.countryRepository = countryRepository; } diff --git a/initial/build.gradle b/initial/build.gradle index 77eccec..d155b12 100644 --- a/initial/build.gradle +++ b/initial/build.gradle @@ -23,14 +23,8 @@ repositories { maven { url "http://repo.spring.io/libs-milestone" } } -configurations { - jaxb -} - dependencies { compile("org.springframework.boot:spring-boot-starter-web") - compile("org.springframework.ws:spring-ws-core:2.1.4.RELEASE") - jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1") } task wrapper(type: Wrapper) { From 9cb39fad448d6da0703b042723791279181f1023 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 6 May 2014 18:41:28 +0200 Subject: [PATCH 10/11] - removed "draft" from build.gradle and tutorial - "we" -> "you" --- README.adoc | 20 ++++++++++---------- initial/build.gradle | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.adoc b/README.adoc index 0f8e64c..e1f7729 100644 --- a/README.adoc +++ b/README.adoc @@ -23,14 +23,14 @@ projects: [spring-ws] :toc: :icons: font :source-highlighter: prettify -:project_id: draft-gs-template +:project_id: gs-soap-service This guide walks you through the process of creating a SOAP-based web service server with Spring. == What you'll build You will build a server that exposes European countries data using WSDL-based SOAP web service. -In order to simplify the example we will use hardcoded data for couple of countries only: United Kingdom, Spain and Poland. +In order to simplify the example you will use hardcoded data for couple of countries only: United Kingdom, Spain and Poland. == What you'll need @@ -51,7 +51,7 @@ include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/ `build.gradle` // AsciiDoc source formatting doesn't support groovy, so using java instead -[source,java] +[source,java,indent=0] ---- include::initial/build.gradle[] ---- @@ -70,7 +70,7 @@ include::complete/pom.xml[tags=springws] ---- If you use gradle, make sure to have dependency to `spring-ws-core` added: -[source,java] +[source,java,indent=0] ---- include::complete/build.gradle[tags=dependencies] ---- @@ -80,7 +80,7 @@ include::complete/build.gradle[tags=dependencies] Web service domain is defined in XSD file that is later on wrapped with WSDL. Create XSD file describing our domain, which is a service exposing one method returning basic information about requested country: name, population, capital and currency. `src/main/resources/countries.xsd` -[source,xml] +[source,xml,indent=0] ---- include::complete/src/main/resources/countries.xsd[] ---- @@ -118,7 +118,7 @@ In both cases, the JAXB domain object generation process has been wired into the == Create country repository -In order to provide data to web service, create country repository. In this guide we create dummy country repository implementation with hardcoded data. +In order to provide data to web service, create country repository. In this guide you create dummy country repository implementation with hardcoded data. [source,java,indent=0] ---- @@ -136,7 +136,7 @@ include::complete/src/main/java/hello/CountryEndpoint.java[] When Spring WS receives SOAP message it searches all defined endpoints for methods matching namespace and localPart. An endpoint is created typically by annotating class with the {Endpoint}[`@Endpoint`] annotation. -In order to route incoming XML message to correct method we use {PayloadRoot}[`@PayloadRoot`] annotation that indicates that all messages with namespace `http://spring.io/guides/gs-soap-service` and containing local name `getCountryRequest` will be routed to this method. +In order to route incoming XML message to correct method use {PayloadRoot}[`@PayloadRoot`] annotation that indicates that all messages with namespace `http://spring.io/guides/gs-soap-service` and containing local name `getCountryRequest` will be routed to this method. {RequestPayload}[`@RequestPayload`] indicates that message will be mapped to `request` parameter. @@ -144,7 +144,7 @@ Analogously, {ResponsePayload}[`@ResponsePayload`] annotation makes Spring WS ma == Configure web service components -There are two efficient ways of configuring Spring WS beans: using XML namespaces or using Java config. In this tutorial we create beans using plain Java. +There are two efficient ways of configuring Spring WS beans: using XML namespaces or using Java config. In this tutorial you will create beans using plain Java. Create a new class with Spring WS related beans configuration: @@ -165,7 +165,7 @@ Although it is possible to package this service as a traditional link:/understan `src/main/java/hello/Application.java` -[source,java] +[source,java,indent=0] ---- include::complete/src/main/java/hello/Application.java[] ---- @@ -190,7 +190,7 @@ Logging output is displayed. The service should be up and running within a few s Now that the application is running, you can test it. Create a file `request.xml` containing example SOAP request: -[source,xml] +[source,xml,indent=0] ---- include::test/request.xml[] ---- diff --git a/initial/build.gradle b/initial/build.gradle index d155b12..85198e8 100644 --- a/initial/build.gradle +++ b/initial/build.gradle @@ -14,7 +14,7 @@ apply plugin: 'idea' apply plugin: 'spring-boot' jar { - baseName = 'draft-gs-template' + baseName = 'gs-soap-service' version = '0.1.0' } From 6c39562e54305748357a16d4d94632e08e1b7114 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 6 May 2014 21:59:56 +0200 Subject: [PATCH 11/11] minor changes --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index e1f7729..c65024c 100644 --- a/README.adoc +++ b/README.adoc @@ -216,7 +216,7 @@ Execute from command line `curl --header "content-type: text/xml" -d @request.xm == Summary -Congratulations! You've just developed first Spring WS based SOAP service! All without single line of XML configuration! +Congratulations! You've developed Spring WS based SOAP service! All without single line of XML configuration!