Context: I am writing the service and controller for filtering records in my database based by given multiple parameters in my query search.
Example of usage: when given GET with search query with parameters like http://localhost:8080/pets?name=namesample&type=typesample I want to find in database pets with name like 'namesample' and type like 'typesample'
As I use mongodb database and I have read that creating filters and criteria using JPA and classes Specification like https://docs.spring.io/spring-data/jpa/reference/jpa/specifications.html and https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/ may be not possible, as this is NoSQL language.
Inside the interface MongoRepository there is the method for using Example<T> findBy(Prototype prototypem) class, which like something could use.
However, the problem is with the @Nonnull annotation on the class fields ie. type, as this throw NullPointerExcaption during creating object of Example class.
Question: Is there a way to temporarily disable @Nonnull adnotation? Or force the object to be created even with nullpointer exception> I do not want to insert the object into the database - only create a 'mock' of it with some chosen fields.
Error:
2024-01-14T14:13:03.090+01:00 ERROR 3544 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: gender is marked non-null but is null] with root cause
java.lang.NullPointerException: gender is marked non-null but is null
at pl.pollub.alergeek.tai.backend.model.entity.Pet$PetBuilder.gender(Pet.java:14) ~[main/:na]
at pl.pollub.alergeek.tai.backend.controller.PetController.searchByQuery(PetController.java:45) ~[main/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
<...>
Technology Stack:
- Java 17
- Spring Boot 3.2.1
- Mongodb database - queries are made by interface MongoRepository
My repository class:
@Repository
public interface PetRepository extends MongoRepository<Pet, String> {
Optional<Pet> findByUrlId(String urlId);
@Override
<S extends Pet> List<S> findAll(Example<S> example);
}
My Pet class:
@Builder
@Data
@Document(collection = "pet")
public class Pet {
@Id
@Indexed(unique = true)
private String id;
private String urlId;
private String name;
@NonNull
private String gender;
// @NonNull
private String type;
// @NonNull
private String age;
private Integer weight;
private String box;
private String foundLocation;
private String group;
private LocalDate dateFrom;
private LocalDate dateTo;
// @NonNull
private PetStatus status;
private List<PetContactPerson> contactPeople;
public PetDto toDto() {
return PetDto.builder()
.id(id)
.urlId(urlId)
.name(name)
.gender(gender)
.type(type)
.weight(String.valueOf(weight))
.age(age)
.foundLocation(foundLocation)
.group(group)
.box(box)
.dateFrom(dateFrom)
.dateTo(dateTo)
.status(status.getDescription())
.contactPeople(contactPeople == null ? List.of(): contactPeople)
.build();
}
My controller class:
@RestController
@RequiredArgsConstructor
public class PetController {
private final PetService petService;
private final PetFinder petFinder;
@GetMapping(path = "/pets")
public ResponseEntity<List<PetDto>> getAll() {
return ResponseEntity.ok(petFinder.findAll());
}
@GetMapping("/pet")
public ResponseEntity<List<PetDto>> searchByQuery(@RequestParam Map<String, String> allRequestParams) {
ExampleMatcher matcher = ExampleMatcher.matchingAll()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
.withIgnoreCase()
.withIgnoreNullValues();
Example<Pet> examplePet = Example.of(Pet.builder()
.id(allRequestParams.get("id"))
.urlId(allRequestParams.get("url_id"))
.gender(allRequestParams.get("gender"))
.weight(allRequestParams.get("weight") == null ? null : Integer.parseInt(allRequestParams.get("weight")))
.name(allRequestParams.get("name"))
.age(allRequestParams.get("age"))
.type(allRequestParams.get("type"))
.foundLocation(allRequestParams.get("found_location"))
.box(allRequestParams.get("box"))
.group(allRequestParams.get("group"))
.build(),
matcher);
List<PetDto> pets = petFinder.findAllBy(examplePet).stream().map(Pet::toDto).toList();
return ResponseEntity.ok(pets);
}
}
I want to create an object of Example with some fields that are marked as @NonNull