I'm trying to develop a REST service using Apache-CXF, on top of JAX-RS. For starters, I have a method called test that receives a String message and int value. I want the clients to be able to pass these parameters in a POST message body. I can't seem to achieve this.
Before I paste the code here, here are some details:
- I'm using CXF without Spring
- It's not a web app, so I don't have the WEB-INF folder with the web.xml
- I test the service using SoapUI and Postman (Google Chrome application)
With the following code, I get WARNING: javax.ws.rs.BadRequestException: HTTP 400 Bad Request:
DemoService.java
@WebService(targetNamespace = "http://demoservice.com")@Path("/demoService")public interface DemoService { @POST @Path("/test") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public String test (String message, int value);}DemoServiceImpl.java
public class DemoServiceImpl implements DemoService { @Override public String test(String message, int value) { return "test message: "+ message +" value = : "+ value; }}DemoServer.java
public class DemoServer{ public static void main(String[] args) { JAXRSServerFactoryBean serverFactory = new JAXRSServerFactoryBean(); DemoService demoService = new DemoServiceImpl(); serverFactory.setServiceBean(demoService); serverFactory.setAddress("http://localhost:9090"); serverFactory.create(); }}My POM.xml (minus the attributes in the root tag, everything's there)
<project ...><modelVersion>4.0.0</modelVersion><groupId>demo</groupId><artifactId>demoService</artifactId><version>1.0-SNAPSHOT</version><properties><cxf.version>3.0.0</cxf.version></properties><dependencies><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-frontend-jaxws</artifactId><version>${cxf.version}</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-frontend-jaxrs</artifactId><version>${cxf.version}</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-transports-http</artifactId><version>${cxf.version}</version></dependency><!-- Jetty is needed if you're are not using the CXFServlet --><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-transports-http-jetty</artifactId><version>${cxf.version}</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-rs-service-description</artifactId><version>3.0.0-milestone1</version></dependency></dependencies></project>Testing with {"message":"hello there!", "value":"50"} to the URL http://localhost:9090/demoService/test gave a HTTP 400 Bad Reuest.
Then I saw this question on S.O.: How to access parameters in a RESTful POST method and tried this:
added the following nested class in DemoServer.java:
@XmlRootElement public static class TestRequest { private String message; private int value; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } }I also modified the DemoService interface and the implementation to use this class as a parameter in the test method, although this is still ultimately not what I want to do. (just showing the implementation here, question's already getting long):
@Overridepublic String test(TestRequest testRequest) { String message = testRequest.getMessage(); int value = testRequest.getValue(); return "test message: "+ message +" value = : "+ value;}And to fix this error that I got: SEVERE: No message body reader has been found for class DemoService$TestRequest, ContentType: application/json (in Postman I see error 415 - unsupported media type) I added the following dependencies (jettison and another thing) to the POM.xml:
<dependency><groupId>org.codehaus.jettison</groupId><artifactId>jettison</artifactId><version>1.3.5</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-rs-extension-providers</artifactId><version>2.6.0</version></dependency>I tested the service using the following JSON message, in a HTTP POST request:
{"testRequest":{"message":"hello there!", "value":"50"}}
This works. Though this solution where I use a TestRequest class to encapsulate the parameters works, that's not the solution I'm looking for. I want to be able to pass the two parameters in a JSON message, without having to introduce this TestRequest class (explicitly).
Questions:
- Would this be easier to implement using Jersey?
- I don't have a web.xml nor a WEB-INF folder, so I can't configure CXF in a cxf.xml file can I? A lot of tutorials online seem ot use a lot of XML configuration, but I don't want to deploy a framework like TomEE or Spring or Glassfish just to do that.
- Searching online for solutions, I came across Spring Boot. Would you recommend using that, perhaps? Would that make developing web services like this easier?
- Also, how do I get it to return the value in JSON format (or is it not supposed to do that for Strings?)