Spring, Kotlin a JSON decoding errors

Nedávno jsem narazil na zajímavý problém. Měl jsem dvě služby, kdy se přes REST rozhraní zavolá jedna, ta provolá druhou a vrátí výsledek. Původní odpověď vypadala takto:

data class GetAchievementsResponse(
        achievements: List<AchievementInfo>
)

Jakmile jsem ale objekt změnil takto:

data class GetAchievementsResponse(
        val aAchievements: List<AchievementInfo>,
        val rAchievements: List<AchievementInfo>
)

Začal jsem dostávat tyto chyby:

JSON decoding error: Instantiation of [simple type, class cz.vitfo.client.GetAchievementsResponse] value failed for JSON property aAchievements due to missing (therefore NULL) value for creator parameter aAchievements which is a non-nullable type
JSON decoding error: Cannot deserialize instance of `java.util.ArrayList` out of FIELD_NAME token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of FIELD_NAME token

Nakonec jsem přišel na to, že z nějakého důvodu com.fasterxml.jackson v tomto případě nezvládá camel case názvy proměnných. Řešením bylo toto pojmenování:

data class GetAchievementsResponse(
        val a_achievements: List<AchievementInfo>,
        val r_achievements: List<AchievementInfo>
)

Vrácení pouze některých sloupců při vytvoření dotazu pomocí entity manažera

Pokud vytváříte dotaz pomocí entity manažera (viz příspěvek Spring Data a vytvárení dotazů pomocí entiy managera) můžete omezit sloupce, které daným dotazem budete vracet. V tomto případě používám tabulku t_order se sloupci id, identifier a sum, která je v představována entitou Order.

Číst dálVrácení pouze některých sloupců při vytvoření dotazu pomocí entity manažera

Spring Data a získání metod pro základní operace nad tabulkou

Spring Data poskytuje rozhraní CrudRepository<T, ID>, takže pokud chceme získávat data z databázové tabulky, stačí nám vytvořit vlastní rozhraní, který bude rozšiřovat CrudRepository a určit typ entity, kterou tabulka obsahuje. Jednoduchý příklad to objasní. Pokud budeme mít entitu Order

import java.math.BigDecimal
import java.util.*
import javax.persistence.*

@Entity
@Table(name = "t_order")
@SequenceGenerator(name = "t_order_seq_gen", sequenceName = "t_order_seq", allocationSize = 1)
class Order(

        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "t_order_seq_gen")
        var id: Long = 0L,

        var identifier: UUID = UUID.randomUUID(),

        var sum: BigDecimal = BigDecimal.ZERO
)

vytvoří se nám (volba spring.jpa.generate-ddl: true v application.properties) tabulka t_order. Pro operace s daty této tabulky vytvoříme rozhraní OrderRepository, které bude rozšiřovat CrudRepository.

import cz.vitfo.springdata.entity.Order
import org.springframework.data.repository.CrudRepository

interface OrderRepository : CrudRepository<Order, Long>

Toto stačí, abychom měli k dispozici sadu základních metod (count, delete, deleteAll, deleteById, existsById, findAll, findAllById, findById, save, saveAll) a další metody mohli jednoduše vytvářet použitím jmenné konvence – findByUuid, findByUuidAndSum, …

Spring Data a vytváření dotazů pomocí entity manažera

To jak Spring Data zjednodušuje práci s databází jsem ukázal v příspěvku Spring Data a získání metod pro základní operace nad tabulkou. V tomto příspěvku si ale ukážeme jak vytvářet sql příkazy pomocí entity manažera (EntityManager).

Vytvoříme si třídu s názvem OrderRepository a označíme ji jako repository anotací @Repository (org.springframework.stereotype.Repository).

Číst dálSpring Data a vytváření dotazů pomocí entity manažera

Spuštění kódu při startu Springu

Pokud potřebujete spusti určitý kód po naběhnutí Springu, můžete použít CommandLineRunner. Je to rozhraní, které indikuje beanu, která má být spuštěna jakmile je ve Spring aplikaci.

Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple CommandLineRunner beans can be defined within the same application context and can be ordered using the Ordered interface or Order @Order annotation.

Zde je jednoduchý příklad, kdy si vytvoříme konfigurační třídu s názvem SpringDataConfig.

Číst dálSpuštění kódu při startu Springu

Co znamená WIP v názvu větve

Pokud v rámci GitLabu nebo GitHubu nazvete větev s prefixem WIP a mezerou, půjde na tuto větev udělat merge request, ale nebude ji možné mergnout. WIP v tomto případě znamená Work In Progress. Tato vlastnost má výhodu v tom, že můžete ukázat aktuální stav ve své větvi tak, aby ostatní viděli vaše změny (diff), ale nechcete, aby tyto změny byly sloučeny (merge). Pokud byste vytvořili merge request a pouze tam přidali komentář, je možné, že by si ho někdo z kolegů nevšiml, a vaši práci mergnul.

Zdroj: stackoverflow.com/…/github-what-is-a-wip-branch

Instalace Dockeru na Linux Mint

Instalaci Dockeru na Ubuntu jsem se věnoval v jednom z předchozích příspěvků. Zdálo by se, že protože Linux Mint je založen na Ubuntu, bude instalace stejná. Podobná je, ale v jedné části se liší. Při instalaci na Ubuntu se používá příkaz

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

Ten je pro Mint potřeba změnit následovně

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"

Je to proto, že Linux Mint používá vlastní jména verzí, která se liší od Ubuntích.

Pokud už jste sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" zadali (přídá úložště do zdrojů), odstraňte ji ze zdrojů. Pravděpodobně bude v /etc/apt/sources.list.d/additional-repositories.list. Pak již update proběhne v pořádku.

Zdroj: www.unixtutorial.org/install-docker-in-linux-mint-19-1

Řazení dat v PostgreSQL podle části řetězce

V tomto příspěvku ukáži, jak získat unikátní emaily ze sloupce databáze PostgreSQL seřazené podle domény. K tomu použijeme funkci substring(co, odkud, kam).

select email from  table_name order by substring(email, position('@' in email), length(email));

Uvedený select zobrazí záznamy ze sloupce email tabulky table_name a seřadí je dle domény (podle části řetězce, který vrátí substring). Pokud chceme unikátní, select změníme následovně:

select email from (select distinct email from table_name) as sub order by substring(email, position('@' in email), length(email));

Spring Data a Liquibase

Liquibase umožňuje hlídat změny v databázi. Každá změna (blok změn) má svůj vlastní changeset. Liquibase si vytváří dvě vlastní tabulky: databasechnagelog, kde jsou uloženy provedené changesety a databasechangeloglock, která slouží pro zamykání (řeší případ přístupu, kdy více vývojářů dělá změny v databázi současně). Může se stát, že pokud Liquibase neskončí korektně a zůstane zámek. Pak je potřeba locked nastavit na false manuálně.

Číst dálSpring Data a Liquibase