Zwracanie obiektu (copy?)

0

Hej, dzisiaj podczas implementowania HATEOS'a trochę mnie olśniło.
Kiedyś w robocie gdy używałem jeszcze SONAR'a pamiętam że pluło warningami w stylu "You should/must return a copy of given {...} Object" nie za bardzo rozumiałem dlaczego. Poszedłem troche na skróty, postanowiłem trzymać dane w pamięci:

    private final Set<Moderator> FAKE_DATA = Set.of(
            new Moderator(1L, "Bolec", "Adam", "Kowalski", "[email protected]", LocalDate.of(1992, 3, 3)),
            new Moderator(2L, "Koles", "Adrian", "Kownacki", "[email protected]", LocalDate.of(1994, 10, 17)),
            new Moderator(3L, "Dolec", "Antek", "Koterski", "[email protected]", LocalDate.of(1991, 11, 21))
    );

W kontrolerze do ResponseEntity jak to bywa w HATEOAS dopisywałem linki. Zauważyłem że każdorazowo gdy wołałem findAll() inkrementopałem link dostępu

  response.forEach(x -> x.add(linkTo(AdminController.class).slash(x.getId()).withSelfRel()));

I następstwo :

"_embedded": {
        "moderatorList": [
            {
                "id": 3,
                "nickname": "Dolec",
                "firstName": "Antek",
                "lastName": "Koterski",
                "email": "[email protected]",
                "registrationDate": "1991-11-21",
                "_links": {
                    "self": [
                        {
                            "href": "http://localhost:8080/admin/3"
                        },
                        {
                            "href": "http://localhost:8080/admin/3"
                        }
                    ]
                }
            },

I tutaj mi zabłysło i wrzuciłem deepCopy(...) co rozwiązało problem.

  public Set<Moderator> findAll() {
        return FAKE_DATA.stream()
                .map(this::deepCopy)
                .map(x -> (Moderator) x)
                .collect(Collectors.toSet());
    }

Całość kodu tutaj:
https://github.com/Korges/spring-hateoas

No i czas na pytanko, jak to jest z tym zwracaniem kopii obiektów? Domyślam się że chodzi o to aby w publicznych akcesorach nie udostępniać mutowalnych danych. W jakich przypadkach należy je stosować i jaki sposób polecacie? Czy taka implementacja jaka jest u mnie wystarczy ? (deepCopy() w klasie ModeratorRepositoryDao)

2

Ja mam bardzo dobre rozwiązanie na takie problemy - efektywnie miemutowalne obiekty. Jak kolekcje to z Vavra.

1

Popieram powyższe - nie używanie kolekcji z java.util to jedyne zdrowe rozwiązanie. Vavr jest ok.

1

Ja rozumiem podniecanie sie vavrem, ale przecież nie o to pyta autor ;) Zresztą nikt nie broni użyć UnmodifiableList jakiegoś ;)
@Korges twój problem polega na tym, że twoje obiekty domenowe (jak ten Moderator) popsułeś i dodałeś do nich jakieś dziwne pola, które wypłeniasz dopiero jak chcesz zwrócic dane z kontrolera. Ludzkie rozwiązanie to mieć osobny model i przemapować obiekty domenowe na jakieś DTOsy które wychodzą z kontrolera.
A tak btw, to za wyciąganie jakiegoś list z niemutowalnego obiektu i mieszanie w tej liscie to powinni ucinać ręce :D użyj tam Collections.unmodifiableList() skoro tak cie kusi robić złe rzeczy.

0
Shalom napisał(a):

Ja rozumiem podniecanie sie vavrem, ale przecież nie o to pyta autor ;) Zresztą nikt nie broni użyć UnmodifiableList jakiegoś ;)
@Korges twój problem polega na tym, że twoje obiekty domenowe (jak ten Moderator) popsułeś i dodałeś do nich jakieś dziwne pola, które wypłeniasz dopiero jak chcesz zwrócic dane z kontrolera. Ludzkie rozwiązanie to mieć osobny model i przemapować obiekty domenowe na jakieś DTOsy które wychodzą z kontrolera.
A tak btw, to za wyciąganie jakiegoś list z niemutowalnego obiektu i mieszanie w tej liscie to powinni ucinać ręce :D użyj tam Collections.unmodifiableList() skoro tak cie kusi robić złe rzeczy.

Zmodyfikowałem kod, dodałem oddzielną warstwę DTO mapowaną przez MapStruct. Teraz bedzie gites? Rozbuduje troche api i żeby było można bardziej poszaleć z HATEOAS'em.
Mam jeszcze jedno pytanko. Dajmy na to że mamy różne typy kont, zrobiliśmy jakiś request, z API z konkretnej metody dostajemy możliwe dostępne linki (operacje/zasoby) do których możemy się dostać. Jak połaczyć to z Spring Security, aby dodawać zasoby w zależności od roli/uprawnień? Wiadomo że moge zablokować dostęp do zasobu adnotacją @Pre... nad konkrentymi metodami, kwestia jak to zintegrować z systemem HATEOAS?

0

Mam jeszcze jedno pytanko. Dajmy na to że mamy różne typy kont, zrobiliśmy jakiś request, z API z konkretnej metody dostajemy możliwe dostępne linki (operacje/zasoby) do których możemy się dostać. Jak połaczyć to z Spring Security, aby dodawać zasoby w zależności od roli/uprawnień? Wiadomo że moge zablokować dostęp do zasobu adnotacją @Pre... nad konkrentymi metodami, kwestia jak to zintegrować z systemem HATEOAS?

Znalazłem rozwiązanie:

4. Programmatic Checking of the Role

A user authority can also be checked programmatically, in raw Java code, if the request object is available:

@RequestMapping
public void someControllerMethod(HttpServletRequest request) {
    request.isUserInRole("someAuthority");
}
And of course, without access to the request, the check can also be done manually by simply verifying if the currently authenticated user has that particular authority. The user can be obtained from the Spring Security context in a variety of ways.

1 użytkowników online, w tym zalogowanych: 0, gości: 1