Hi I have Rest API and used swagger for the test this API.
below is one of my API.
#RequestMapping(value = "/api/test", method = RequestMethod.POST)
public void test(String string){
// body
}
The Possible value for the arguments are "Database" or "Cache".
So i want drop down in swagger view.
I have gone through the google search , i can not found how to implement with java.
You have to use Enum as your method argument instead of String. See below reference:
#RequestMapping(value = "/api/test", method = RequestMethod.POST)
public void test(TestEnum enum) {
// body
}
And below is your TestEnum:
public enum TestEnum {
Dropdown1("DropDown1"),
DropDown2("DropDown2");
private String str;
TestEnum(String str){
this.str = str;
}
public String getStr() {
return str;
}
}
You can annotate your parameter with the possible values
#RequestMapping(value = "/api/test", method = RequestMethod.POST)
public void test(#ApiParam(allowableValues = "one, two, three") String string) {
// body
}
Related
I have a user table in my database with 2 fields id and name. I want to create an API to delete a user on the bases of id or name. Like this:
#DeleteMapping(path = "/{name}")
public ResponseEntity<Object> clearUser(#PathVariable("name") String name){
myService.deleteUser(name);
return new ResponseEntity<>(HttpStatus.OK);
}
#DeleteMapping(path = "/{id}")
public ResponseEntity<Object> clearUser(#PathVariable("id") int id){
myService.deleteUser(id);
return new ResponseEntity<>(HttpStatus.OK);
}
But I want to do it under one #DeleteMapping and I have to do it using path param only not query param. A person can enter id or name to delete that user.
You might use your two path variables as optional.
#DeleteMapping(path = {"/{name}", "/{id}")
public ResponseEntity<Object> clearUser(#PathVariable("name") Optional<String> name, #PathVariable("id") Optional<Integer> id){
myService.deleteByIdOrName(id, name);
return new ResponseEntity<>(HttpStatus.OK);
}
MyRepo ...
void deleteByIdOrName(Optional<Integer> id, Optional<String> name);
MyService
void deleteByIdOrName(Optional<Integer> id, Optional<String> name) {
repo.deleteByIdOrName(id, name);
}
Just check the path parameter type whether it is numeric or a String. Based on that, you can change the implementation under one method. just a hint:
#DeleteMapping(path = "/{user}")
public ResponseEntity clearUser(#PathVariable("user") String user){
myService.deleteUser(user);
return new ResponseEntity<>(HttpStatus.OK);
}
and inside the implementation, do the following:
use Java's built-in java.text.NumberFormat object to see if, after
parsing the string the parser position is at the end of the string. If
it is, we can assume the entire string is numeric:
public static boolean isNumeric(String str) {
NumberFormat formatter =
NumberFormat.getInstance();
ParsePosition pos = new
ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
....
if(isNumeric(user)){
// implement delete by ID
}else{
//implement delete by Name
}
....
Hope this will give you an idea..
I have a Switch that contains 13 case, each case executes a different sql request. I got the result in an ArrayList<HashMap<String, String>>. This result is supposed to be displayed with angular , for now i'm using this this.respTest = JSON.stringify(response); so it displays a list of "key":"value" .
My problem is since each request gets me different database fields and values ,so I want to merge some fields .
I created this class :
public class DataCollect {
private String type ;
private String entity ;
private String modPar ;
private String dateModif ;
private String numVersion ;
public DataCollect(String type, String entity, String modPar, String dateModif, String numVersion) {
this.type = type;
this.entity = entity;
this.modPar = modPar;
this.dateModif = dateModif;
this.numVersion = numVersion;
}
public DataCollect() {
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getEntity() {
return entity;
}
public void setEntity(String entity) {
this.entity = entity;
}
public String getModPar() {
return modPar;
}
public void setModPar(String modPar) {
this.modPar = modPar;
}
public String getDateModif() {
return dateModif;
}
public void setDateModif(String dateModif) {
this.dateModif = dateModif;
}
public String getNumVersion() {
return numVersion;
}
public void setNumVersion(String numVersion) {
this.numVersion = numVersion;
} }
In this class I'm supposed to affect the fields' names to the variables that I created and as a return an arraylist of hashmap with the data I extracted from the data base.
I mean I used to return for example "field-name":"value" , I want to return "type":"value","entity":"value" ..etc
I'm using springboot for the backend and angular 5 for the front.
Any help would be appreciated.
What you essentially want is a way to map keys in [each of] your hashmap to the corresponding member variable in the "DataCollect" POJO.
If there is a one to one mapping between the key present and corresponding member variable, you can expose a public constructor in "DataCollect" that takes in the hash map and constructs the corresponding object.
public DataCollect(Map<String, String> result) {
this.type = result.get("type");
this.entity = result.get("db_entity_key");
...
}
If there is no one on one mapping, you'd have to create a factory class, which takes your Map as an input and some context, and returns you the constructed DataCollect object.
Once you have the constructor or the factory class, you only need to iterate over your results list and do the needful to convert each Map into the DataCollect object.
Your controller should automatically serialise the DataCollect objects to corresponding JSON, or you can even use Jackson's ObjectMapper to achieve the same.
We are parsing okhttp response objects using GSON.
In order to allow a generic parsing logic, We had opened to pass a type of response using setType(Type type) and now using below code to parse all responses.
Object mResponse = mGson.fromJson(response.body().string(), mType);
As this code is not open for a change I have extended this class and overridden the parse response method. I have also created a new class called MyRespose and want to initialize with whatever type is passed in setType method so that the consumers are returned the object of what type they have passed instead of an instance of Object class.
public class MyResponse<T> {
private int mStatus;
private T mResponseData;
public MyResponse(int status, T responseBody) {
this.mStatus = status;
mResponseData = responseBody;
}
public MyResponse(T responseBody) {
mResponseData = responseBody;
}
public int getStatus() {
return mStatus;
}
public void setStatus(int status) {
this.mStatus = status;
}
public T getResponseData() {
return mResponseData;
}
public void setResponseData(T responseData) {
mResponseData = responseData;
}
}
How can I use the Type(interface) to pass as so that the when someone calls getResponseData it return the object of type which is passed in setType instead of a generic Object ?
Something like
Object mResponse = mGson.fromJson(response.body().string(), mType);
mMyResponse = new MyResponse<???>(response.code(), mResponse );
How can i use mType to pass at place of "???"
I think, you can make use of TypeToken here. Its included in Gson and should go like this.
Type responseType = new TypeToken<MyResponse<XYZ>>() {}.getType();
gson.fromJson(json, responseType);
You can read further on this here
suppose I have the following simple rest defined:
#RequestMapping("/user/data")
#ResponseBody
public String getUserDetails(#RequestParam int id) {
...
}
Is there a way to read the path string problematically by another part of the code (i.e. from a different method altogether) ?
Something like:
String restPath = SomeReflection.getPath("getuserdetails"); // received value: "/user/data"
WDYT?
thanks!
Solved!
here's the implementation I needed:
public String getUrlFromRestMethod(Class controllerClass, String methodName) {
try {
Method method = controllerClass.getMethod(methodName);
if (method != null && method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMappingAnnotation = method.getAnnotation(RequestMapping.class);
return requestMappingAnnotation.toString();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();//TODO
}
return null;
}
If you mean that you wanna access that value programmatically even from another class, then maybe you can start working out your solution from this example:
//get all methods defined in ClassA
Method[] methods = ClassA.class.getMethods();
for (Method m : methods) {
//pick only the ones annotated with "#RequestMapping"
if (m.isAnnotationPresent(RequestMapping.class)) {
RequestMapping ta = m.getAnnotation(RequestMapping.class);
System.out.println(ta.value()[0].toString());
}
}
I would suggest you add a HttpServletRequest request in your method, and then from there go request.getServletPath()
ei
public String getUserDetails(HttpServletRequest request, #RequestParam int id) {
Or if this is done in Spring http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-requestmapping
#RequestMapping(path = "/{day}", method = RequestMethod.GET)
public Map<String, Appointment> getForDay(#PathVariable #DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
return appointmentBook.getAppointmentsForDay(day);
}
#RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(#PathVariable String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner";
}
maybe u can call its value.
I'm a new member in Restful API, I'm writing a GET method:
#RequestMapping(method = RequestMethod.GET, value = "/resourcerecords", produces={"application/json", "application/xml"})
public #ResponseBody Object getRRs(#RequestBody RRRequest requestBody){
// do something
}
The RRRequest class:
public class RRRequest{
private RRREC reqObject;
// getter and setter
}
The RRREC class:
public class RRREC{
protected String infraAddr;
protected RRINFRATYPE infraType;
// getter and setter
}
And the RRINFRATYPE class:
public enum RRINFRATYPE {
V_6_ADDRESS("V6ADDRESS"),
OBJECT("OBJECT"),
ZONE("ZONE"),
V_4_REVERSEZONE("V4REVERSEZONE"),
V_6_REVERSEZONE("V6REVERSEZONE"),
NODE("NODE"),
ALL("ALL");
private final String value;
RRINFRATYPE(String v) {
value = v;
}
public String value() {
return value;
}
public static RRINFRATYPE fromValue(String v) {
for (RRINFRATYPE c: RRINFRATYPE.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}
Then, I sent a request GET with RequestBody ( I use Fiddler Web Debugger)
"reqObject" : {
"infraAddr" : "192.168.88.4",
"infraType": {
"value": "OBJECT"
}
}
I get 400 Bad Request. If I change to
"reqObject" : {
"infraAddr" : "192.168.88.4",
"InfraType": {
"value": "OBJECT"
}
}
I can debug.
However, The reqObject only receive infraAddr with "192.168.88.4", the InfraType is null.
Who can explain to me, why I must be use "InfraType" instead of "infraType" and how to send value for InfraType.
The first one is when your api in GET method you still cant send body of request to server, try to change it to POST.
Because you use ENUM in your Object so you should define a converter like Converting JSON to Enum type with #RequestBody
But in this case, I think the fastest way is change infraType to String and use switch case with String on server side.
public class RRREC{
protected String infraAddr;
protected String infraType;
// getter and setter
}
Your JSON will be:
{
"reqObject" : {
"infraAddr" : "192.168.88.4",
"infraType": "OBJECT"
}
}