2017-10-25

Nástroje pro kontrolu platnosti parametrů v Java

Pro kontrolu platnosti parametrů se využívají validační třídy z někerý Java frameworků, rád bych připomněl (z mého pohledu) ty nejvýznamnější:
  1. Validate z projektu Apache Commons
  2. Preconditions z projektu Google Common
  3. Assert z projektu Spring Framework
  4. Objects z Java 8 (metoda requireNonNull(), doplněno 2019-09-12)
Třídy se liší počtem i názvem veřejných metod, všechny (výše zmíněné) podporují zprávy pro výjimku, ale jen první dvě umožňují vkládání parametrů pomocí šablon pro rychlejší běh aplikace (finální zprávu lze sestavit až před vyhozením výjimky, zpravidla IllegalArgumentException). Pokud však máte v oblibě framework pro logování událostí zvaný LogBack, vznikne v projektu nekonzistence zápisu parametrů v šabloně, protože LogBack označuje pozici parametru v šabloně dvojicí složených závorek "{}" (na rozdíl od validátorů používajích zpravidla výraz "%s"). Této rozdílnosti se nezbavíme ani použitím třídy Logger ze standardní Java knihovny, protože jeho šablona očekává číslovaný seznam parametrů podle vzoru "{0} {1}". Také se mi nelíbí nejednotné vyhazování výjimek, protože první dvě implementace (výše zmíněné) vyhazují při porušení pravidla not-null odlišnou výjimku (typu NullPointerException). Přesto, že uvedené výhrady nejsou zásadní, po zvážení jsem přistoupil ke vlastní implementaci validátoru s plným vědomím rizika, že to nezpůsobí revoluci ve světě IT :-). Jako vzor pro inspiraci jsem použil třídu Assert ze Spring frameworku, líbilo se mi, jak autoři obešli zápor v názvu metody pro testování parametru typu not-empty. Nový validátor využívají (podle očekávání) ostatní moduly frameworku Ujorm, třída zodpovědná za sestavování zpráv se využívá také pro interní proxy loggger.

Popis třídy Assert z frameworku Ujorm

Vlastnosti nové implementace:
  • podporuje parametry v šabloně (na rozdíl od svého vzoru)
  • pozice parametrů se označuje párem složených závorek "{}", formátování hodnot parametrů není podporováno šablonou
  • do zprávy se zapisují i parametry, které nemají vlastní značku v šabloně a jsou pak odděleny čárkou
  • parametry typu Throwable, které nemají vlastní značku v šabloně vypisují stacktrace
  • jsou podporované také argumenty typu Supplier (od verze 1.82+)
  • podmínku platnosti parametru lze popsat Lambda výrazem
  • při porušení platnosti se vyhazuje výhradně výjimka IllegalArgumentException
Uvádím vzorové použití, v komentáři najdete zprávu vyhozené výjimky:

   Integer value = 20;
   Assert.isTrue(value < 10, "Wrong number {}!", value); // "Wrong number 20!"
   Assert.isTrue(value < 10, "Wrong", value);            // "Wrong, 20"
   Assert.isTrue(value < 10,  value);                    // "20"
   Assert.isTrue(value < 10);                            //  null

   value = null;
   Assert.isTrue(value, (x)-> x<10, "Wrong number {}!", value); // "Wrong number null!"

   Supplier<Object> s = () -> value;
   Assert.isTrue(value < 10, "Wrong number {}!", s); // "Wrong number null!"
Všimněte si, že parametry postrádající svoji značku v šabloně se zapsaly na konec zprávy (například framework LogBack je zahazuje). Pokud je skutečný počet parametrů šablony naopak menší, nevyužité značky se zobrazí beze změny. Metody sice neřeší formátování parametrů, ale v případě nouze je možné parametry pro logování obalit vlastní třídou s překrytou metodou toString(), která to formátování řešit může. Pokud má parametr hodnotu null, tak nedochází k volání Lambda výrazu a není třeba to ošetřovat v kódu. Vzorové použití dalších metod uvádím pro zjednodušení bez kometářů, všechna tvrzení jsou pravdivá:

   Assert.isTrue(true);
   Assert.isTrue(30, (x)-> x>20);
   Assert.notNull("ABC");
   Assert.hasLength("ABC");
   Assert.hasLength(new char[]{'A', 'B', 'C'});
   Assert.hasLength(new StringBuilder().append("ABC"));
   Assert.hasLength(Arrays.asList("A", "B", "C"));

   Assert.isFalse(false);
   Assert.isFalse(30, (x)-> x<20);
   Assert.isNull (null);
   Assert.isEmpty("");
   Assert.isEmpty(new char[0]);
   Assert.isEmpty(new StringBuilder());
   Assert.isEmpty((List) null);
 
Performance testy vychází poměrně příznivě, pro zájemce přikládám odkaz na jUnit testy třídy Assert, případně na testy třídy MsgFormatter, která je zodpovědná za sestavování chybových zpráv. Pokud vás tento článek zaujal, knihovnu můžete připojit snadno pomocí Mavenu, velikost JAR je pouze 10 KB, modul přitom nemá žádné další závislosti.

   <dependency>
     <groupId>org.ujorm</groupId>
     <artifactId>ujo-tools</artifactId>
     <version>1.82</version>
   </dependency>

Žádné komentáře: