I am part of a coding competition, the task is to create a RESTful online marketplace where users can post buy and sell requests via http.
I need to build a front end web service that accepts and stores these requests.
The tech requirements include both Spring boot and CXF. As far as I am aware, both CXF and Spring boot are capable of accepting http requests.
In spring boot, you use a controller like:
#Controller
#EnableAutoConfiguration
public class controller {
#RequestMapping("/")
#ResponseBody
String home() {
return "Hello, World!";
}
}
Whereas with CXF (using javax.ws.rs), the code might look like this:
#WebService(serviceName = "MarketService", targetNamespace = "http://localhost:9005")
#Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public interface MarketService {
#GET
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces({ MediaType.APPLICATION_JSON })
#Path("/sells/{id}")
public prod getProduct(#PathParam("id") int id);
Can someone help me understand the fundamental difference between these two approaches to handling http requests? Is there a way I can use both Spring Boot and CXF in the same application?
Spring MVC and Apache CXF are 2 separate frameworks to handle HTTP requests and that can be used to build REST web services.
Spring MVC is a project under the Spring "umbrella" (and therefore strongly tied to the Spring framework on top of which it's built),
Apache CXF is a open-source implementation of JAX-RS (REST) and JAX-WS (SOAP). Apache CXF can be run standalone or be included in a Spring application.
If you are looking to build a REST web service, they are pretty much mutually exclusive (you have to pick one). If all you're going to do is build REST web services, then they're pretty much equivalent. If you also need to have an MVC framework to serve HTML pages, then Spring MVC has that capability (CXF does not).
Personal opinion: Spring MVC is easier to get started with (thanks to Spring Boot which handles most of the configuration for you) than CXF (which requires more XML configuration).
PS: in your CXF example, you have a #WebService annotation. This annotation is part of JAX-WS (SOAP), not JAX-RS (REST). You probably don't need it.
Use the Spring Boot CXF JAX-RS starter by adding:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
<version>3.1.7</version>
</dependency>
See also: http://cxf.apache.org/docs/springboot.html
Check this project out for nice starter for JAX-RS (REST) that leverages CXF on Tomcat via TomEE.
Everything is all setup and ready to go.
https://github.com/tomitribe/tomee-jaxrs-starter-project
Long description here:
http://www.tomitribe.com/blog/2014/06/apache-tomee-jax-rs-and-arquillian-starter-project
Note, running CXF "Standalone" still requires a Servlet container (Tomcat or Jetty), so the above is several steps completed, simplified and finished in a small starter project. Designed for impatient people (like myself) that don't like to read directions and just like to start hacking. Always easier for me to start with something that works and then tweak it.
Related
I have to save some values in a reactive way using spring Webflux. But when I send the request then 404 status is returned as a response.
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
EmpController class
#RestController
#RequestMapping("/emp")
public class EmpController {
private EmployeeRepository empRepo;
#Autowired
public EmpController(EmployeeRepository empRepo)
{
this.empRepo=empRepo;
}
#PostMapping("/save")
#Consumes({MediaType.APPLICATION_JSON})
public void saveEmp(#RequestBody Mono<Employee> emp)
{
emp.subscribe(e-> {
e.setDate(new Date());
empRepo.saveEmp(e);
});
}
}
When I send the request via PostMan then 404(not found) is returned.
JAX-RS is a specification within Java EE of how to code REST api's. Several libraries have then implemented said specification, Like Jersey or restEasy. WHen building a Java EE application, you needed one of these libraries to be able to build a rest api.
Spring built their own way of building rest apis spring-web for non reactive applications, and spring-webflux for reactive applications.
Jersey and restEasy (to my knowledge) only works if you are building a non-reactive application.
In order to make your code work you need to remove:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
Jersey is a Java EE implementation of JAX-RS. It is used in Java EE to build Java EE styled rest apis. You are building a reactive application, using Spring Webflux which has its own way of building REST api's.
Spring is not a Java EE application. When you added that dependency, spring assumed that you wanted to build a Spring Application but not use the Spring built in REST api functions and annotations etc, so it didn't register your code, that you have written with Springs way of building rest apis.
It assumed you were going to write a REST api the "jersey way" and if you are using jersey you need to register your api classes manually. And (to my knowledge) Jersey only works with non-webflux applications.
This is all mainly basic knowledge, and if you dont understand why i suggest you read up and build a regular spring boot application, before trying out webflux.
I suggest you read the following parts:
Reactive programming, Reactor getting started
Baeldung Webflux
Building a reactive Webflux Application
Spring boot Webflux
It is Strange but when I removed jersey dependency and it Worked. Still not sure about the reason behind it.
raised pull request you the merge the same to take the changes I have done
https://github.com/Benzeman97/reactive-async-app/pull/1
You need to remove below Jersey dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
The reason behind is that the spring-boot-starter-jersey is a starter for building Restful web applications using JAX-RS and Jersey. Since you have used it in your project the spring does not use in built spring functions for rest api's like #GetMapping, #PostMapping.
If you want to use jersey to create the rest api then use #GET annotation for Get api and the #Produces to defined the mapping as below.
Eg.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.stereotype.Service;
#Service
#Path("/hello")
public class HelloService {
#GET
#Produces("text/plain")
public String hello() {
return "Hello from Spring";
}
}
Also you have to register this class in JerseyConfig.
import com.zetcode.endpoint.HelloService;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;
#Configuration
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(HelloService.class);
}
}
And if you want to go ahead with the spring build in functions and use reactive just remove the jersey dependency and use webflux dependency to create your rest api's.
I had the same problem.
The solution:
go to application.properties,
remove server.servlet.context-path
and add spring.webflux.base-path
ive been tasked with a total refactor of legacy code. It's a simple webservice, just an http request, then business logic with possibly a few database calls and a few other microservice calls, then a json response. I am being pushed not to use spring boot because no one else around me has used it before, and I was told jersey does everything spring boot does. I've never used jersey so im trying to find out how to do things that spring boot makes simple (ie repository layer with spring-data, caching, spring-consul, spring-zuul, spring-actuator, spring-circuit-breaker) It looks like jersey does do an analog of spring-security, bean validation, and easy insertion of servlet filters, but not everything spring-boot does. Is there an easy way to wire in a JPA type repository in jersey? I cant find it in the docs at https://jersey.java.net/documentation/latest/index.html.
I think about it this way. There are different layers in your application. You have a service layer, and you have a "REST layer". You access the Spring repositories with the service layer. Then you have the REST layer. With Spring, you have Spring MVC which is its web layer implementation, that you can also use as REST services. There is also Jersey, which is completely independent of Spring, which is a another REST layer options.
That be said, when using Spring MVC as the REST layer, adding the service layer with Spring data is seamless. But Jersey also has integration with Spring, that allows us to use Spring at the service layer inside our Jersey REST services. You check out this post which has some links to example of how this can be done (no hacking, this is supported out of the box). Using this approach, you can just injector your Spring data repositories into your Jersey resource class
interface PetsRepository extends JpaRepository<Pets, Long> {}
#Path("/pets")
class PetsResource {
#Autowired
private PetsRepository repo;
}
Now lets talk about Spring Boot. Spring Boot is just a bootstrapping framework. What it does is allow you to easily bootstrap an application without all the boilerplate configuration you would need without it. When your using Spring Boot for your REST services, you're not actually using Spring Boot itself as the REST service engine. You are only using it to bootstrap Spring MVC and maybe your Spring Data. But Spring MVC is the actual REST service engine.
Now like I said before, Jersey has support for integrating Spring into into it (for the service layer). Because of this support, Spring Boot has also provided a bootstrap configuration to integrate this support seamlessly. So instead of using the manual configuration that you would see in one of the examples linked to above, Spring Boot handles this configuration for us. So we can use Jersey as the REST layer, and Spring beans as the service layer. Check out the links below
See also:
Spring Boot docs for Jersey support
I am wondering, if it's possible to use Spring Web MVC with Jersey annotations, as I'm having a massive problem with Spring not being able to parse part variables the way Jersey can and I need to migrate some Jersey code to Spring MVC.
I have the following code in Jersey:
#PUT
#Path("{storageId}/{repositoryId}/{path:.*}")
#PreAuthorize("hasAuthority('ARTIFACTS_DEPLOY')")
public Response upload(#PathParam("storageId") String storageId,
#PathParam("repositoryId") String repositoryId,
#PathParam("path") String path,
InputStream is)
{
...
}
I would like to convert this over to Spring MVC, but, like I've explained in this SO post, I'm experiencing issues with parsing the path variables.
Hence, my wondering (and a separate question): is it possible to use the same Jersey annotations with Spring MVC?
it's possible to use Spring Web MVC with Jersey annotations, try make a little sample in Spring Initializer there you can check the option jersey, see how spring build this project and try in yours
I have an existing API which has both JAX-RS and JAX-WS. I want to migrate it into a Spring Boot application. What I've done for JAX-RS part is registering that class:
#GET
#Path("/ping")
#Produces("text/plain")
String ping();
into a Jersey Config which extends ResourceConfig. Here is the example from JAX-WS of same class:
#WebMethod(operationName = "Ping", action = "ping-app")
String ping();
Since I've used reference implementations of JAX-RS and JAX-WS I hope that it should be easy to migrate it into Spring Boot. I've easily done JAX-RS integration. Is there any such simple way to integrate JAX-WS too?
Ideally you'd want to use a Spring Boot Starter to assist you. According to their documentation:
Starters are a set of convenient dependency descriptors that you can
include in your application. You get a one-stop-shop for all the
Spring and related technology that you need, without having to hunt
through sample code and copy paste loads of dependency descriptors.
For example, if you want to get started using Spring and JPA for
database access, just include the spring-boot-starter-data-jpa
dependency in your project, and you are good to go.
Using this list of official and community starters, it looks like you have the following options:
spring-boot-starter-jersey should be able to handle JAX-RS
spring-boot-web-services might be able to handle JAX-WS. From what I understand, you might need to do things the 'Spring Web Services' way which is different to JAX-WS. It's been a while since I worked with Spring Web Services, so I might be incorrect on this point.
The Apache CXF starter can support both JAX-RS and JAX-WS which seems to meet your requirement. They have this guide for their spring boot integration for you to look at.
I didn't use this personally but it seems that spring provides starter pack for JAX-WS
Take a look at this artifact. It should be enough just to add this dependency to your project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
I have solved the problem by using this dependency
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.3.6</version>
</dependency>
and add this bean in the configuration bean
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.xml.ws.Endpoint;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
#Configuration
public class WebServiceConfig{
#Autowired
private Bus bus;
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, new SpPortImpl());
endpoint.publish("/NpcdbService");
return endpoint;
}
}
SpPortImpl is the class annotated with #WebService
I have to create java project that used only for rest webservices. I have to choose between SpringMVC and Jersey. I consider springMVC because we use SpringMVC in all our other projects. I considered Jersey because its standard(JAX-RS) and its created specially for Rest.
Would it be overhead to use SpringMVC for rest only web project? Or should I use Jersey(or any other JAX-RS implementation)
If you also know how to configure / develop the backend in both worlds (CDI, Spring) it is really up to you.
But if you are more experienced with Spring(MVC) I would suggest that you use it or take a look at spring boot (samples especially spring-boot-hateoas).