Dynamic Request body REST API Method using swagger - java

I have use case were I need to get requestBody based on selection of field.below is same code which I was able get the dynamic responseBody Based on selection ProtocolType.Is there is any way that swagger can read the RequestBody Dynamically.
Controller.Java
#ApiOperation(value = "Protocol Account", tags = {"ProtocolAccount"})
#RequestMapping(value = "/protocolAccount/{protocolName}",
method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody public ProtocolAccount getProtocol(#PathVariable String protocolName)
{
return service.getProtocol(protocolName);
}
Service.Java
public ProtocolAccount getProtocol(String protocolName){
ProtocolAccount protocolAccount=new ProtocolAccount();
Object object=ProtocolType.fromMap(protocolName);
protocolAccount.setProtocol(object);
return protocolAccount;
}
POJOs
public class ProtocolAccount
{
String Id;
private Object protocolType
}
public class Protocol{
private String port;
}
public class FTPProtocol extends Protocol{
/*Some Fields*/
}
public class SFTPProtocol extends Protocol{
/*Some Fields*/
}
Enumeration
public enum ProtocolType
{
SFTP("SFTP"), FTPS("FTPS"), AS2("AS2"), FTP("FTP");
private final String value;
private static final EnumMap<ProtocolType,
Object>map = new EnumMap<ProtocolType, Object>(ProtocolType.class);
static{
map.put(ProtocolType.SFTP, new SFTPProtocol());
map.put(ProtocolType.FTP, new FTPProtocol());
map.put(ProtocolType.FTPS,new FTPSProtocol());
}
ProtocolType(String v){
value=v;
}
public static ProtocolType fromValue(String val){
return EnumSet.allOf(ProtocolType.class)
.stream().filter(e->e.value.equals(val))
.findFirst().orElseThrow(()->new IllegalArgumentException(val));
}
public String value(){
return value;
}
public static Object fromMap(String value)
{
return map.get(ProtocolType.fromValue(value));
}
}

Related

Creating a string list from RestTemplate

I am using restTemplate to retrieve data from a url, and I get it as a List of Objects but I need a List of Strings to be able to filter it (I want to remove duplicates and change some attribute names).
This is my Template:
public static Provinces restTemplateProvince(RestTemplate restTemplate) {
String ProvinceCommunityURL = "https://www.el-tiempo.net/api/json/v2/provincias";
Provinces province = restTemplate.getForObject(ProvinceCommunityURL, Provinces.class);
return province;
}
Now I want to filter this data and show it in my own API. I'm able to show it with the following:
RestController
public class ShowcaseController {
#Autowired
ProvinceService provinceService;
#GetMapping("/provinces")
public Provinces getAllProvinces(){
return provinceService.getAllProvinces();
}
}
#Service
public class ProvinceService {
#Autowired
RestTemplate restTemplate;
public Provinces getAllProvinces(){
Provinces listOfProvinces = Templates.restTemplateProvince(searchList);
return listOfProvinces;
}
}
But I can't filter it in this list type.
How could I do it?
My Province class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Provinces {
#JsonProperty("provincial")
private List<ProvincesData> provinces;
public Provinces(){}
public Provinces(List<ProvincesData> provinces) {
this.provinces = provinces;
}
#JsonProperty("provincial")
public List<ProvincesData> getprovinces() {
return provinces;
}
#JsonProperty("Test")
public void setprovinces(List<ProvincesData> provinces) {
this.provinces = provinces;
}
}
And ProvinceData class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class ProvincesData {
#JsonProperty("CODPROV")
private String codProv;
#JsonProperty("NOMBRE_PROVINCIA")
private String nomeProvincia;
#JsonProperty("CODAUTON")
private String codAuton;
#JsonProperty("COMUNIDAD_CIUDAD_AUTONOMA")
private String comunidadeCidadeAutonoma;
public ProvincesData(){
}
public ProvincesData(String codProv, String nomeProvincia, String codAuton, String comunidadeCidadeAutonoma){
this.codProv = codProv;
this.nomeProvincia = nomeProvincia;
this.codAuton = codAuton;
this.comunidadeCidadeAutonoma = comunidadeCidadeAutonoma;
}
#JsonProperty("CODPROV")
public String getCodProv() {
return codProv;
}
#JsonProperty("Test")
public void setCodProv(String codProv) {
this.codProv = codProv;
}
public String getNomeProvincia() {
return nomeProvincia;
}
public void setNomeProvincia(String nomeProvincia) {
this.nomeProvincia = nomeProvincia;
}
public String getCodAuton() {
return codAuton;
}
public void setCodAuton(String codAuton) {
this.codAuton = codAuton;
}
public String getComunidadeCidadeAutonoma() {
return comunidadeCidadeAutonoma;
}
public void setComunidadeCidadeAutonoma(String comunidadeCidadeAutonoma) {
this.comunidadeCidadeAutonoma = comunidadeCidadeAutonoma;
}
}
The filter to isolate the codAuton and comunidadeCidadeAutonoma columns without repeating. If possible, build a new list with only the data I want and change de variable name so that I can then show them in my API with different titles and such.
Regards.
Update your service to something like:
public static Provinces restTemplateProvince(RestTemplate restTemplate) {
String ProvinceCommunityURL = "https://www.el-tiempo.net/api/json/v2/provincias";
Provinces province = restTemplate.getForObject(ProvinceCommunityURL, Provinces.class);
List<String> included = new ArrayList<>();
List<ProvincesData> filtered = province.getprovinces()
.stream().filter(p -> {
if (included.contains(p.getCodAuton())) {
return false;
} else {
included.add(p.getCodAuton());
return true;
}
})
.collect(Collectors.toList());
province.setprovinces(filtered);
return province;
}
Could be done more efficiently but it is probably more readable like this.

How to Use DI to get a final variable as #PostMapping's path

I have a final class Constants, which holds some final data.
#Component
public final class Constants {
public final String TOKEN;
public final String HOST;
public final String TELEGRAM;
public Constants(#Value("${myapp.bot-token}") String token,
#Value("${myapp.host}") String host) {
this.TOKEN = token;
this.HOST = host;
this.TELEGRAM = "https://api.telegram.org/bot" + TOKEN;
}
}
The problem is that, when I want to use a variable as #PostMapping path, I faced this error:
Attribute value must be constant
#RestController
#RequestMapping
public class Controller {
private final Constants constants;
#Autowired
public Controller(Constants constants) {
this.constants = constants;
}
#PostMapping(constants.TOKEN)// Problem is here
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
I've tried to load TOKEN in my controller class but faced the same issue.
#RestController
#RequestMapping
public class Controller {
#Value("${myapp.bot-token}") String token
private String token;
#PostMapping(token)// Problem is here
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
When I do something like this the problem will gone. But I don't want to declare my token in source-code.
#RestController
#RequestMapping
public class Controller {
private final String TOKEN = "SOME-TOKEN";
#PostMapping(TOKEN)// No problem
public ResponseEntity<?> getMessage(#RequestBody String payload) {
return new ResponseEntity<HttpStatus>(HttpStatus.OK);
}
}
Can anyone please give me a solution to this?
Try to paste string with property path inside #PostMapping annotation. Like this
#GetMapping(value = "${app.path}")
public String hello() {
return "hello";
}
You can only use a constant (i.e. a final static variable) as the parameter for an annotation.
Example:
#Component
class Constants {
public final static String FACEBOOK = "facebook";
}
#RestController
class Controller {
#PostMapping(Constants.FACEBOOK)
public ResponseEntity<ResponseBody> getMessage(#RequestBody String payload) {
return new ResponseEntity<>(HttpStatus.OK);
}
}
You must use builder pattern(use Lombok for ease) and freeze the value that you are getting from the properties and then use that in your program.

Unable to parse json with List elements inside it

I have a Java class which has 2 List Object inside it and i am Json serializing the parent class.
#JsonSerialize
public class RequestSalesJson {
#JsonProperty("nonUniqueSalesList")
private List<SalesDataJson> getNonUniqueSalesDataJson;
#JsonProperty("uniqueSalesList")
private List<SalesDataJson> uniqueSalesDataJson;
public List<SalesDataJson> getGetNonUniqueSalesDataJson() {
return getNonUniqueSalesDataJson;
}
public void setGetNonUniqueSalesDataJson(List<SalesDataJson> getNonUniqueSalesDataJson) {
this.getNonUniqueSalesDataJson = getNonUniqueSalesDataJson;
}
public List<SalesDataJson> getUniqueSalesDataJson() {
return uniqueSalesDataJson;
}
public void setUniqueSalesDataJson(List<SalesDataJson> uniqueSalesDataJson) {
this.uniqueSalesDataJson = uniqueSalesDataJson;
}
}
SalesReturnJson.java
#JsonSerialize
public class SalesReturnJson {
#JsonProperty("starttime")
private String startTime;
#JsonProperty("pn")
private String partNumber;
#JsonProperty("so")
private String SalesOrderNumber;
#JsonProperty("wo")
private String workOrderNumber;
#JsonProperty("loc")
//other variables declared..
}
Controller.java :-
#RequestMapping(value = "/addAllSalesData",method = RequestMethod.POST)
public void addAllSalesData(#RequestBody RequestSalesJson requestSalesJsons){
log.info("POST : '/addSalesData'");
try{
System.out.print("In Controller "+requestSalesJsons.getUniqueSalesDataJson());
//salesService.processSalesData(requestSalesJsons);
}
catch(Exception e){
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
}
The value here is coming to be null.
Below is the json i am using :-
{ "uniqueSalesJson": [{"SO":4000955,"Part Number":"000","Locator":255638,"Lot Number":"P01-2059139","Reservation Quantity":2,"Status":"Released to warehouse","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"},{"SO":4000955,"Part Number":"000","Locator":255652,"Lot Number":"P01-2059140","Reservation Quantity":10,"Status":"Released to warehouse","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"}],"nonUniqueSalesJson":[{"SO":4000992,"Part Number":"1276M84G15","Locator":12345,"Lot Number":"P01-2344141","Reservation Quantity":6,"Status":"PACKED","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"},{"SO":4000992,"Part Number":"1276M84G15","Locator":12345,"Lot Number":"P01-2344141","Reservation Quantity":6,"Status":"PICKED","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"}]}
There are some issues in your code that let me doubt that your application compiles. First of all, rename the SalesReturnJson class to SalesDataJson.
Then check your #JsonProperty annotations. The value here must match exactly the property key in the Json String. Refactoring all this stuff will lead you to your root entity class:
#JsonSerialize
public class RequestSalesJson {
#JsonProperty("nonUniqueSalesJson")
private List<SalesDataJson> nonUniqueSalesDataJson;
#JsonProperty("uniqueSalesJson")
private List<SalesDataJson> uniqueSalesDataJson;
...
}
and your SalesDataJson class (missing a lot of attributes which the mapper ignores by configuration):
#JsonSerialize
public class SalesDataJson {
#JsonProperty("Start_Time")
private String startTime;
#JsonProperty("Part Number")
private String partNumber;
#JsonProperty("SO")
private String SalesOrderNumber;
}
This sample works as expected with the com.fasterxml.jackson.databind.ObjectMapper
Hope that helps!

Converting request parameters to the Class object

I have two POJO classes.
Class 1 is Engine.java:
private String engineId;
public String getEngineId(){
return this.engineId;
}
public void setEngineId(String engineId){
this.engineId = engineId;
}
The Second POJO class is Vehicle.java:
private String type;
private String manufacturer;
private Engine engine;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
I have a REST Controller for providing information of Vechicles (RequestMethod.GET):
#RequestMapping(method = RequestMethod.GET)
public Vehicle getVechileDetails(Vehicle inputVehicle){
Vehicle vehicle = new Vehicle();
// some processing
return vehicle;
}
When I hit this service and provide the Request parameter as type or manufacturer, then the Spring creates the Vehicle object and populates the value of type and manufacturer. But if I provide the value of engineId, then the Spring is not able to create the Engine object such that vehicle.getEngine().getEngineId() != null
Is there any way in which if I invoke my Rest Service like:
http://localhost:8080/Controller/getVehicleDetails?engineId=12345
then the Vehicle is created with Engine having the value of engineId ?
You can get the vehicleId like this (ResponseEntity structure is included):
#RequestMapping(value = "/Controller/getVehicleDetails", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public
#ResponseBody
ResponseEntity<AjaxResponse> controller(#RequestParam(value = "engineId") Long engineId) {
//Do whatever you want with the engineId
return new ResponseEntity<AjaxResponse>(new AjaxResponse("Success"), HttpStatus.OK);
}
But, for POJOs, I have to warn two things:
Make sure your classes implement Serializable
For the fields which are not certain while converting from Java to Javascript or vice versa, like Date variables, You have to set your JsonSerializer class properly
Update: You wanted to get the object from request, so:
#RequestMapping(value = "/Controller/getVehicleDetails", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, , consumes = MediaType.APPLICATION_JSON_VALUE)
public
#ResponseBody
ResponseEntity<AjaxResponse> controller(#RequestBody Vehicle vehicle) {
//vehicle.getEngine().getEngineId()
return new ResponseEntity<AjaxResponse>(new AjaxResponse("Success"), HttpStatus.OK);
}
POJOS:
public class Engine implements Serializable {
//...
}
public class Vehicle implements Serializable {
private Engine engine;
}
JS side:
var vehicle = {
engine: {id: 123}//,
//...
}
//via angularjs:
$http.post("http://localhost:8080/Controller/getVehicleDetails", vehicle).success(function(response) {
console.log("success");
});
Here you can refer , where the request body has JSON which converted to Object
See : For references
#RequestMapping(value = EmpRestURIConstants.CREATE_EMP, method = RequestMethod.POST)
public #ResponseBody Employee createEmployee(#RequestBody Employee emp) {
logger.info("Start createEmployee.");
emp.setCreatedDate(new Date());
empData.put(emp.getId(), emp);
return emp;
}

Nested JSON Object (Retrofit)

I'm using Retrofit to send picture request and receive this Json
{"response":{
"face":{
"value":"true",
"confidence":55
},
"gender":{
"value":"male",
"confidence":73
},
...
}}
and I'm receiving it with Retrofit....
RestAdapter adapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(END_POINT)
.build();
Mylistenerr listener = adapter.create(Mylistenerr.class);
File photo = new File(picturePath);
TypedFile image = new TypedFile("multipart/image/jpg", photo);
listener.setUserImage(
image,
new Callback<respostring>() {
#Override
public void success(respostring rp, Response arg1) {}
#Override
public void failure(RetrofitError arg0) {
pd.hide();
pd.dismiss();
Log.d("ERROR:", arg0.getLocalizedMessage());
}
});
}
private static class respostring {
private Content face;
private Content gender;
respostring() {}
}
class Content
{
private int confidence;
private String value;
Content(){}
public int getconf(){
return this.confidence;
}
public String getvalue(){
return this.value;
}
}
My interface
public interface Mylistenerr {
#Multipart
#POST("/public/test")
void setUserImage(
#Part("image") TypedFile file,
Callback<respostring> response);
}
but there is retrofit error. Is there something I miss here?
I'd recommend you using Gson for json deserialization instead since retrofit supports it very well. Then you can just create classes like this:
Your face class:
public class Face implements Serializable {
#SerializedName("value")
public boolean value;
#SerializedName("confidence")
public int confidence;
}
Your gender class:
public class Gender implements Serializable {
#SerializedName("value")
public String value;
#SerializedName("confidence")
public int confidence;
}
your response class:
public class YourResponseType implements Serializable {
#SerializedName("face")
public Face face;
#SerializedName("gender")
public Gender gender;
}
Then you can actually make retrofit doing the rest for you:
listener.setUserImage(image, new Callback<YourResonseType>() {...});
Hope that helps!

Categories