Vavr + Jackson deserializacja multimap

0

Wie ktoś jak zdeserializować multimape vavrovą?
Mam taki kod:

    private fun typeReference() = object : ParameterizedTypeReference<HashMultimap<String, String>>() {}

    val response = restTemplate.exchange("http://localhost:${port}/user", HttpMethod.POST, HttpEntity(newUser), typeReference())

Dostaje:

Type definition error: [simple type, class io.vavr.collection.HashMultimap]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `io.vavr.collection.HashMultimap` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
1

Nie znam się ale wypowiem się:

To wygląda obiecująco: https://github.com/vavr-io/vavr-jackson/blob/master/README.md

0

@DisQ: oczywiście że mam już to dodane. Ale niestety dla Multimapy nie działa :(

1

Nie mam pojęcia:
Wyizoluj przypadek - zrób test z gołym vavr-jackson (jak tu):

https://github.com/vavr-io/vavr-jackson/blob/master/src/test/java/io/vavr/jackson/datatype/multimap/HashMultimapTest.java

Będzie wiadomo co dalej.

0

Ciekawe:
Jak mam to:

 @Bean
 fun module() : Module {
        return VavrModule()
 }

Oraz

    val response = restTemplate.postForEntity("http://localhost:${port}/user", newUser, String::class.java)

To mam prawidłowo serializowaną mape:

{"username":["This username is already taken!"],"email":["This email is already taken!"]}

Spróbuję jakoś wyizolować przypadek, choć przyznam że nie wiem czy aż tak warto kopać się z koniem biorąc pod uwagę że tej multimapy potrzebuje tylko do testów.
Ale na pewno wyizolije później przypadek od Spring Boota i sprawdze czy tam działa
Ale skoro serializuje to powinno deserializowac :d

edit: sprawdzę czy nie trzeba skonfigurować jeszcze resttemplate :D

0

Jeśli różne moduły to zobacz czy dobrze pakiety widzi.

Rest template raczej nie trzeba dodatkowo konfigurować, jedynie modelMappera mu podać dobrego

0

Ogólnie to takie coś:

 @Bean
    fun vavrModule(): VavrModule {
        return VavrModule()
    }

działa dużo lepiej niż takie coś:

	@Bean
	public ObjectMapper jacksonBuilder() {
		ObjectMapper mapper = new ObjectMapper();
		return mapper.registerModule(new VavrModule());
	}

ten drugi sposób tak jakby nadpisywał jakieś defaultowe konfiguracje spring boota, przez co sypie tym wyjątkiem deserializacji i wymaga dodania @JsonCreator i @JsonProperty w konstruktorze.

0

@kkojot: już mam tak poprawione. Serializacja działa świetnie, gorzej odwrotnie

0

@jarekr000000: ucieszysz się, to wina Szpringa, normalnie to działa:


    val mapper = objectMapper()
    val multiMap = HashMultimap.withSet<String>().of("one", "1", "two", "2")
    val json = mapper.writeValueAsString(multiMap)!!
    println(json)
    val deserializedMap = mapper.readValue<Multimap<String, String>>(json)
    println(deserializedMap)

2

@jarekr000000 @Charles_Ray @danek możecie być ciekawi, nie wiem czemu tego nie ogarnąłem ale błąd jest przez to że używam TestRestTemplate :D
Zwykły RestTemplate "działa" (oczywiście rzuca wyjątkiem zamiast wrócić responseentity z body jak by logika nakazywała) ;)
No cóż ale zawaliłem ja, trzeba było przeczytać dokumentacje :(

If you need customizations (for example to adding additional message converters) use a RestTemplateBuilder @Bean.

Ale to też chyba niezbyt precyzyjnie opisane, logika nakazywałaby raczej że TestRestTemplate powinno mieć te konwertery z aplikacji, a tu tylko powinniśmy dodawac konwertery swoich klas.

Swoją drogą to ciekawe - czemu TestRestTemplate od początku działał poprawnie dla data class Kotlinowych? Może bugiem jest to że nie zarejestrował beanu z konfiguracją Vavra?

1

No nie do końca, bo tak naprawdę, żeby być 100% czystym powinieneś mieć RestTemplate per serwer - API specyfikuje np. format daty, zapisu pieniędzy itd, każdy może sobie zwracać format jaki chce. Do tego inne ustawienia timeoutów mogą być sensowne.

TestRestTemplate jest klientem zasobów wystawianych przez Ciebie i dla mnie to logiczne, że powinno się go konfigurować niezależnie.

A czemu coś działało, a tamto nie, to tylko debugerka Springa chyba prawdę powie - to akurat logiczne być nie musi i pewnie potrafi się zmieniać razem z wersja Springa :p

0

No nie do końca, bo tak naprawdę, żeby być 100% czystym powinieneś mieć RestTemplate per serwer - API specyfikuje np. format daty, zapisu pieniędzy itd, każdy może sobie zwracać format jaki chce. Do tego inne ustawienia timeoutów mogą być sensowne.

Co do zasady masz rację, mi chodziło o moduły Jacksonowe do obsługi (de)serializacji. Zwykły RestTemplaty współdzielą globalnie zarejestrowane moduły, więc widze tu niekonsekwencję troche

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