Spring RestTemplate Row Mapper - rest

Java - spring RestTemplate
using following code to get rest response
PropsNotMatchClass notMatchClass;
ResponseEntity<PerfectPropsMatchClass> resp= restTemplate.getForEntity(url, PerfectPropsMatchClass.class)
PerfectPropsMatchClass props = resp.getBody();
i had to create PerfectPropsMatchClass class b/c my PropsNotMatchClass didn't had exact names as in returned response. is there a efficient way i can iterate on each row in response and create objects of PropsNotMatchClass.

You can use ResponseExtractor.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/ResponseExtractor.html
It is used in RestTemplate as such.
<T> T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor, Map<String,?> uriVariables)

Related

Liferay 7.2 Api Rest Session parameter

I have Liferay 7.2.
I created a module rest.
It is possibile to save a variable in session ad use it in other method?
My idea of code is:
#GET
#Path("/save/paramt")
public String jsonSaveParamRequest() throws Exception {
String json = "xx";
//SAVE IN SESSION json
return "ok";
}
#GET
#Path("/get/paramt")
public String jsonGetParamRequest() throws Exception {
String xx= SESSION VARIABLE json
return xx;
}
Saving state in a HTTP session in a REST API is not recommended and should be avoided. Please refer to the discussions here SO:how-to-understand-restful-api-is-stateless.
Technically, I guess this is possible as you can inject the HttpServletRequest as a method param via #Context HttpServletRequest request to your annotated method and use getSession(). But I am not sure if you can rely on that.

Is it possible for a restful webservice to have a parameter in the url?

I was instructed to create webservices ( with Spring-Boot ). My colleague gave me the url of the webservice and it looks like this : http://172.20.40.4:8080/Oxalys_WS/stock/ITM=1559
In general we create a RestController with the url :
#RestController
#RequestMapping("stock")
public class StockController {
#Autowired
private StockService stockService;
#GetMapping(value = "/{code}", produces = "application/json")
public JsonModel getByCode(#PathVariable String code) {
JsonModel jsonModel = new JsonModel();
final Map<String, Object> data = new HashMap<>();
List<Stock> stock = stockService.getByCode(code);
data.put("stock", stock);
data.put("stockTotal", stockService.getTotal(code));
jsonModel.setDatas(data);
return jsonModel;
}
}
So is it normal to create a Restful Spring-Boot webservice with a parameter in the url ?
Spring provides parameter in two standard way.
Query Param : http://172.20.40.4:8080/Oxalys_WS/stock?ITM=1559
Path Variable : http://172.20.40.4:8080/Oxalys_WS/stock/1559
Query Param :- It is a typical old way to pass some value as QueryParam with using of some variable starts with ?(Question Mark) and value is assigned using =(equals).
PathVariable :- this is a newer pattern introduce for REST-api Services. URL must be structured such in a way that this should not look too messy if multiple parameters need to pass within a URL.
For more info Navigate this link
Yes, you can have the one in your URL
When you are required to have the path variable, you can give in the Request URL

Wiremock: choose body file name based on request parameter

I am using wiremock to mock http server and I am returning responses from json files (using withBodyFile method).
Now I want to choose and return response json file based on request parameter. For the example below, I want to define one stub so that the body file is chosen based on request parameter.
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key1"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key1.json")
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key2"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key2.json")
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key3"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key3.json")
Any idea how this would be possible? I tried defining transformer but it was not possible to get Stream Source Path from Response object in overridden method so can't use that appraoch. Thanks a lot..
Body File name can't be parameterized in wiremock as of now. I had a similar requirement, I needed to return the file based on the request URL. So I implemented a transformer as below:
public class BodyFileNameResponseTransformer extends ResponseDefinitionTransformer {
public ResponseDefinition transform(Request request, ResponseDefinition rd,
FileSource fileSource, Parameters parameters) {
if (rd.getBodyFileName().startsWith("{{")) {
return new ResponseDefinitionBuilder().**withBodyFile**(request.getUrl().substring(1))
.withStatus(rd.getStatus())
.withHeaders(rd.getHeaders())
.withTransformers(
rd.getTransformers().toArray(new String[rd.getTransformers().size()]))
.build();
}
return rd;
}
public String getName() {
return "BodyFileNameTransformer";
}
}
you can use request.queryParameter(key) instead of request.getUrl() and form any
file path. Create the file path based on your need and set it as bodyFile on returned ResponseDefinition.
Don't forget to start wiremock with --extensions: Extension class names
More details at Extending Wiremock
This is possible by using the inbuilt template helpers provided by Handlebar.
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key3"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_{{request.query.key}}.json")
Check for the various models available at http://wiremock.org/docs/response-templating/.

Send http request with encoded URI

I m trying to send http request as follows, using citrus test framework http://www.citrusframework.org/
http().client(ENV).post("/xx/v1/ouxxtbound/tel%3A%2B94xxxxxxx")
.header("Authorization", authorization)**strong text**
.header("Accept", "application/json")
.payload(send)
.contentType("application/json");
its is passing a url encoded values, but when it encode again when sending request by Citrus.as tel%253A%252B94xxxxxxx
Is there are way to send encoded URI correctly?
Citrus uses the following method on the Spring RestTemplate
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {
...
}
The url is given as String value and Spring will automatically encode this value. When passing in some already encoded String the encoding is done twice. When using non-encoded String value the Spring RestTemplate applies uriVariables logic which is also causing errors.
Citrus should use some other method signature on the RestTemplate that uses the URL object instead of String value. As a temporary workaround you can use a custom RestTemplate subclass that overwrites the methods like this and automatically creates the URL object from String:
#Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {
return super.exchange(URI.create(url), method, requestEntity, responseType);
}
You can add the custom RestTemplate subclass as Spring bean into the configuration and reference the bean on the Citrus client component by using the attribute rest-template.

Xpage REST service control and service bean

I am trying to implement REST Service using XPage REST Service Control. I have opted for "customRESTService".
I would like to emit JSON when this service is requested. I can write logic in Server Side Java Script.
But I noticed that this customRESTService also supports "serviceBean", meaning I can write whole logic in pure JAVA.
I have given below code of the bean. I have declared it in faces-config.xml as well. But it throws exception while rendering. Has anyone used "serviceBean" in customRESTService?
I appreciate any help!! Thanks!!
public class GetApproverJSON{
public GetApproverJSON(){
System.out.println("Instantiating Bean");
}
public String doGet() throws NotesException{
JSONObject mainObj = new JSONObject();;
JSONObject itemObj;
try{
mainObj.put("label", "name");
mainObj.put("identifier", "abbr");
itemObj = new JSONObject();
itemObj.put("name", "");
itemObj.put("abbr", "");
mainObj.accumulate("items", itemObj);
return mainObj.toString();
}catch(Exception e){
System.out.println("Exception occured while generating JSON ");
e.printStackTrace();
return mainObj.toString();
}finally{
}
}
Error :
com.ibm.domino.services.ServiceException: Error while rendering service
at com.ibm.xsp.extlib.component.rest.CustomService$ScriptServiceEngine.renderService(CustomService.java:304)
at com.ibm.domino.services.HttpServiceEngine.processRequest(HttpServiceEngine.java:167)
at com.ibm.xsp.extlib.component.rest.UIBaseRestService._processAjaxRequest(UIBaseRestService.java:252)
at com.ibm.xsp.extlib.component.rest.UIBaseRestService.processAjaxRequest(UIBaseRestService.java:229)
at com.ibm.xsp.util.AjaxUtilEx.renderAjaxPartialLifecycle(AjaxUtilEx.java:206)
at com.ibm.xsp.webapp.FacesServletEx.renderAjaxPartial(FacesServletEx.java:221)
at com.ibm.xsp.webapp.FacesServletEx.serviceView(FacesServletEx.java:166)
at com.ibm.xsp.webapp.FacesServlet.service(FacesServlet.java:160)
at com.ibm.xsp.webapp.FacesServletEx.service(FacesServletEx.java:137)
at com.ibm.xsp.webapp.DesignerFacesServlet.service(DesignerFacesServlet.java:103)
at com.ibm.designer.runtime.domino.adapter.ComponentModule.invokeServlet(ComponentModule.java:576)
at com.ibm.domino.xsp.module.nsf.NSFComponentModule.invokeServlet(NSFComponentModule.java:1267)
at com.ibm.designer.runtime.domino.adapter.ComponentModule$AdapterInvoker.invokeServlet(ComponentModule.java:847)
at com.ibm.designer.runtime.domino.adapter.ComponentModule$ServletInvoker.doService(ComponentModule.java:796)
at com.ibm.designer.runtime.domino.adapter.ComponentModule.doService(ComponentModule.java:565)
at com.ibm.domino.xsp.module.nsf.NSFComponentModule.doService(NSFComponentModule.java:1251)
at com.ibm.domino.xsp.module.nsf.NSFService.doServiceInternal(NSFService.java:598)
at com.ibm.domino.xsp.module.nsf.NSFService.doService(NSFService.java:421)
at com.ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:341)
at com.ibm.designer.runtime.domino.adapter.LCDEnvironment.service(LCDEnvironment.java:297)
at com.ibm.domino.xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:272)
Caused by: com.ibm.xsp.FacesExceptionEx: Bean getApproverJSON is not a CustomServiceBean
at com.ibm.xsp.extlib.component.rest.CustomService.findBeanInstance(CustomService.java:226)
at com.ibm.xsp.extlib.component.rest.CustomService$ScriptServiceEngine.renderService(CustomService.java:255)
... 20 more
You need to change your code to:
public class GetApproverJSON{ ...}
to:
public class GetApproverJSON extends CustomServiceBean {
#Override
public void renderService(CustomService service, RestServiceEngine engine) throws ServiceException {
HttpServletRequest request = engine.getHttpRequest();
HttpServletResponse response = engine.getHttpResponse();
response.setHeader("Content-Type", "application/json; charset=UTF-8");
// Here goes your code, get the response writer or stream
}
since that's the interface the REST service is expecting. You will need to implement just renderService. You can get the method (GET, POST etc.) from the request object
I've never used the service bean before, I usually create my own parser with a static doGet method very similar to yours and in the doGet property of the custom REST service make a call to the static doGet method I create. But I think (I'm probably wrong on this count) if you use the service bean it has to be an entire servlet like if you wrote your own actual REST Service, and not just the parser portion.
I've created quite a few of the parsers and have found that a list of maps:
List>
is usually the best approach for building the initial data. I then loop through the list to build my JSON. In the Extension Library there is a class called JsonWriter which makes it very easy to build a JSON Object. Use the JsonWriter like:
StringWriter sw = new StringWriter();
JsonWriter jw = new JsonWriter(sw);
jw.startObject();
jw.startProperty("SomeProperty");
jw.outStringLiteral("SomeValue");
jw.endProperty();
jw.endObject();
return sw.toString();
For a full on example you can take a look at the REST service I built for my JQuery FullCalendar demo. While none of the methods are static (I need to track a couple of properties) you should get the basic idea. But what kicks the whole thing off is a call to the writeJson() method. That is invoked in this custom control.
Those examples should get you going on building your own custom JSON parser and emitting that JSON back to your application.