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..
Related
I have a predicate that I use to filter a list of the same Entity Object:
Predicate<DWHDeal> companyFilter = i -> i.getCompany().equals(company);
I also have to apply the same filter, with the exact same condition on the exact same field, on a list of DTOs where the DTOS is built based on the entity from before:
Predicate<DWHDealDTO> companyFilterDTO = i -> i.getCompany().equals(company);
Is it possible to achieve this without instancing two different predicates? If possible, I would like to achieve this by making only one Predicate.
Assuming getCompany() returns a String you could create Predicate<String>:
Predicate<String> predicate = s -> s.equals(company);
And then using it like:
list.stream()
.filter(dto -> predicate.test(dto.getCompany()))
...
But there is not much benefit since it requires almost the same code.
If equality is only check then you can use static Predicate isEqual(Object targetRef). see java doc https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html#isEqual-java.lang.Object-
class StudentView{
String name;
public StudentView(String name) {
this.name = name;
}
}
class StudentDTO{
String name;
public StudentDTO(String name) {
this.name = name;
}
}
public void testPredicate(){
StudentView studentView= new StudentView("John");
StudentDTO studentDTO = new StudentDTO("Sam");
Predicate p = Predicate.isEqual("John");
System.out.println("Test for Student View "+ p.test(studentView.name));
System.out.println("Test for Student DTO "+ p.test(studentDTO.name));
}
I think you will need a Function<T,R> before using Predicate :
There are two concepts to Function. First is a java.util.function.Function which accepts one argument and produces a result. The second is stream intermediate operation map which converts each element in a stream into another object via the supplied function.
In your case the Function should look like :
Function<DWHDeal, DWHDealDTO> myFunction = new Function<DWHDeal, DWHDealDTO>() {
public DWHDealDTO apply(DWHDeal t) {
return ... ;
}
};
I tried the basic Program as below with success:
static class DWHDeal{
String name;
public DWHDeal(String name) {
this.name = name;
}
}
static class DWHDealDTO{
String name;
public DWHDealDTO(String name) {
this.name = name;
}
}
static Predicate<DWHDealDTO> companyFilter = i -> i.name.equalsIgnoreCase("com");
public static void main(String[] args) {
Function<DWHDeal, DWHDealDTO> myFunction = new Function<DWHDeal, DWHDealDTO>() {
public DWHDealDTO apply(DWHDeal t) {
return new DWHDealDTO("com");
}
};
DWHDeal newDWHDealDTOObj = new DWHDeal("com");
System.out.println(companyFilter.test(myFunction.apply(newDWHDealDTOObj))); //Works
}
As suggested in the comments, the common interface would be the preferred solution.
I guess you could do something like this, but to be fair, it is ugly.
private String getCompany(Object o) {
if(o instanceof DWHDeal)
return ((DWHDeal) o).getCompany();
else
return ((DWHDealDTO) o).getCompany();
}
Predicate<Object> companyFilter = i -> getCompany(i).equals(company);
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.
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
}
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 want to create a String using a format, replacing some tokens in the format with properties from a bean. Is there a library that supports this or am I going to have to create my own implementation?
Let me demonstate with an example. Say I have a bean Person;
public class Person {
private String id;
private String name;
private String age;
//getters and setters
}
I want to be able to specify format strings something like;
"{name} is {age} years old."
"Person id {id} is called {name}."
and automatically populate the format placeholders with values from the bean, something like;
String format = "{name} is {age} old."
Person p = new Person(1, "Fred", "32 years");
String formatted = doFormat(format, person); //returns "Fred is 32 years old."
I've had a look at MessageFormat but this only seems to allow me to pass numeric indexes, not bean properties.
Rolled my own, testing now. Comments welcome.
import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BeanFormatter<E> {
private Matcher matcher;
private static final Pattern pattern = Pattern.compile("\\{(.+?)\\}");
public BeanFormatter(String formatString) {
this.matcher = pattern.matcher(formatString);
}
public String format(E bean) throws Exception {
StringBuffer buffer = new StringBuffer();
try {
matcher.reset();
while (matcher.find()) {
String token = matcher.group(1);
String value = getProperty(bean, token);
matcher.appendReplacement(buffer, value);
}
matcher.appendTail(buffer);
} catch (Exception ex) {
throw new Exception("Error formatting bean " + bean.getClass() + " with format " + matcher.pattern().toString(), ex);
}
return buffer.toString();
}
private String getProperty(E bean, String token) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field field = bean.getClass().getDeclaredField(token);
field.setAccessible(true);
return String.valueOf(field.get(bean));
}
public static void main(String[] args) throws Exception {
String format = "{name} is {age} old.";
Person p = new Person("Fred", "32 years", 1);
BeanFormatter<Person> bf = new BeanFormatter<Person>(format);
String s = bf.format(p);
System.out.println(s);
}
}
Yes, it's possible using the Pojomatic library. Implement and plug in your own implementation of PojoFormatter. Pojomator#doToString(T) may be also interesting.
Don't really know how complex is the model you're up to consume but if you want to deal with object trees I would implement my own formatter using Jexl as expession language this way:
Initialize a singleton Jexl engine
Populate a MapContext with all the objects you want to consume when formatting strings
Parse your strings and create a Jexl expression per "${}" construct you have.
Evaluate the previous created expressions against the object context map.
The good thing about Jexl is that it will allow you to use method calls, not just properties.
Hope it helps.
Not quite close, but you can look at StringTemplate, your bean:
public static class User {
public int id; // template can directly access via u.id
private String name; // template can't access this
public User(int id, String name) { this.id = id; this.name = name; }
public boolean isManager() { return true; } // u.manager
public boolean hasParkingSpot() { return true; } // u.parkingSpot
public String getName() { return name; } // u.name
public String toString() { return id+":"+name; } // u
}
Then you can render it like this:
ST st = new ST("<b>$u.id$</b>: $u.name$", '$', '$');
st.add("u", new User(999, "parrt"));
String result = st.render(); // "<b>999</b>: parrt"
Code sample above taken from ST4 Introduction