CXF-WS integration with spring boot (jhipster stack) - soap

I try to integrate CXF WS to jhipster stack, so avoid xml configuration.
The first class to config service
#EnableWs
#Configuration
#AutoConfigureAfter(WebConfigurer.class)
public class WebServiceConfig extends WsConfigurerAdapter {
#Bean
public ServletRegistrationBean dispatcherServlet() {
CXFServlet cxfServlet = new CXFServlet();
return new ServletRegistrationBean(cxfServlet, "/soap/*");
}
#Bean(name = "cxf")
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public Hello hello() {
return new HelloPortImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), hello());
endpoint.publish("/hello");
return endpoint;
}
}
The second file :
#WebService(targetNamespace = "http://service.ws.sample/", name = "Hello")
public interface Hello {
#WebResult(name = "return", targetNamespace = "")
#RequestWrapper(localName = "sayHello", targetNamespace = "http://service.ws.sample/", className = "com.orange.api.rfid.tacites.proxyauth.web.restWS.SayHello")
#WebMethod(action = "urn:SayHello")
#ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://service.ws.sample/", className = "com.orange.api.rfid.tacites.proxyauth.web.restWS.SayHelloResponse")
public java.lang.String sayHello(
#WebParam(name = "myname", targetNamespace = "")
java.lang.String myname
);
}
The third file
#javax.jws.WebService(
serviceName = "HelloService",
portName = "HelloPort",
targetNamespace = "http://service.ws.sample/",
endpointInterface = "com.orange.api.rfid.tacites.proxyauth.web.restWS.Hello")
public class HelloPortImpl implements Hello {
private static final Logger LOG = Logger.getLogger(HelloPortImpl.class.getName());
public java.lang.String sayHello(java.lang.String myname) {
LOG.info("Executing operation sayHello" + myname);
try {
return "Welcome to CXF Spring boot " + myname + "!!!";
} catch (java.lang.Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
}
In my logs when start spring boot, i have this line:
[DEBUG] com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator - Wrigin XML Schema for com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator#6a08fd54[http://service.ws.sample/=com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator$Namespace#76617add]
com.sun.xml.bind.v2.util.StackRecorder: null
at com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator.write(XmlSchemaGenerator.java:441) [jaxb-impl-2.2.jar:2.2]
The problem is Jhipster index.html is not found and in http://localhost:8080/soap/hello i have No binding operation info while invoking unknown method with params unknown
I think the cxf servlet kill first one servlet, how to configure to coexist both?
Regards

Try renaming your WebServiceConfig.dispatcherServlet method to something else as there is probably a bean with this name defined by Spring Boot that you're overriding.

To solve the issue, i add to WebConfigurer.java:
/**
* Initialize cxf - ws
*/
private void initCxf(ServletContext servletContext) {
log.debug("Initialize cxf - ws");
ServletRegistration.Dynamic cxfServlet = servletContext.addServlet("CxfWS", new CXFServlet());
cxfServlet.addMapping("/soap/*");
cxfServlet.setLoadOnStartup(3);
}

I've got this error when not specifying the proper wsdl name. Verify that the Soap Service instance uses a proper path to wsdl.

Related

Spring Batch Reading AWS S3 -stepExecutionContext is null

I am trying to read files from AWS s3 using spring batch but the file name becomes null in stepExecutionContext. Same code was working when i read the files from the windows mount but when we migrate the code and reading it from S3 it is becoming null.
#Bean
#JobScope
public CustomMultiResourcePartitioner partitioner() {
CustomMultiResourcePartitioner partitioner = new CustomMultiResourcePartitioner();
Set<String > filesToProcess= fileRepository.findAllFilesByFileState("NEW");
List<Resource> resourceList = new ArrayList<>();
for(String file:filesToProcess) {
Resource resource = getS3Resource(file);
resourceList.add(resource);
log.info("resourceList Size"+resourceList.size());
}
if(resourceList.size()>0 && resourceList.toArray()!=null) {
resources = resourceList.stream().toArray(Resource[]::new);
ExecutionContext executionContext = new ExecutionContext();
executionContext.put("FILE_NAME",filesToProcess);
}
else
{
resources = new Resource[0];
}
partitioner.setResources(resources);
return partitioner;
}
#Bean
#StepScope
public FlatFileItemReader<RosterInput> itemReader(#Value("#{stepExecutionContext[fileName]}") String filename) throws UnexpectedInputException, ParseException {
FlatFileItemReader<RosterInput> reader = new FlatFileItemReader<RosterInput>();
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
tokenizer.setStrict(false);
Resource resource =getS3Resource(filename);
}
I was using ByteArrayResource in my getS3Resource() method it was causing the file name to null. After modifying the code to use below the problem is solved.
public class FileNameAwareByteArrayResource extends ByteArrayResource {
private String fileName;
public FileNameAwareByteArrayResource(String fileName, byte[] byteArray) {
super(byteArray);
this.fileName = fileName;
}
#Override
public String getFilename() {
return fileName;
}
}

javax.xml.ws.AsyncHandler is an interface, and JAXB can't handle interfaces

I am trying to implement a JAX-WS web service as asynchronous and Bridging to Project Reactor.
I have implemented the client side code as follows:
Mono<IsAgentAuthorizedResponse> isAuthResponse = Mono.<IsAgentAuthorizedResponse>create(sink -> servicePortType.isAgentAuthorizedAsync(isAgentAuthorizedRequestBean, outputFuture -> {
try {
sink.success(outputFuture.get());
} catch (Exception e) {
sink.error(e);
}
}));
The SEI looks like below
#WebMethod(exclude = true)
#RequestWrapper(localName = "isAgentAuthorized", targetNamespace = "http://authapi.agentauth.rakuten.com", className = "com.demo.agentauth.authapi.IsAgentAuthorized")
#ResponseWrapper(localName = "isAgentAuthorizedResponse", targetNamespace = "http://authapi.agentauth.demo.com", className = "com.demo.agentauth.authapi.IsAgentAuthorizedResponse")
public Future<?> isAgentAuthorizedAsync(
#WebParam(name = "request", targetNamespace = "")
IsAgentAuthorizedRequestBean request,
#WebParam(name = "asyncHandler", targetNamespace = "")
AsyncHandler<IsAgentAuthorizedResponse> asyncHandler);
I am getting the following error:
com.sun.xml.internal.ws.spi.db.DatabindingException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
javax.xml.ws.AsyncHandler is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at javax.xml.ws.AsyncHandler
at public javax.xml.ws.AsyncHandler com.bjit.consume.async.esanew.way.jaxws.IsAgentAuthorizedAsync.asyncHandler
at com.bjit.consume.async.esanew.way.jaxws.IsAgentAuthorizedAsync
java.util.concurrent.Future is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at java.util.concurrent.Future
at public java.util.concurrent.Future com.bjit.consume.async.esanew.way.jaxws.IsAgentAuthorizedAsyncResponse._return
at com.bjit.consume.async.esanew.way.jaxws.IsAgentAuthorizedAsyncResponse
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions

Mocking an autowired field using mockito gives null response in rest call

I am using spring boot and mockito. I have autowired one class i.e, BDSRequest and in Junit Test class, i have used #Spy and #InjectMocks annotations. but while calling rest services in Junits, i am getting response (bdsCustomerHoldings) as null and assertion is failing. How to test this rest call with out mocking rest template like mockito.when(restTemplate.postForObject(Constants.BDS_REST_URL, bdsRequest,
BDSCustomerHoldings.class) ?
class BDSRestCall
{
#Autowired
BDSRequest bdsRequest;
public BDSCustomerHoldings getBDSCustomerInfo(String channelId, String customerId, String cinSuffix,
String countryCode) {
logger.info("prepareRequestForBDS");
Header header = new Header();
header.setMsgId(RandomStringUtils.randomAlphanumeric(20));
header.setChannelId(channelId);
header.setCountryCode(countryCode);
header.setRecordTimeStamp(DateTimeFormatter.ofPattern(Constants.DATE_FORMATTER).format(LocalDateTime.now()));
TxnRequest txnRequest = new TxnRequest();
txnRequest.setIdDoc(customerId);
txnRequest.setIdDocSuffix(cinSuffix);
txnRequest.setIdDoctype("");
txnRequest.setInsurerCode("");
bdsRequest.setHeader(header);
bdsRequest.setTxnRequest(txnRequest);
logger.info("BDS request " + bdsRequest);
BDSCustomerHoldings bdsResponse = restTemplate.postForObject(Constants.BDS_REST_URL, bdsRequest,
BDSCustomerHoldings.class);
logger.info("BDS Response : " + bdsResponse);
return bdsResponse;
}
}
Junit:
#RunWith(MockitoJUnitRunner.class)
class BDSRestCallTest
{
#InjectMocks
private BDSRestCall bdsRestCall;
#Mock
private RestTemplate restTemplate;
#Spy
private BDSRequest bdsRequest;
#Test
public void getBDSCustomerInfoExceptionTest() {
BDSCustomerHoldings bdsCustomerHoldings = bdsRestCall.getBDSCustomerInfo("SG", "S9718016D",
"00", "SG");
System.out.println("response is " + bdsCustomerHoldings);
assertNotNull("response is not null", bdsCustomerHoldings);
}
}
As we are using #RunWith(MockitoJUnitRunner.class), then we should use mocking the response of restTemplate like below
Mockito.when(restTemplate.postForObject(Mockito.anyString(), bdsRequest, BDSCustomerInsuranceHoldings.class)).thenReturn(sampleBDSCustomerInsuranceHoldings());
Then it will give mock response.

Can I use repository populator bean with fongo?

I'm using Fongo not only for unit tests but also for integration tests so I would like to initialize Fongo with some collections, is that possible?
This is my java config (based on Oliver G. answer):
#EnableAutoConfiguration(exclude = {
EmbeddedMongoAutoConfiguration.class,
MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class
})
#Configuration
#ComponentScan(basePackages = { "com.foo" },
excludeFilters = { #ComponentScan.Filter(classes = { SpringBootApplication.class })
})
public class ConfigServerWithFongoConfiguration extends AbstractFongoBaseConfiguration {
private static final Logger log = LoggerFactory.getLogger(ConfigServerWithFongoConfiguration.class);
#Autowired
ResourcePatternResolver resourceResolver;
#Bean
public Jackson2RepositoryPopulatorFactoryBean repositoryPopulator() {
Jackson2RepositoryPopulatorFactoryBean factory = new Jackson2RepositoryPopulatorFactoryBean();
try {
factory.setResources(resourceResolver.getResources("classpath:static/collections/*.json"));
} catch (IOException e) {
log.error("Could not load data", e);
}
return factory;
}
}
When I run my IT tests, on the log it appears Reading resource: file *.json but the tests fails because they retrieve nothing (null) from Fongo database.
Tests are annotated with:
#RunWith(SpringRunner.class)
#SpringBootTest(classes={ConfigServerWithFongoConfiguration.class})
#AutoConfigureMockMvc
#TestPropertySource(properties = {"spring.data.mongodb.database=fake"})
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
Lol, I feel so stupid right now. Was format issue. JSON collections must be formated like this:
[
{/*doc1*/},
{/*doc2*/},
{/*doc3*/}
]
I was missing the [] and comma separated documents.

Spring Bean Scope for StringRedisConnection

I have the following two bean definitions for Spring Data Redis. I cant seem to find the relevant documentation to determine the scopes(singleton,request or session) of these beans for a web app.
#Bean
public StringRedisTemplate redisTemplate() throws Exception {
StringRedisTemplate redisTemplate = new StringRedisTemplate();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
return redisTemplate;
}
#Bean
public StringRedisConnection stringRedisConnection() throws Exception {
return new DefaultStringRedisConnection(redisTemplate().getConnectionFactory().getConnection());
}
Thanks to #Christoph Strobl recommendation here is the implementation Iam currently using
public List<String> testAutoComplete(String key,String query, int limitCount){
StringRedisSerializer serializer = new StringRedisSerializer();
RedisZSetCommands.Range range = Range.range();
range.gt(query);
RedisZSetCommands.Limit limit = new RedisZSetCommands.Limit();
limit.count(limitCount);
return template.execute(new RedisCallback< List<String>>() {
public List<String> doInRedis(RedisConnection connection) {
Set<byte[]> results = connection.zRangeByLex(serializer.serialize(key), range,limit);
List<String> resultAsString = new ArrayList<String>();
for(byte[] result : results){
resultAsString.add(serializer.deserialize(result));
}
return resultAsString;
}
},false);
}