How to create search api with Example.of(Probe probe, Example matcher) and @NonNull fields

37 Views Asked by At

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

0

There are 0 best solutions below