Spring MVC i immutable obiekt JSON

0

Cześć,
Problem jest następujący: wysyłam immutable obiekt w formie JSON do kontrolera Spring MVC: przeszedł testy jednostkowe serializacji JSON, więc się serialuzje / deserializuje. Do obsługi JSON używam Jacksona, całość na Spring Boot 1.5.6. Spring MVC szuka bezargumentowego konstruktora, którego nie utworzę, zamiast tego mam builder (wersja Lombok) lub konstruktor argumentowy (plain java i @JsonCreator). Otrzymuje następujący komunikat:

    "timestamp": "2017-08-07T21:24:08.349+0000",
    "status": 500,
    "error": "Internal Server Error",
    "exception": "org.springframework.beans.BeanInstantiationException",
    "message": "Failed to instantiate [pl.margor.immutable.NewPerson]: No default constructor found; nested exception is java.lang.NoSuchMethodException: pl.margor.immutable.NewPerson.<init>()",
    "path": "/system/mvc/lombok/persons"
}```

Tak wygląda obiekt:

public final class NewPerson {

public static final String NAME ="name";
public static final String SURNAME = "surname";
public static final String PESEL = "pesel";

@JsonProperty(NAME)
private final String name;
@JsonProperty(SURNAME)
private final String surname;
@JsonProperty(PESEL)
private final String pesel;

@JsonCreator
public NewPerson(@JsonProperty(NAME) String name, @JsonProperty(SURNAME) String surname,
                 @JsonProperty(PESEL) String pesel) {
    this.name = name;
    this.surname = surname;
    this.pesel = pesel;
}

// getters, equals hashcode itp.
}

lub wersja z Lombok (takiej używam docelowo, pierwsza jest tylko po to, aby wykluczyć problem z powodu użycia Lomboka):

@Value
@Builder(toBuilder = true)
@JsonDeserialize(builder = NewPersonLombok.NewPersonLombokBuilder.class)
public final class NewPersonLombok {

public static final String NAME ="name";
public static final String SURNAME = "surname";
public static final String PESEL = "pesel";

@JsonProperty(NAME)
private final String name;
@JsonProperty(SURNAME)
private final String surname;
@JsonProperty(PESEL)
private final String pesel;

@JsonPOJOBuilder(withPrefix = "")
@JsonIgnoreProperties(ignoreUnknown = true)
public static class NewPersonLombokBuilder {
    @JsonProperty(NAME)
    private String name;
    @JsonProperty(SURNAME)
    private String surname;
    @JsonProperty(PESEL)
    private String pesel;
}

}


Tak wygląda kontroler Spring MVC:

@RestController
@RequestMapping("/mvc/persons")
public class SpringMVCNewPerson {

@PostMapping
public void add(NewPerson person) {
    System.out.println(person);
}

}

Takie coś nie współpracuje z immutable parameterem. Znalazłem na JIRA issue i wygląda na to, że pracują nad tym i będzie w Springu 5:
https://jira.spring.io/browse/SPR-15199
.
Postanowiłem spróbować wariantu z JAX-RS (Jersey) na Spring Boot: zadziałało out-of-box (dla Lomboka i bez lomboka). Kontroler wygląda tak:

@Service
@Path("/jersey/newpersonlombok")
@Produces("application/json")
@Consumes("application/json")
public class JerseyNewPersonLombok {

@POST
public void create(NewPersonLombok person)
{
    System.out.println(person);
}

}


Pytania:
1. Co trzeba zrobić, aby prawidłowo serializować / deserializować immuable klasę w Springu MVC? Jak podczas codziennej pracy z czystym springiem radzicie sobie z tego typu problemem? Może brakuje mi jakiejś pierdoły, przecież to jest podstawowa rzecz, więc powinna być od dawna wspierana.
2. Może warto dać se siana do czasu Spring Boot 2.0 (opartego na Spring 5) i po prostu używać Springa wraz JAX-RS? Aż tak bardzo nie zależy mi na Spring MVC, jeśli mam robić na to jakieś haki. Ale nie ukrywam, że preferuje natywną technologię.

Na chwile obecną przychodzi mi tylko stworzenie CustomArgumentResolvera na potrzeby immutable klas: https://sdqali.in/blog/2016/01/29/using-custom-arguments-in-spring-mvc-controllers/. Zastanawiam się czy można prościej i czy jest gotowiec, który po prostu wykorzysta @JsonCreator / Lombok builder. Na pewno nie wchodz w grę implementacja resolvera dla każdego typu oddzielnie.
0

A po co robić immutable DTO?

1

na moje takie cos powinno dzialac i Spring Boot 1.5.6. nie powinien miec z tym problemow:

@Value
@Builder
public final class NewPersonLombok {

    private final String name;

    private final String surname;

    private final String pesel;


nie wiem po co Ci te jacksonowe adnotacje i jeszcze osobny builder jak juz masz lombokowy.

1

Ostatnio robilem immutable dto i wszystko mi smigalo.

1

Zapomniałeś @RequestBody w kontrolerze

 @PostMapping
    public void add(@RequestBody  NewPerson person) {
        System.out.println(person);
    }

0

Fajnie, ze dziala.
A ja sorry za 3 posty pod rzad ;)
Starsze wersje spring boot nie dzialaly dobrze z lombokiem. Bylo trzeba nauczyc springa serializowac jakims konfigiem. Nowe nie maja problemu.

Swoja droga co do JAX-RS, lubilem to API. Ale obecnie olalbym i uzywal czystego springa. Kilka razy mnie ugryzlo, ze cos niepoprawnie mi dzialalo z integracja z innymi springowymi komponentami. No i poprawili swoje api w springu wiec nie ma tragedii.

Zalecam tez nie korzystanie z defaultowych ustawien rest klientow. Bo posysają. Rest template czy Jersey. Warto przyjrzec sie implementacji. Z rest template mozna uzywac np. Apache http client.

W Springu 5 pojawil sie fajny web client, z duzo fajniejszym api niz rest template. Ale do zastosowan reactive.

0

Wedlug mnie dto to dto. Moge chcec to serializowac na jsona, xmla czy robic z tego csv.

Wedlug mnie to kontroller pokazuje, ze w tym miejscu powinien byc to json.

Obecnie w springu produces, consumes json jest chyba jako default.

0

Co do klientów to w pracy miałem okazję poznać fajne narzędzie tzn. Feign Client. Dobrze zintegrowany z Hysterixem, więc od razu mamy fallback. Ale na początek chcę użyć RestTemplate + Hysterix do prostych rzeczy (aby mieć fallback). Buduje coś w rodzaju własnego stacka (zbiór własnych auto-konfiguracji dla Spring Boota) z konfiguracją Springa z pełnym wsparciem dla testów integracyjnych (PostgreSQL, Mongo). Docelowo chcę tego używać z Kotlinem.

Feign jest potężny, ale dość skomplikowany i chyba rozważę coś lżejszego. Z drugiej strony podoba mi się praktycznie lajtowa integracja ze Spring Cloudem i Consulem (service discovery). Proste jak się używa do komunikacji wewnętrznej i ma się działające service-discovery.

0

Feign jest spoko. Rest Template jest niestety wedlug mnie bardzo slaby w springu. Bardzo noewygodny w porownaniu do innych.Nie raz sie gimnastykowalem.

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