I am consuming a soap service using dropwizard-jaxws.
Managed to generate the relevant java classes using Apache CXF 3.4. Here's the generated interface IService.
#WebService(targetNamespace = "http://tempuri.org/", name = "IService")
#XmlSeeAlso({ObjectFactory.class})
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface IService {
#WebMethod(operationName = "PayBill", action = "http://tempuri.org/IService/PayBill")
#Action(input = "http://tempuri.org/IService/PayBill", output = "http://tempuri.org/IService/PayBillResponse")
#WebResult(name = "PayBillResponse", targetNamespace = "http://tempuri.org/", partName = "parameters")
public PayBillResponse payBill(
#WebParam(partName = "parameters", name = "PayBill", targetNamespace = "http://tempuri.org/")
PayBill parameters
);
I wrote this implementing class IserviceImpl in kotlin
#WebService(endpointInterface = "com.mmm.platform.utility.easy.IService",
targetNamespace = "http://tempuri.org/",
name = "IService",
wsdlLocation = "wsdl/mmm-easy.wsdl")
class IServiceImpl: IService {
override fun payBill(parameters: PayBill?): PayBillResponse {
var response = PayBillResponse();
response.setSctrxnid(parameters?.sctxnid);
return response;
}
This is my dropwizard Application class in kotlin
class UtilityServiceApplication : Application<UtilityServiceConfiguration>() {
private val jaxWsBundle = JAXWSBundle<Any>()
override fun initialize(bootstrap: Bootstrap<UtilityServiceConfiguration>?) {
bootstrap?.addBundle(jaxWsBundle)
}
override fun run(configuration: UtilityServiceConfiguration?, environment: Environment?) {
environment!!.jersey().register(
AccessEasyServiceResource(
jaxWsBundle.getClient(
ClientBuilder(IService::class.java,
"http://mmm.hhhhh.xyz/EMTerminalAPI/wsdl.svc")
.handlers(AccessEasyClientHandler()))))
}
}
Dropwizard resource class AccessServiceResource in kotlin for end-point /paybillone
#Path("/paybillone")
#Produces(MediaType.APPLICATION_JSON)
public class AccessServiceResource {
var serviceClient: IService? = null
constructor(serviceClient: IService) {
this.serviceClient = serviceClient;
}
#GET
#Timed
fun getFoo(): String {
val of = ObjectFactory()
var payBill = of.createPayBill()
payBill.sctxnid = of.createPayBillSctxnid(RandomStringUtils.randomAlphanumeric(15))
payBill.txntype = of.createPayBillTxntype("1")
payBill.payeecode = of.createPayBillPayeecode("POWER")
payBill.accountno = of.createPayBillAccountno("04246483624")
payBill.phoneno = of.createPayBillPhoneno("0700252181")
payBill.amount = of.createPayBillAmount("5000")
var payBillResponse = serviceClient?.payBill(payBill)
return payBillResponse?.receiptno?.value.toString()
}
This call var payBillResponse = serviceClient?.payBill(payBill) unfortunately returned an error response message missing mandatory values yet I clearly added them to the payBill object.
Qn 1 Is this the correct way of creating the request object, so I get the correct corresponding response payBillResponse?
Qn 2 How and where should I pass payBill so I get the correct response to that call?
Qn 3 The other issue is most likely my implementation of IServiceImpl is wrong, is it even required?
Related
Using wsdl2java tool to generate client classes, I can't seem to able to force to wrap Web Service response in a return type - the return type is always void and OUT parameters wrapped in Holders are generated. Auth.java auto-generated client interface looks like this:
#WebService(targetNamespace = "http://xml.kamsoft.pl/ws/auth", name = "Auth")
#XmlSeeAlso({pl.kamsoft.xml.ws.common.ObjectFactory.class, pl.kamsoft.xml.ws.kaas.login_types.ObjectFactory.class})
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface Auth {
// [...] - `logout`, `changePassword`, `changePasswordLog` methods
#WebMethod(action = "login")
public void login(
#WebParam(partName = "request", name = "login", targetNamespace = "http://xml.kamsoft.pl/ws/kaas/login_types")
pl.kamsoft.xml.ws.kaas.login_types.LoginRequest request,
#WebParam(partName = "response", mode = WebParam.Mode.OUT, name = "loginReturn", targetNamespace = "http://xml.kamsoft.pl/ws/kaas/login_types")
jakarta.xml.ws.Holder<java.lang.String> response,
#WebParam(partName = "session", mode = WebParam.Mode.OUT, name = "session", targetNamespace = "http://xml.kamsoft.pl/ws/common", header = true)
jakarta.xml.ws.Holder<pl.kamsoft.xml.ws.common.Session> session,
#WebParam(partName = "token", mode = WebParam.Mode.OUT, name = "authToken", targetNamespace = "http://xml.kamsoft.pl/ws/common", header = true)
jakarta.xml.ws.Holder<pl.kamsoft.xml.ws.common.AuthToken> token
) throws pl.kamsoft.wsdl.common.AuthenticationExceptionMsg, pl.kamsoft.wsdl.common.ServerExceptionMsg, PassExpiredExceptionMsg, pl.kamsoft.wsdl.common.AuthTokenExceptionMsg, pl.kamsoft.wsdl.common.InputExceptionMsg, pl.kamsoft.wsdl.common.AuthorizationExceptionMsg;
}
Minimal example (build.gradle.kts file with Gradle configuration):
plugins {
java
id("com.yupzip.wsdl2java") version "3.0.0"
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.apache.cxf:cxf-rt-frontend-jaxws:4.0.0")
implementation("org.apache.cxf:cxf-rt-transports-http-hc5:4.0.0")
wsdl2java("com.sun.xml.bind:jaxb-impl:4.0.1")
wsdl2java("org.apache.cxf.xjc-utils:cxf-xjc-runtime:4.0.0")
wsdl2java("jakarta.xml.ws:jakarta.xml.ws-api:4.0.0")
wsdl2java("com.sun.xml.ws:rt:4.0.0")
wsdl2java("org.jvnet.jaxb2_commons:jaxb2-namespace-prefix:2.0")
wsdl2java("codes.rafael.jaxb2_commons:jaxb2-basics-runtime:3.0.0")
wsdl2java("codes.rafael.jaxb2_commons:jaxb2-basics:3.0.0")
}
wsdl2java {
wsdlDir = file("$projectDir/src/main/resources/")
includeJava8XmlDependencies = false
cxfVersion = "4.0.0"
cxfPluginVersion = "4.0.0"
wsdlsToGenerate = listOf(
listOf(
"-wsdlLocation", "https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl",
"-autoNameResolution",
"https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl",
)
)
}
How can I force wsdl2java tool to generate LoginResponse class of which instance would be returned on Auth#login invocation?
I've tried to include binding file (bindings.xml):
<bindings
wsdlLocation="https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://java.sun.com/xml/ns/jaxws">
<enableWrapperStyle>false</enableWrapperStyle>
</bindings>
but neither setting enableWrapperStyle to false or true did change anything. Here is how my configuration looked like (build.gradle.kts):
wsdl2java {
wsdlDir = file("$projectDir/src/main/resources/")
includeJava8XmlDependencies = false
cxfVersion = "4.0.0"
cxfPluginVersion = "4.0.0"
wsdlsToGenerate = listOf(
listOf(
"-b", "$projectDir/src/main/resources/wsdl/bindings.xml",
"-wsdlLocation", "https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl",
"-autoNameResolution",
"https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl",
)
)
}
Can the fact that both session and token are declared as wsdlsoap:header have impact on the resulting generated Java code?
I have built a Restful-API Java(SpringBoot) and created the needed requests.
The following request is a POST Request to add new Category.
I have tested the POST request by POSTMAN, and it working as expected.
I am building the client-side in ASP.NET 5.x.x.
Now the problem appear when I am calling the post request, it seems the API doesn't receive the data (#RequestBody category) that has been send from the client.
Here is a code simple of how I have created them
Server Side:
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(value = "/add", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public CategoryDTO create(#RequestBody CategoryDTO category) {
log.info("Adding new Category Name: " + category.getName());
return categoryMapper.asCategoryDTO(categoryService.save(categoryMapper.asCategory(category)));
}
Client Side
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Category category)
{
Category newCategory = new Category();
// Serialize the concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(category);
// Wrap the JSON inside a StringContent which then can be used by the HttpClient class
StringContent content = new StringContent(stringPayload);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.PostAsync("http://localhost:8080/category/add", content))
{
string apiResponse = await response.Content.ReadAsStringAsync();
newCategory = JsonConvert.DeserializeObject<Category>(apiResponse);
}
}
return RedirectToAction("Index");
}
I don't know what is wrong there, could anybody help!
EDIT--
Here is the request via postman
EDIT
I have created another POST request but as a RequestParam instead of RequestBody
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
public CategoryDTO addCategory(#RequestParam(name = "categoryName") String categoryName){
return categoryMapper.asCategoryDTO(categoryService.addCategory(categoryName));
}
and created in the client side the request as following
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Category category)
{
Category newCategory = new Category();
var parameters = new Dictionary<string, string> { { "categoryName", category.Name } };
var encodedContent = new FormUrlEncodedContent(parameters);
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.PostAsync("http://localhost:8080/category/add", encodedContent))
{
string apiResponse = await response.Content.ReadAsStringAsync();
newCategory = JsonConvert.DeserializeObject<Category>(apiResponse);
}
}
return RedirectToAction("Index");
}
And It's works fine!
So the problem is how to pass the data via the httpClient, which need to be of type RequestBody (the data in the body not in the header!) also as a application/json.
So how to pass the data?
I suppose that your spring boot application just blocks POST request because you didn't provide instruction how to handle requests. Try to disable csrf protection like it did here: https://stackoverflow.com/a/48935484/13314717
It might be a problem in the naming convention. Starting with capital letters in properties in C#, and starting with lowercase in Java.
If your class looks like this in C#
class Category {
int Id;
string Name;
...
}
And like this in Java
class Category {
int id;
string name;
...
}
It is not going to work so you have to match the property names. So make either both id or both Id.
We are trying to do pagination with the help of this
<dependency>
<groupId>net.kaczmarzyk</groupId>
<artifactId>specification-arg-resolver</artifactId>
<version>2.1.1</version>
</dependency>
With request parameters its fine, but when we try with Path variables its giving exception saying
Requested path variable {destUserId} is not present in Controller request mapping annotations
The following are the methods we tried
Method-1 : With #PathVariable
#RequestMapping(method = RequestMethod.GET, value = "/cf/{destUserId}")
#ResponseBody
public PagedResponse<SystemStock> croudFundReport(#PathVariable(name = "destUserId") String eventId,
#Conjunction (value = {
#Or(value = #Spec(path = "metaType", params = {"meta_type"}, spec = Equal.class))},
and = #Spec(path = "destUserId", pathVars = "destUserId", spec = Equal.class)) Specification<UserData> spec) {
return null;
}
Method-2 : Without #PathVariable
#RequestMapping(method = RequestMethod.GET, value = "/cf/{destUserId}")
#ResponseBody
public PagedResponse<SystemStock> croudFundReport(#Conjunction (value = {
#Or(value = #Spec(path = "metaType", params = {"meta_type"}, spec = Equal.class))},
and = #Spec(path = "destUserId", pathVars = "destUserId", spec = Equal.class)) Specification<UserData> spec) {
return null;
}
Method-3 : RequestMapping with just path and with #PathVariable
#RequestMapping("/cf/{destUserId}")
#ResponseBody
public PagedResponse<SystemStock> croudFundReport(#PathVariable(name = "destUserId") String eventId,
#Conjunction (value = {
#Or(value = #Spec(path = "metaType", params = {"meta_type"}, spec = Equal.class))},
and = #Spec(path = "destUserId", pathVars = "destUserId", spec = Equal.class)) Specification<UserData> spec) {
return null;
}
Method-4 : RequestMapping with just path and without #PathVariable
#RequestMapping("/cf/{destUserId}")
#ResponseBody
public PagedResponse<SystemStock> croudFundReport(#Conjunction (value = {
#Or(value = #Spec(path = "metaType", params = {"meta_type"}, spec = Equal.class))},
and = #Spec(path = "destUserId", pathVars = "destUserId", spec = Equal.class)) Specification<UserData> spec) {
return null;
}
Method-5 : RequestMapping with just path, without #PathVariable, without #Conjunction
#RequestMapping("/cf/{destUserId}")
#ResponseBody
public PagedResponse<SystemStock> croudFundReport(#Spec(path = "destUserId", pathVars = "destUserId", spec = Equal.class) Specification<UserData> spec) {
return null;
}
Method-6 : GetMapping without #PathVariable, without #Conjunction
#GetMapping(path = "/cf/{destUserId}", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public PagedResponse<SystemStock> croudFundReport(#Spec(path = "destUserId", pathVars = "destUserId", spec = Equal.class) Specification<UserData> spec) {
return null;
}
References
Path variable support
#PathVariable issue
The problem is we can access the PathVariable as a method argument, but when we try to specify it in that in pathVars in the above cases execution is not reaching our Controller and we are getting the same above exception. Any help?
One thing I noticed you used GetMapping only in the last example. Is there reason for using RequestMapping?
Is there a specific reason to not use [JPA pagination][https://www.baeldung.com/jpa-pagination]?
Have you tried the following?
#GetMapping(path = "/cf/{destUserId}", produces = MediaType.APPLICATION_JSON_VALUE)
public PagedResponse<SystemStock> croudFundReport( #PathVariable(name = "destUserId") final String destUserId) {
// TODO implementation
}
java artifacts for Soap Web Service Client using wsimport from a WSDL. Which produced:
AppPortalSMupdate.java with some sample code from it
public interface AppPortalSMupdate {
#WebMethod(operationName = "RetrieveAppPortalSMupdate", action = "Retrieve")
#WebResult(name = "RetrieveAppPortalSMupdateResponse", targetNamespace = "http://schemas.hp.com/SM/7", partName = "RetrieveAppPortalSMupdateResponse")
public RetrieveAppPortalSMupdateResponse retrieveAppPortalSMupdate(
#WebParam(name = "RetrieveAppPortalSMupdateRequest", targetNamespace = "http://schemas.hp.com/SM/7", partName = "RetrieveAppPortalSMupdateRequest")
RetrieveAppPortalSMupdateRequest retrieveAppPortalSMupdateRequest);
AppPortalSMupdate_Service.java
#WebServiceClient(name = "AppPortalSMupdate", targetNamespace = "http://schemas.hp.com/SM/7", wsdlLocation ="http://ss_user:sqzblsft#msmapptst001.lvh.com:13088/SM/7/AppPortalSMupdate.wsdl")
public class AppPortalSMupdate_Service extends Service{
private final static URL APPPORTALSMUPDATE_WSDL_LOCATION;
private final static WebServiceException APPPORTALSMUPDATE_EXCEPTION;
private final static QName APPPORTALSMUPDATE_QNAME = new QName("http://schemas.hp.com/SM/7", "AppPortalSMupdate");
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("http://ss_user:sqzblsft#msmapptst001.lvh.com:13088/SM/7/AppPortalSMupdate.wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
APPPORTALSMUPDATE_WSDL_LOCATION = url;
APPPORTALSMUPDATE_EXCEPTION = e;
This is the call to in my main from test client class:
AppPortalSMupdate appUpdate = calc.getAppPortalSMupdate();
UpdateAppPortalSMupdateResponse appResponse = appUpdate.updateAppPortalSMupdate(requestMessage);
My question is the web service needs a user id and password. How do I add a user id and password in my call in the main. This is being used inside a liferay portlet.
use #HandlerChain annotation and configure them by implementing the SOAPHandler interface.
Let me know if you need more clarification.
I have a web service using JAX-WS and Ibatis, when analyzed with the New Relic tool can see that the running time is 17 seconds. Seeing the detail of the report shows that the database calls are fast, but what is delaying is this: JAXWSWebAppServlet.service (). Someone has an idea that can be ??
Thanks x your help.
PD: I would like to know where to locate JAXWSWebAppServlet.service () in my code. Any ideas??
The WS code:
#WebService(name = "WS_XXXXXX", portName = "WS_XXXXXSoap12HttpPort")
#BindingType(SOAPBinding.SOAP12HTTP_BINDING)
public class WS_GetPlanUsage {
#WebMethod(operationName = "xxxxxx")
#javax.jws.soap.SOAPBinding(parameterStyle = javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED)
public GetPlanUsageMapBean getPlanUsage(#WebParam(name = "phoneNumber", partName = "request") String phoneNumber,
#WebParam(name = "initialDate", partName = "request") String initialDate,
#WebParam(name = "finalDate", partName = "request") String finalDate) {
BReturn oBReturn = null;
GetPlanUsageResponse response = new GetPlanUsageResponse();
GetPlanUsageRequest rq = new GetPlanUsageRequest();
rq.setPhoneNumber(phoneNumber);
rq.setInitialDate(initialDate);
rq.setFinalDate(finalDate);
oBReturn = new GetPlanUsageBL().getPlanUsage(rq);
GetPlanUsageMapBean getPlanUsage = (GetPlanUsageMapBean)oBReturn.getObject();
return getPlanUsage;
}