neděle 10. září 2023

Jak ušetřit platbou v bitcoinech

 Bitcoin jsem nechtěl nikdy utrácet. Příjem mám korunách a navíc i u mě funguje Grashamův zákon. Jaký smysl by mělo převádět koruny na bitcoin abych jím následně zaplatil, pročež si restauratér přijaté satoshi ihned nechá směnit zpět na koruny? Nic než další transakční náklady.

Jednou za rok až dva jsem si na chaincampu za pár stovek koupil satoshi do lightning peněženky. Obvykle jsem to pak hned utratil za občerstvení nebo nějaké to tričko. Letos jsem měl ještě nějaké satoshi z nákupu před dvěma lety. Když jsem v peněžence ale viděl, že jsem tenkrát bitcoin kupoval za dvojnásobnou cenu, nechtělo se mě je utrácet vůbec - vždyť bych, vyjádřeno v korunách, platil dvojnásobnou cenu než je na cenovce. Silně jsem tak pocítil negativní stránku volatility bitcoinu. Negativní zkušenost lze ale vždy chápat jako příležitost. Tentokrát jsem si uvědomil, že je to příležitost nakoupit bitcoin za nízkou cenu. Ne proto abych v něm spořil na důchod/nemovitost/..., ale proto abych ho utratil za běžnou spotřebu v době, kdy bude opět za vysoké ceny. Nejen že budu moci nakupovat levněji, zároveň svým malým dílem přispěji ke snižování dlouhodobé volatility bitcoinu.

Představa, že dnes nakoupím bitcoin na svoji roční útratu v restauracích a za dva roky budu platit např.  přes qerko poloviční ceny, je hodně lákavá. Přitom pravděpodobnost takového scénáře mi nepřipadá malá.

Nejsem už tak mladý abych nevěděl, že jakoukoli moji myšlenku už měl někdo přede mnou. Pokud jste na takovou úvahu již narazili, dejte prosím link do komentářů.

pátek 21. července 2023

Použítí oneOf v YAML + openapi generator

 Definice problému

Mám Spring Boot aplikaci REST JSON služby. Služba má definované API pomocí YAML. Z YAML souboru jsou generovány Java třídy pomocí openapi-generator-maven-plugin verze 6.6.0 nebo novější.

Pokud je v YAML

Addressee:
oneOf:
- $ref: '#/components/schemas/AddresseeBranch'
- $ref: '#/components/schemas/AddresseeHome'

Je při generování vytvořeno rozhraní Addressee a třídy AddresseeBranch a AddresseeHome implementující rozhraní Addressee.
Při volání služby a následném pokusu o deserializaci nastane chyba

Cannot construct instance of `...Akddressee` (no Creators, like default constructor, exist).

Ta je způsobena tím, že deserializer neví na kterou instanci mapovat. Použije proto (nevhodně) samotné rozhraní, které však nelze instanciovat.
Tento problém je na githubu ve stavu otevřený.

Řešení

V některých případech (kdy je jedna z implementací pouhým rozšířením druhé) je možné pomocí SimpleAbstractTypeResolver napevno definovat na kterou z uvedených instancí se mají příchozí data deserializovat. Takové řešení je popsáno zde.

Obecné řešení však spočívá v použití diskriminátoru v YAML definici:

Addressee:
oneOf:
- $ref: '#/components/schemas/AddresseeBranch'
- $ref: '#/components/schemas/AddresseeHome'
discriminator:
propertyName: objectType

Následně je třeba v každém z referencovaných objektů definovat property objectType typu String. Ta by měla mít hodnotu odpovídající názvu reference (tj. názvu implementace rozhraní). Klient tak v requestu vlastně sám uvede, který z možných objektů posílá. objectType zároveň musí být povinná. Příklad pro první z uvedených instancí:

AddresseeBranch:
description: Office
type: object
required:
- objectType
properties:
objectType:
type: string
pattern: '^AddresseeBranch$'

Uvádět pattern není povinné. Je však vhodné ho definovat, aby v případě chybné hodnoty zadané klientem nevznikla chyba během zpracování. Takto bude případná chyba odchycena již při validaci requestu.

Pokud chceme aby hodnota property objectType neodpovídala názvu objektu, je třeba definovat mapování mezi hodnotou a názvem objektu. Podrobněji v sekci Mapping Type Names.