I am struggling to properly make a SOAP request with open feign client and get the response. For testing purposes i took this public SOAP service http://www.learnwebservices.com/ and this is WSDL -> http://www.learnwebservices.com/services/hello?WSDL
I generated classes from this WSDL that looks like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "SayHello", propOrder = {
"helloRequest"
})
public class SayHello {
#XmlElement(name = "HelloRequest", required = true)
protected HelloRequest helloRequest;
//getters and setters
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "helloRequest", propOrder = {
"name"
})
public class HelloRequest {
#XmlElement(name = "Name", required = true)
protected String name;
//getters and setters
}
And i tried to follow this example:
How to send a SOAP object with FEIGN client?
basically i created this feign config:
private static final JAXBContextFactory jaxbContextFactory = new JAXBContextFactory.Builder()
.withMarshallerJAXBEncoding("UTF-8")
.withMarshallerSchemaLocation("http://www.learnwebservices.com/services/hello?WSDL")
.build();
#Bean
public Decoder feignDecoder() {
return new SOAPDecoder(jaxbContextFactory);
}
#Bean
public Encoder feignEncoder() {
return new SOAPEncoder(jaxbContextFactory);
}
And then here i try to invoke end point like this:
#FeignClient(name = "feign-example",
url = "http://www.learnwebservices.com/services/hello",
configuration = FeignConfig.class)
public interface WogSeb20FeignClient {
#PostMapping(value = "", consumes = MediaType.TEXT_XML_VALUE, produces = MediaType.TEXT_XML_VALUE)
HelloResponse get(#RequestBody HelloRequest addRequest);
}
First when i tried to do the call i got error that says HelloRequest is missing XmlRootElement, so i added that annotation to the class (even i am not sure what to put as root element, i just added #XmlRootElement on top of the class. Afterwards when i create a request i get this error:
Error during parsing response data. Status: 500, Cause: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>Message part helloRequest was not recognized. (Does it exist in service WSDL?)</faultstring></soap:Fault></soap:Body></soap:Envelope>
Obviously i am doing something wrong, can someone give me some guidance since i was not able to find too much material regarding this topic.
Related
I have been having issues trying to get endpoint mapping to work for my web service. I am using Tomcat to host my web service and I am using soapUI to send test messages to it.
Endpoint
#Endpoint
public class ProductEndpoint {
private static final String NAMESPACE_URL="http://com.springbootsoap.allapis";
#Autowired
ProductService productService;
#PayloadRoot(namespace = NAMESPACE_URL, localPart = "addProductRequest")
#ResponsePayload
public AddProductResponse addProduct(#RequestPayload AddProductRequest request) {
AddProductResponse response= new AddProductResponse();
ServiceStatus servicestatus=new ServiceStatus();
Product product=new Product();
BeanUtils.copyProperties(request.getProductInfo(),product);
productService.addProduct(product);
servicestatus.setStatus("Success");
servicestatus.setMessage("Content Added Successfully");
response.setServiceStatus(servicestatus);
return response;
}
#PayloadRoot(namespace = NAMESPACE_URL, localPart = "getProductByIdRequest")
#ResponsePayload
public GetProductResponse GetProduct(#RequestPayload GetProductByIdRequest request) {
GetProductResponse response=new GetProductResponse();
ProductInfo productInfo=new ProductInfo();
BeanUtils.copyProperties(productService.getProductById(request.getProductId()),productInfo);
response.setProductInfo(productInfo);
return response;
}
}
SoapUI
enter image description here
here is what I got in soapUi.
I do not have any idea what should I do to make it correct, I saw many questions regarding this problem but did not find any solution.
I also had the same issue. At that time I change the version of java to 1.8 in pom.xml file
I have an endpoint in RestController. When request would be processed , there must performed redirecting to another URL and There need to pass one parameters in redirect URL.
#RestController
#RequiredArgsConstructor
#Slf4j
public class RestControllerImpl {
#Value("${uri-root}")
private String uriRoot;
private final Service service;
#PostMapping("/api")
public RedirectView performRequest(#RequestBody Transaction dto) {
service.perform(dto);
String referenceToken = "sldflh#2lhf*shdjkla"
String urlRedirect = uriRoot + "?token=" + referenceToken;
return new RedirectView(urlRedirect);
}
}
The code above doesn't work for me.
I was looking for information on stackoverflow, but it suggests either using ModelAndView or RedirectAttributes attributes. But I need endpoint to accept a Post request that would bring data that will be processed in the service layer.
It is not possible to complete this task. Could someone explain how this can work and how such a task can be accomplished ?
It worked.
#RestController
#RequiredArgsConstructor
#Slf4j
public class RestControllerImpl {
#Value("${uri-root}")
private String uriRoot;
private final Service service;
#PostMapping("/api")
public ResponseEntity createClient(#RequestBody Transaction dto) throws URISyntaxException {
service.perform(dto);
String referenceToken = "sldflh#2lhf*shdjkla"
String urlRedirect = uriRoot + "?token=" + referenceToken;
return ResponseEntity.created(new URI(urlRedirect)).build();
}
}
I created a spring REST web service using spring boot. It accepts XML in requestbody. The problem is, it accepting unwanted tags also and giving the results, which I want to restrict and notify user about this.
How can i validate the request body (xml) against xsd before it reaches controller or by any other way. Please suggest.
Controller:
#PostMapping(value = "/webservice/{text}", produces = { MediaType.APPLICATION_XML_VALUE })
public ServiceResult processRequest(#PathVariable("text") String text,
#RequestBody Request Request) {
Beans:
#XmlRootElement(name="Request")
#XmlType(propOrder = {"requestHeader", "requestBody"})
public class Request implements Serializable {
private RequestHeader requestHeader;
private RequestBody requestBody;
#XmlElement(name="RequestHeader")
public RequestHeader getRequestHeader() {
return requestHeader;
}
public void setRequestHeader(RequestHeader requestHeader) {
this.requestHeader = requestHeader;
}
#XmlElement(name="RequestBody")
public RequestBody getRequestBody() {
return requestBody;
}
public void setRequestBody(RequestBody requestBody) {
this.requestBody = requestBody;
}
}
Then you might want to fail on unwanted tags: https://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/DeserializationFeature.html#FAIL_ON_UNKNOWN_PROPERTIES
Also, if you can make use of bean validation to validate the values. However, this validation has nothing to do with xsd
Adding the below property to application.properties files solved my problem.
spring.jackson.deserialization.fail-on-unknown-properties=true
I have a service defined as follow
class Echo {
private String message; // getters and setters omitted
}
#RequestMapping("/app")
interface Resource {
#RequestMapping(method = GET)
Echo echo(#ModelAttribute Echo msg);
}
#RestController
class ResourceImpl implements Resource {
#Override
Echo echo(Echo msg) { return msg; }
}
and his client on a different application
#FeignClient(name = "app", url = "http://localhost:8080")
interface Client extends Resource {}
However, when I call resource method
#Autowired
private Resource client;
#Test
public void test() {
Echo echo = new Echo();
echo.setMessage("hello");
client.echo(echo);
}
I got a confusing error message
feign.FeignException: status 405 reading ClientLocal#echo(Echo);
content: {"timestamp":1512686240485,"status":405,"error":"Method Not
Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request
method 'POST' not supported","path":"/app"}
What I did wrong here?
Found the same issue and for me the reason of POST with GET mixing by Feign is usage of Object as request param
was with same error as yours:
#GetMapping("/followers/{userId}/id")
Page<String> getFollowersIds(#PathVariable String userId, Pageable pageable);
added #RequstParam for 2 argument fixed it, like:
#GetMapping("/followers/{userId}/id")
Page<String> getFollowersIds(#PathVariable String userId, #RequestParam Pageable pageable);
We have written a service controller for providing rest services in spring which is like---
#Controller
public class ServicesController {
//first service
#ResponseBody
#RequestMapping(value = "/emailDomainValidate", method = RequestMethod.POST, headers = { jsonContentType })
public List<String> emailDomailValidate(#RequestBody EmailDomainValidateVO emailDomainValidate) {
List<String> errorCodes = getEmailDomainValidationService().emailDomainValidation(
emailDomainValidate);
}
//second service
#ResponseBody
#RequestMapping(value = "/changePassword", method = RequestMethod.POST, headers = { jsonContentType })
public List<String> changePassword(#RequestBody ChangePasswordVO changePasswordVO) {
List<String> passwords = getChangePasswordFacade().changePassword(changePasswordVO);
}
}
In web.xml we have provided
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
when we are accessing one of the service by making a rest call----http://"url":8080/service/emailDomainValidate --- this is working
but when we are accessing the other service
http://"url":8080/service/changePassword--- this is not working and is giving us 400 http error code
The steps we have executed so far are ----
deleting the temp directory for the server.
redeployment
change the input class vo for the service which is not working----ChangePasswordVO
please let me why this is still not working when every other service provided is working
Thanks a lot
Try adding a mapping to the controller then add mapping to your methods. This is working for me at least:
#Controller
#RequestMapping('/rest')
public class ServicesController {
private static final Log log = LogFactory.getLog(ExampleRestController.class);
#ResponseBody
#RequestMapping(value = "/emailDomainValidate", method = RequestMethod.POST, headers = { jsonContentType })
public List<String> emailDomailValidate(#RequestBody EmailDomainValidateVO emailDomainValidate) {
if(log.isDebugEnabled()) log.debug('emailDomainValidate hit');
List<String> errorCodes = getEmailDomainValidationService().emailDomainValidation(emailDomainValidate);
}
//second service
#ResponseBody
#RequestMapping(value = "/changePassword", method = RequestMethod.POST, headers = { jsonContentType })
public List<String> changePassword(#RequestBody ChangePasswordVO changePasswordVO) {
if(log.isDebugEnabled()) log.debug('change password hit');
List<String> passwords = getChangePasswordFacade().changePassword(changePasswordVO);
}
}
You then would post to:
http://localhost:8080/service/rest/emailDomainValidate
http://localhost:8080/service/rest/changePassword