Return an empty object Java Spring Boot REST - spring-boot

I'm writing a dto class containing the information of a user
public class User {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
I'd receive this JSON object if I do GET api/v1/user/1
{
firstName: John,
lastName: Kennedy
}
But when the firstName and the lastName are null, I want to receive an empty object like:
{}
How would you do technically on Spring Boot in order to receive such empty object in Json format?
Thank you in advance

You could try to annotate your class with:
#JsonInclude(Include.NON_NULL)

If you want an empty object { } and empty request is not valid for you, you can create an auxiliar class called EmptyObject or something similar:
#JsonSerialize
public class EmptyObject {
}
And into your controller:
return user.getFirstName() == null && user.getLastName() == null ?
ResponseEntity.ok(new EmptyObject()) : ResponseEntity.ok(user);

Related

Springdoc cannot detect POJO's fields to map as individual parameters on UI

My springboot application has a #RestController which takes a POJO class as parameter.
#GetMapping(path="/")
public void sayHello(Person person) {
System.out.println(person);
}
and here's the definition of Person class which is just a POJO.
public class Person {
private String firstName;
private String lastName;
private int age;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Override
public String toString() {
return "Person [firstName=" + firstName + ", lastName=" + lastName + ", age=" + age + "]";
}
}
This is how springdoc-ui interprets it for showing parameters in UI.
I did not use #RequestBody in the controller yet springdoc assumes the input to be in the form of JSON body. I intend it to be as query parameters as below
Interestingly if I change the swagger implementation to springfox, each fields of the POJO is interpreted as individual parameters in the UI by default. The last screenshot was taken using springfox implemntation. How do I get the same behavior with springdoc?
Using #ParameterObject fixes this.
#GetMapping(path="/")
public void sayHello(#ParameterObject Person person) {
System.out.println(person);
}
Found the solution here:
https://github.com/springdoc/springdoc-openapi/issues/162
https://github.com/springdoc/springdoc-openapi/pull/505

Spring MVC #GetMapping #ModelAttribute percent(%) symbol gives null value

Here is my controller:
#CrossOrigin(origins = "http://localhost:3000")
#RestController
#RequestMapping("/api/v1/employees")
public class EmployeeController {
#Autowired
private EmployeeService employeeService;
#GetMapping()
public List<Employee> getEmployeesBySearch(#Valid #ModelAttribute SearchDto searchDto) {
return employeeService.getEmployeesBySearch(searchDto);
}
}
And Here is my SearchDto:
public class SearchDto {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
.
http://localhost:8080/api/v1/employees?firstName=%%%
http://localhost:8080/api/v1/employees?firstName=a%
http://localhost:8080/api/v1/employees?firstName=%a
Whenever there's percent(%) symbol in my GET request, it always give null value.
You should encode it.
https://www.urlencoder.org/
a% -> a%25
%%% -> %25%25%25
name%surname -> name%25surname
Your final url look like below
http://localhost:8080/api/v1/employees?firstName=a%25

Spring JPA QuerydslPredicate Snake Case

I am using spring boot with Query DSL. I have configured my spring boot to use snake case i.e. spring.jackson.property-naming-strategy=SNAKE_CASE. So my json payload input and output is in snake case like below
{
"first_name": "First",
"last_name": "Last"
}
I am using #QuerydslPredicate for my search functionality. If I enter query params in snake case like below
(http://localhost:8080/context/resource/?first_name=First)
it is not parsed by Query DSL Predicate. However, If I provide the params in camel case like below
(http://localhost:8080/context/resource/?firsName=First)
it works fine. This is not synonymous with json structure.
How can I achieve snake case in query params so that Query DSL parses it?
This is how my REST end point looks like
#GetMapping
public ResponseEntity<Output> listUsers(#QuerydslPredicate(root = User.class) Predicate predicate, Pageable pageable) {
...
return new ResponseEntity<>(output, HttpStatus.OK);
}
PN: My Model Object is in camel case like below
Model Object
public class User {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
I came across a solution on HandlerMethodArgumentResolver, but that is lot of work. There should be a way to automate it than doing all model fields.

java 8 streams filter by list over list

I need to filter condition by firstname and lastname in the List of names present in either official or unOfficial names List and return List of EmployeeDetails.
Below are the pojo classes
public class EmployeeDetails {
private NameDetails nameDetails;
public NameDetails getNameDetails() {
return nameDetails;
}
public void setNameDetails(NameDetails nameDetails) {
this.nameDetails = nameDetails;
}
}
public class NameDetails {
private List<Name> officalName;
private List<Name> unOfficialName;
public List<Name> getOfficalName() {
return officalName;
}
public void setOfficalName(List<Name> offiicalName) {
this.officalName = offiicalName;
}
public List<Name> getUnOfficialName() {
return unOfficialName;
}
public void setUnOfficialName(List<Name> unOfficialName) {
this.unOfficialName = unOfficialName;
}
}
public class Name {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
I tried for filtering with list of officialNames and it is working fine,but I also want to filter names present in unOfficial Names also.(OR Condition)
return employeeDetailList.stream().filter(employeeDetails->(employeeDetails.getNameDetails().getOffiicalName()).stream()
.anyMatch(name-> (null!=name) && (firstName).equals(name.getFirstName()) && (lastName).equals(name.getLastName())))
.collect(Collectors.toList());
Help me to solve the issue.Thanks
If you can't override equals/hashCode (if you could there would be a faster way), then:
employeeDetailList
.stream()
.filter(x -> Stream.concat(
x.getNameDetails().getOfficalName().stream(),
x.getNameDetails().getUnOfficialName().stream()
)
.anyMatch(y -> Objects.equals(y.getFirstName(), firstName) &&
Objects.equals(y.getLastName(), lastName)))
.collect(Collectors.toList());
Just add the OR condition:
return employeeDetailList.stream().filter(employeeDetails->
((employeeDetails.getNameDetails().getOffiicalName()).stream().anyMatch(name-> (null!=name) && (firstName).equals(name.getFirstName()) && (lastName).equals(name.getLastName()))))
|| ((employeeDetails.getNameDetails().getUnOfficialName()).stream().anyMatch(name-> (null!=name) && (firstName).equals(name.getFirstName()) && (lastName).equals(name.getLastName()))))
.collect(Collectors.toList());

How can I get multiple properties from a Java POJO using the Java 8 Stream API?

Given this class written in the Java 8 style, I wanted to see if I dont need to call the stream api twice :
import java.util.*;
public class Foo {
public static void main(String... args) {
List<Person> persons = new ArrayList<>();
init(persons, Person::new, "John", "Doe");
persons.stream()
.map(Person::getFirstName)
.forEach(System.out::println);
persons.stream()
.map(Person::getLastName)
.forEach(System.out::println);
}
#FunctionalInterface
interface PersonFactory {
Person create(String firstName, String lastName);
}
private static void init(List<Person> persons, PersonFactory factory, String fn, String ln) {
persons.add(factory.create(fn, ln));
}
}
class Person {
private final String firstName;
private final String lastName;
public Person(String fName, String lName) {
this.firstName = fName;
this.lastName = lName;
}
public String getFirstName() {return this.firstName;}
public String getLastName() {return this.lastName;}
}
I wanted to see if I could instead stream the "persons" List in one go.
Any suggestions ?
If you don't need to transform object to another, you can try this
persons.forEach(i -> System.out.println(i.getFirstName() + " " + i.getLastName()));
i think it could be helpfull for you using Map
Map<String, String> mapp = persons.stream().collect(HashMap::new,
(m, c) ->{
m.put(c.getFirstname(), "");
m.put(c.getLastname(), "");
},HashMap::putAll);
System.out.println(mapp.keySet().toString());

Resources