Camel CXF POJO mode using Java DSL - soap

I have a pre-existing web service "connect" (SOAP) I would like to call without using the Swing framework if possible. I have followed the contact first development generating my java files using cxf/wsdl2java tool.
I wish for the userName and password to be extracted from the java object and placed in a SOAP object then sent onot my localhost web service.
When sending the Connect object as a body to the "direct:start" I get an exception...
Caused by: java.lang.IllegalArgumentException: Get the wrong parameter size to invoke the out service, Expect size 2, Parameter size 1. Please check if the message body matches the CXFEndpoint POJO Dataformat request.
I've checked the first argument is actually an instance of the Connect object passed in.
Do I need some additional annotations in the one of the classes, is the method of testing invalid or
is there an alternative pattern I should follow?
public class TestConnectCXF extends CamelTestSupport
{
#Override
protected RouteBuilder createRouteBuilder() throws Exception
{
return new RouteBuilder()
{
String cxfAddressLine = "cxf:http://localhost:8081/nuxeo/webservices/privateadservice?wsdlURL=wsdl/privateadservice.wsdl" //
+ "&dataFormat=POJO" //
+ "&serviceClass=com.sandbox.camelfeed.PrivateAdServiceInterface" //
+ "&serviceName={http://ws.sandboxtest.com/}PrivateAdService" //
+ "&synchronous=true" //
+ "&loggingFeatureEnabled=true" //
+ "&portName={http://ws.sandboxtest.com/}PrivateAdServiceInterfacePort";
#Override
public void configure() throws Exception
{
from("direct:start").to(cxfAddressLine).to("mock:end");
}
};
}
#Test
public void testConnectViaPojo() throws InterruptedException
{
Connect connectToServer = new Connect();
connectToServer.setUserName("FakeUser");
connectToServer.setPassword("scrubbed");
template.sendBody("direct:start", connectToServer);
Thread.sleep(1000);
}
}
I'm new to camel and web services so any helpful pointers would be greatly appreciated.
Additional info
Using camel 2.10, Java 1.6
Classes generated from wsdl2java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "connect", propOrder = {
"userName",
"password"
})
public class Connect {
protected String userName;
protected String password;
public String getUserName() {
return userName;
}
public void setUserName(String value) {
this.userName = value;
}
public String getPassword() {
return password;
}
public void setPassword(String value) {
this.password = value;
}
}
#WebService(targetNamespace = "http://ws.sandboxtest.com/", name = "PrivateAdServiceInterface")
#XmlSeeAlso({ObjectFactory.class})
public interface PrivateAdServiceInterface {
// Omitted Code relating to other web calls
#WebResult(name = "return", targetNamespace = "")
#RequestWrapper(localName = "connect", targetNamespace = "http://ws.sandboxtest.com/", className = "com.sandbox.camelfeed.Connect")
#WebMethod
#ResponseWrapper(localName = "connectResponse", targetNamespace = "http://ws.sandboxtest.com/", className = "com.sandbox.camelfeed.ConnectResponse")
public java.lang.String connect(
#WebParam(name = "userName", targetNamespace = "")
java.lang.String userName,
#WebParam(name = "password", targetNamespace = "")
java.lang.String password
) throws ClientException_Exception;
}
#XmlRegistry
public class ObjectFactory {
{
// Omitted other web calls information
private final static QName _Connect_QNAME = new QName("http://ws.sandboxtest.com/", "connect");
#XmlElementDecl(namespace = "http://ws.sandboxtest.com/", name = "connect")
public JAXBElement<Connect> createConnect(Connect value) {
return new JAXBElement<Connect>(_Connect_QNAME, Connect.class, null, value);
}
}

In my experience there are some things in Camel, like calling a SOAP Web service or making a REST call, that are easier to do in a custom processor, than using a component like CXF, HTTP or HTTP4.
I usually work with Spring, so I tend to use either Spring REST template or the JaxWsPortProxyFactoryBean (for Webservice calls) for outbound calls.
Here is an example using a JAX-WS call:
public class WebServiceProcessorBean {
#Autowired
private JAXWSProxy theProxy;
public void callWebservice(Exchange exchange) {
Response response = theProxy.call();
//Do something with the response and Exchange.
}
}
The definition in the Spring application context:
<bean id="theProxyService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="XXX"/>
<property name="wsdlDocumentUrl" value="http://xxxxx.wsdl"/>
<property name="namespaceUri" value="xxxx"/>
<property name="serviceName" value="xxxx"/>
<property name="portName" value="xxxxx"/>
</bean>
Use the WebServiceProcessorBean defined in Spring application context with beanRef() DSL method.
.beanRef("theProxyService", "callWebservice")

I try also dig into Apache Camel with CXF:).
I think exception, which is throws, is about problem with number of argument.
template.sendBody(what_is_called, input_parameter_s, output_parameter);
Output parameter is the most probably return value from calling of cxf webservices.

Related

JUnit5 - Rest API controller having custom spring validator is failing

I have a controller that accepts path parameter called 'jobName'. The #ValidateJobName is the custom validator that validates the user input. If the input is wrong then it throws the error below
"Invalid Job name, valid job names are: vendor, service, product,
pricing, currency, contract"
The issue I am facing is that, when I am testing my rest controller API the test case always fails by returning the above error even when the job name is one of the acceptable values but when I remove #ValidateJobName custom annotation from the controller my test cases gets passed.
The #ValidateJobName and Controller works all good when triggered from Postman client but when I do unit testing the test case fails.
I have tried lot of blogs and googled but could not get a solution, Below are my Controller and JUnit testcase.
Please help!
JobController.java
#Validated
#Slf4j
#RestController
public class JobController {
#Autowired
ReportService reportService;
#Autowired
ReportConfig reportConfig;
#RequestMapping(value = "/importjob/{jobName}", method = RequestMethod.GET)
ResponseEntity<DataIntegrationResponse> getReport(#PathVariable #ValidateJobName String jobName) throws Exception {
log.info("Received a request to launch the " + jobName + " Job");
return reportService.getReport(jobName);
}
}
JobControllerTest.java
#ExtendWith(MockitoExtension.class)
#WebMvcTest(JobController.class)
#AutoConfigureMockMvc
public class JobControllerTest {
#MockBean
ReportService reportService;
#MockBean
ReportConfig rep;
#MockBean
JobMapping jmap;
#Autowired
public MockMvc mockMvc;
#Test
public void testGetReport() throws Exception {
String jobNameInput="vendor";
HttpStatus httpStatus = HttpStatus.OK;
String fitsReportName = "idex_fits_vendor.csv";
String jobName = "WFitsVendorJob";
String jobStatus = "STARTED";
Long jobInstanceId = 1022L;
String message = "WFitsVendorJob triggered successfully.";
DataIntegrationResponse response = new DataIntegrationResponse(LocalDateTime.now(), httpStatus, fitsReportName, jobName, jobStatus, jobInstanceId, message);
ResponseEntity<DataIntegrationResponse> responseEntity = new ResponseEntity<DataIntegrationResponse>(response, HttpStatus.OK);
Mockito.when(reportService.getReport(jobNameInput)).thenReturn(responseEntity);
mockMvc.perform(get("/importjob/{jobName}", "vendor")).andExpect(status().isOk());
}
JobNameValidator.java
#Component
public class JobNameValidator implements ConstraintValidator<ValidateJobName, String>{
#Autowired
private JobMapping jobMap;
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value!=null && !jobMap.getMappings().containsKey(value)) { return false; }
return true;
}
}
ValidateJobName.java - interface
#Documented
#Constraint(validatedBy = JobNameValidator.class)
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
#Retention(RUNTIME)
public #interface ValidateJobName {
String message() default "Invalid Job name, valid job names are: vendor, service, product, pricing, currency, contract";
Class<?>[] groups() default {};
Class<? extends Payload> [] payload() default {};
}
This is because you use a mock of JobMapping
#MockBean
JobMapping jmap;
Your JobNameValidator receive a Mock and doesn't know what to return when calling the containsKey method.
First solution is to tell what to do with this mock :
Mockito.when(jobMapping.getMappings()).thenReturn(// Map containing "vendor");
The second solution is to import your real JobMapping class instead of a mock:
#ExtendWith(MockitoExtension.class)
#WebMvcTest(JobController.class)
#AutoConfigureMockMvc
#Import(JobMapping.class)
class JobControllerTest {
// #MockBean
// JobMapping jmap;
}

REST API test using Jersey Test Framework [duplicate]

I've created a Rest service with four methods, GET,POST,UPDATE and DELETE.
These methods make connections to a Database to retrieve and store data.
Now I want to test each method. I've used the Jersey Test Framework for this. And it is working as long as I remove the code what actually makes the call to the database. When I leave the code that makes the call to the database it throws an exception that it could not connect to the database.
EDIT: I have done some research and used dependancy injection. The db calls are moved to a separate class but I'm still doing something wrong.
DatabaseResults. In this class the call to the DB is made.
public class DatabaseResults {
private final String getQuery = "SELECT * FROM movies";
private Connection connection = null;
private PreparedStatement pstmt = null;
private final ArrayList<Movie> jsonList = new ArrayList<>();
public JSONObject getAllMovies() throws SQLException {
try {
ComboPooledDataSource dataSource = DatabaseUtility.getDataSource();
connection = dataSource.getConnection();
pstmt = connection.prepareStatement(getQuery);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
jsonList.add(new Movie(rs.getString(1), rs.getString(2), rs.getString(4), rs.getString(3)));
}
} catch (SQLException ex) {
System.out.println(ex);
System.out.println("Could not retrieve a connection");
connection.rollback();
} finally {
connection.close();
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("movies", jsonList);
return jsonObject;
}
}
MoviesResource that contains the REST methods
#Path("movies")
public class MoviesResource {
....
private DatabaseResults dbResults = null;
public MoviesResource() {
this(new DatabaseResults());
}
MoviesResource(DatabaseResults dbr){
this.dbResults = dbr;
}
....
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getAllMovies() throws JSONException, SQLException {
return Response.status(200).entity(dbResults.getAllMovies().toString()).build();
}
The Test class
#RunWith(MockitoJUnit44Runner.class)
public class MovieResourceTest extends JerseyTest {
JSONObject jsonObject = new JSONObject();
#Mock
DatabaseResults dbr;
#Before
public void setup() throws SQLException{
jsonObject.put("id", "hello");
when(dbr.getAllMovies()).thenReturn(jsonObject);
}
Client client = ClientBuilder.newClient();
WebTarget target = client
.target("http://localhost:9998/RestServiceMovies/resources");
#Override
protected Application configure() {
return new ResourceConfig(MoviesResource.class);
}
#Test
public void getAllMoviesTest() throws SQLException {
String responseGetAllMovies = target("/movies").request().get(String.class);
Assert.assertTrue("hello".equals(responseGetAllMovies));
}
At this moment I can run the tests but still when I test the getAllMovies() method it makes a call to the real database instead of returning the jsonObject.
I have the feeling that a connection is missing between the mock object and the constructor from the MovieResource class?
When you register your resource as a class
new ResourceConfig(MoviesResource.class)
you are telling Jersey to create the instance. If you don't have any DI configured, it will just call the no-arg constructor. In your no-arg constructor, you are just creating the service yourself. It knows nothing about your mock.
What you should do instead is register the resource class as an instance. That way you can pass the mock to the constructor.
MockitoAnnotations.initMocks(this);
return new ResourceConfig()
.register(new MoviesResource(dbr));
Don't use the Mockito runner. Instead use the MockitoAnnotations.initMocks method. That way you control when the #Mocks are injected. If you use the runner, the injection will not happen in time, as the the configure method is called by the framework before the Mockito injection happens.

Spring restful service test case fail HTTP status is 500

I want to implement test case for spring restful web services which return a json
MY controller test class is :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {WebAppContext.class,JpaTestConfiguration.class
})
#WebAppConfiguration
public class DominProfileRestControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void testGetDomainProfile() throws Exception {
String profileId = domainProfile.getId().toString();
System.out.print("testing restful"+profileId);
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.city", is("Chandigrah")));
/* mockMvc.perform(get("/service/domainprofile/get/{id}",profileId).accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().contentType("text/plain;charset=ISO-8859-1"))
.andExpect(content().string("hello Prashant"));
*/
}
My Controller class Is :
#RestController
#RequestMapping("/service/domainprofile")
public class DominProfileRestController {
#Autowired
private JpaDomainProfileRepository jpaDomainProfileRepository;
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public DomainProfileResource getDomainProfile(#PathVariable String id) {
JpaDomainProfile domainProfile = jpaDomainProfileRepository.findOne(Long.valueOf(id));
DomainProfileResource domainProfileResource = new DomainProfileResource();
System.out.println("domainProfile.getCity()*************" + domainProfile.getCity());
System.out.println("domainProfile.getAddress()*************" + domainProfile.getAddress());
domainProfileResource.setCity(domainProfile.getCity());
domainProfileResource.setAddress(domainProfile.getAddress());
// return new ResponseEntity<DomainProfileResource>(domainProfileResource, HttpStatus.OK);
return domainProfileResource;
// return domainProfile;
}
}
When I run test case I got An error while we got values in domainprofile.city and domainprofile.address.
Error Is :
java.lang.AssertionError: Status
Expected :200
Actual :500
It Is Working Fine When I return a plain text
can you do this
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andDo(print());
this will print the full response with exception , now if you see HttpMessageNotWritableException which was the issue I was facing , you should try to serialize your object using jackson and see if it works (spring internally uses Jackson ). For example , If any of your fields are null the Serialization will fail.

JAX-RS - MOXy JAXB - ClassCastException when transforming List<List<Object>> to JSON

In my app I'm using MOXy JAXB with JAX-RS (Jersey) on Glassfish server,
I have the following REST webservice:
#Named
#RequestScoped
#Path("/product")
public class ProductService extends BaseServiceFacade<Product, Integer, ProductVO> {
#EJB(mappedName="java:global/myAppEAR/myAppEJB/ProductServiceRest")
ProductServiceRestRemote productServiceRestRemote;
// ...
#GET
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/featuredlists")
public List<List<ProductVO>> featuredlists() {
return productServiceRestRemote.featuredlists();
}
}
When I try to test the REST service accessing:
localhost:8080/atlanteusPortal/rest/product/featuredlists
I get:
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class
at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.getDomainClass(MOXyJsonProvider.java:267)
If I put a debug breakpoint before the method return I can see that the List<List<ProductVO>> chunkList is populated but it's not transformed into JSON
Can someone point out a solution to send a List<List<Object>> type via JSON using JAX-RS MOXy and Jersey?
I solved the issue using a workaround encapsulating List of Lists inside an object
called ProductListVO:
#XmlRootElement
public class ProductListVO extends BaseVO<String> {
private List<ProductVO> productVOs;
public List<ProductVO> getProductVOs() {
return productVOs;
}
public void setProductVOs(List<ProductVO> productVOs) {
this.productVOs = productVOs;
}
public static ProductListVO buildVO(List<Product> t) {
ProductListVO vo = new ProductListVO();
List<ProductVO> prodVOs = new ArrayList<ProductVO>();
StringBuilder sb = new StringBuilder();
for (Product product : t) {
sb.append(product.getId()).append('-');
prodVOs.add(ProductVO.buildVO(product));
}
vo.setId(sb.substring(0, sb.length() - 1));
vo.setProductVOs(prodVOs);
return vo;
}
}
in Service method:
#GET
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/featured")
public List<ProductListVO> featuredlists() {
return productServiceRestRemote.featuredLists();
}

Inject Spring bean within RESTEasy Resource at Test time

Within a Unit/Integration Test, I'm trying to use the RESTEasy embedded server TJWSEmbeddedJaxrsServer or POJOResourceFactory inorder to simulate through a MockHttpRequest.get("/data") a resource call for test purpose.
My problem is that based on the use of the server or the Resource factory I'm not able to have a non null instance of spring beans which are injected normally within my resources.
Here's some code for clarification, thanks in advance.
Spring application context :
<context:annotation-config />
<context:component-scan base-package="com.cdcfast.service" />
<bean id="simpleResource" class="com.cdcfast.rest.SimpleResource" />
SimpleResource.java :
#Component
#Path("/data")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class SimpleResource {
#Autowired
private SimpleService service;
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Data> getData() {
return MockDataBase.getInstance().getRows();
}
Unit Test :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:/test/spring/testApplicationContext.xml" })
public class FakeTest {
private Dispatcher dispatcher;
#Before
public void before() {
dispatcher = MockDispatcherFactory.createDispatcher();
POJOResourceFactory noDefaults = new POJOResourceFactory(SimpleResource.class);
dispatcher.getRegistry().addResourceFactory(noDefaults);
}
#Test
public void aTestThatAlwaysPass() throws URISyntaxException {
MockHttpRequest request = MockHttpRequest.get("/data");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assertions.assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
Assertions.assertThat(response.getContentAsString()).isNotNull().isNotEmpty();
}
}
I've had this before because the RESTEasy factories create the POJO rather than Spring so they don't get wired up which can be worked around in the full container but is less easy in a test. The best way around this is to get a handle to your POJO once the factory creates it and then do something similar to this:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(myPojo);
I personally ended up having Spring create the RESTEasy beans using the RESTEasy-Spring plugin and then launching my tests using Jetty, not sure if that is an option for you though.
I exeprienced same problem and i'have solved in similar way as James did:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:spring-context-test.xml" })
public class TestMyService {
Dispatcher dispatcher;
private String username = "user";
#Autowired
ApplicationContext context;
#Before
public void setUp() {
MyService g = new MyService(); //rest service with #autowired spring beans
context.getAutowireCapableBeanFactory().autowireBean(g);
dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addSingletonResource(g);
}
#Test
public void TestRest() {
MockHttpRequest request;
try {
request = MockHttpRequest.get("/rest/service").header("LOGON_USER", username);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertTrue("Error, unexpected status code: " + response.getStatus(), response.getStatus() == 200);
LoggerFactory.getLogger(this.getClass()).info("********** " + response.getContentAsString());
} catch (URISyntaxException e) {
Log.error(e.getMessage(), e);
fail(e.getMessage());
}
}
}