Piszę aplikację we frameworku Quarkus, która przechowuje dane w bazie MongoDB.
Potrzebuję dodać operację PATCH w ten sposób, aby na wejściu przekazać tylko te pola, które mają zostać zmodyfikowane.
Dane przychodzą w formacie JSON w postaci klucz-wartość, więc nie żadne RFC6902.
Prosty przykład encji - ale w rzeczywistości encje mogą mieć 100 i więcej pól różnych typów:
@Data
class Pies {
private String imie;
private Rasa rasa;
private Plec plec;
private Boolean czySzczepiony;
private LocalDateTime dataUrodzenia;
private String dodatkoweInformacje;
}
Możemy chcieć zaktualizować 2 pola, czyli:
{"imie":"Sonia","dodatkoweInformacje":null}
Należy dokonać walidacji danych: czy zgadzają się typy i czy nie przekazano pola o innej nazwie.
Kontroler - oba powinny zadziałać i albo dostaniemy obiekt klasy Pies (gdzie wszystkie inne pola będą null), albo mapę z polami, które przyszły.
Zakładamy, że jak przyjdzie null, to znaczy skasuj dane pole.
@Patch
@Path("/{id}")
public Pies update(@PathParam Long id, Pies patch) {
serwis.zaktualizuj(id, patch); // nie wiemy, które pola są do aktualizacji lub usunięcia
}
@Patch
@Path("/{id}")
public Pies update(@PathParam Long id, Map<String,Object> patch) { //lub Map<String,String>
serwis.zaktualizuj(id, patch);
}
Jeśli zmapujemy to na obiekt klasy Pies, to tylko "imie" będzie not-null. Jeśli zignorujemy wszystkie pola null, to nie skasujemy pola "dodatkoweInformacje".
Mam kilka pomysłów:
- JSON skonwertować do
HashMap<String,Object>
a potem dokonać walidacji, czy pola w mapie istnieją w klasie i czy typy się zgadzają. - JSON skonwertować do
HashMap<String,String>
a potem dokonać walidacji i konwersji naHashMap<String,Object>
- Użyć ObjectMapper, by skonwertował
HashMap<String,Object>
doPies
i jeśli się nie wywali, to uznajemy, że jest OK. - JSON skonwerować do
Pies
i jednocześnie doHashMap<String,?>
by odczytać pola, jakie trzeba zmodyfikować.
Każdy z tych sposobów ma pewne wady. Idealnie byłoby operować na obiekcie danej klasy zgodnie z OOP. Niestety Java nie rozróżnia w polach null od nie ustawiono.
Zacząłem implementować 2, by wymusić odpowiednie typy i spróbować dokonać konwersji danych, a może wystarczyłoby 1. Prosty wydaje się 3, ale co jeśli nie będą się zgadzać typy, np. np. "2" zamiast 2 i wrzucimy to tak do Mongo? Konwersja ObjectMapper się powiedzie, ale do bazy wrzucamy mapę, którą otrzymaliśmy na wejściu.
Do obsługi MongoDB używam Panache, który posiada metodę update().
Czy ktoś mierzył się z podobnym zagadnieniem? Jak to należy poprawnie zrobić?
A może podchodzę do tego od złej strony? Może Quarkus lub jakaś zewnętrzna biblioteka robi już coś takiego?