Střípky z prototypování: Wicket, Spring, REST

Měl jsem to štěstí, že jsem se teď mohl několik týdnů věnovat prototypování. Štěstí, protože je to jeden z mých nejoblíbenějších aspektů softwarového inženýrství.

Text vyšel původně na autorově webu.

Všechny prototypy vedly k cílovému, zbrusu novému řešení. V kontextu naší firmy by to normálně dělalo oddělení R&D, ale z kapacitních a projektových důvodů to skončilo v našem delivery týmu. Rád jsem se toho ujal.

Vzhledem k tomu, že by popis řešení a implementace zabraly mnoho článků, rozhodl jsem se vytáhnout jen několik zajímavějších fragmentů z následujících témat (a i ty rozdělím do několika článků):

  • REST contract-first
  • Wicket + Spring
  • Wicket + REST via Spring
  • WebSockets
  • Embedded Neo4j
  • Embedded Infinispan

 

REST contract-first

O tomhle tématu jsem psal v článku REST contract-first: Swagger & Gradle. Zmiňuju ho pro úplnost, ať je to na jednom místě, a také protože vychází ze stejného konceptu prototypu jako všechny následující.

Wicket + Spring

Use case

Na počátku bylo slovo: udělejte novou aplikaci. Technologie nikdo neřešil – po pravdě, existovalo rozlehlé architektonické vakuum. Tak jsem se do toho vložil a na základě tehdejších informací a kontextu jsem vybral dvě technologie: Wicket na webové GUI a Spring na „všechno ostatní“.

„Všechno ostatní“ zde znamená:

  • REST služby a klienti
  • Business logika
  • (Potenciálně) persistence
  • (Finálně) security

Implementace

Wicket má se Springem dobré vztahy už po léta… i když, vo-cuď-pocuď. Zkrátka, bývávalo, že jste si ze Springu vzali jen to, co potřebujete. Kdepak, už je to pěkně nenažraný cvalík, který si pozve spoustu bratříčků. A skloubit ho s něčím specifickým… je docela práce.

Nicméně. Způsob, jak propojit Wicket a Spring je dvojí – jde o to, kdo koho instancuje. První způsob, kdy Wicket instancuje springovský kontext, ze kterého je potom možné injektovat do wicketovských komponent přes anotaci @SpringBean, je dobře popsaný ve wicketovské Reference Guide: Integration Wicket with Spring.

Druhý způsob je flexibilnější, avšak není nikde moc zdokumentovaný, a když už, tak jen pomocí konfigurace web.xml. Funguje to tak, že WicketFilter instancuje SpringWebApplicationFactory, která prohledá springovský kontext a instancuje wicketovskou WebApplication. Výhodou je, že se dá injektovat přímo do Wicket aplikace, což u předešlého způsobu nejde.

Pokud chceme oželet web.xml (ano, prosím!), vypadá konfigurace filtru takto:

@WebFilter(value = "/*",
    initParams = {
        @WebInitParam(name = "applicationFactoryClassName",
                      value = "org.apache.wicket.spring.SpringWebApplicationFactory")
    })
public class WicketAppFilter extends JavaxWebSocketFilter {
}

Prozatím pomiňme, že filter rozšiřuje JavaxWebSocketFilter (viz sekce WebSockets), obyčejný WicketFilter postačí také.

Prototype repozitory

Pokud vám to neštymuje dohromady, klíčové jsou 3 třídy:

Poučení

Tady se žádné velké překvapení nekoná – funguje to stejně dobře, jako když jsem s Wicketem a Springem pracoval před osmi lety poprvé, jen se nám oba frameworky mocně posunuly ve verzích. Snad jen, že na takovém malém prototypu se jednoduše nacvičí přepnutí z jednoho typu instancování na druhý.

Wicket + REST via Spring

Use case

Spring a Wicket nám teď pěkně kohabitují. Ale chceme přidat RESTové služby – v současnosti všudypřítomná a triviální záležitost. Ne tak docela.

Spring nabízí REST buď v rámci Spring MVC, nebo Spring Boot. Přiznám se, tady mne dost zaskočilo, že Spring nenabízí RESTové služby samostatně, podobně jako ty SOAPovské (Spring WS). Nejsem expert na Spring, takže mi nejspíš něco schází, ale zatím to vidím tak, že dostává na frak buď modularita, nebo snadnost použití. Přitom jediné, co vlastně potřebuji, je DispatcherServlet.

K tomu use casu – potřeboval jsem dedikované URL pro REST, které by neobsluhoval Wicket, a zpracovávat/produkovat JSON zprávy.

Implementace

Řešení přišlo ve dvou krocích – zaregistrovat DispatcherServlet a podstrčit JSON mapování (z nějakého důvodu to Spring nedělá out-of-the-box). Dobral jsem se k řešení, které je sice funkční, ale rozhodně ne elegantní a možná i špatný design. (Zde bych byl vděčný za jakékoliv navedení na „správnou cestu“.)

Zaregistrovat DispatcherServlet jen tak přes @WebServlet annotaci mi nešlo – lítaly z toho tuny výjimek, protože ve springovském kontextu chybělo spousty věcí ze Spring webové aplikace. Všechno to, co vám tam přidá anotace @EnableWebMvc. Tudy cesta nevedla.

Vyřešil jsem to dynamickým zaregistrováním servletu přes ServletRegistration, když jsem si přes Wicket vytáhnul ServletContext:

@Component
public class WicketApplication extends WebApplication {

    @Override
    protected void init() {
        super.init();

        WebApplicationContext ctx = WebApplicationContextUtils
            .getRequiredWebApplicationContext(getServletContext());
        getComponentInstantiationListeners().add(new SpringComponentInjector(this, ctx));

        ServletRegistration.Dynamic dispatcherServlet = getServletContext().addServlet(
                "dispatcherServlet",
                new DispatcherServlet(ctx));
        dispatcherServlet.setLoadOnStartup(1);
        dispatcherServlet.addMapping("/rest/*");
    }
}

Druhý problém – přesvědčit Spring, aby chroustal JSON – mám vyřešený jen zpola: sice „zázračně“ zafungovalo angažování komba AnnotationMethodHandlerAdapter a MappingJackson2HttpMessageConverter, bohužel je ale první třída @deprecated, a to já nesnáším (pokud není zbytí).

Spring doporučuje migrovat na RequestMappingHandlerAdapter, jenže k tomu chybí jakákoliv dokumentace a Google mlčí. Moje otázka na StackOverflow je také bez odpovědi.

Řešení, na které nejsem hrdý (účel světí prostředky):

@Configuration
@ComponentScan("cz.swsamuraj.wicketspring")
public class SpringRestConfiguration {

    @Bean
    public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter() {
        AnnotationMethodHandlerAdapter adapter = new AnnotationMethodHandlerAdapter();
        HttpMessageConverter<?>[] converters = { new MappingJackson2HttpMessageConverter()};
        adapter.setMessageConverters(converters);

        return  adapter;
    }
}

Prototype repozitory

Klíčové třídy:

Poučení

Spring je fajn. Ale přijde mi po těch letech, že je míň flexibilní a narostl do stejného molocha jako Java EE. Pokud potřebujete něco specifického, budete se brodit springovskými výjimkami a zoufale prohledávat StackOverflow. Mimochodem, další moje StackOverflow otázka o Springu je také nezodpovězena.

Říkám si, jestli to za to stojí, přehrabovat se tak hluboko ve vnitřnostech Springu, aby člověk implementoval relativně jednoduché věci. Trochu mi to zavání vendor lock-in: dobře si rozmyslet, jestli stavět heterogenní aplikaci, nebo použít homogenní Spring.

Příště

V pokračování střípků se podíváme na WebSockety a jak do „standardní“ webové aplikace přidat „reactive-like“ chování.

Repository všech prototypů

Momentálně mě nejvíc baví práce, kde můžu skloubit role team leadera, architekta a vývojáře. Posledních 10+ let se věnuji vývoji v enterprise Javě. Píšu technologické blogy SoftWare Samuraj, kde se věnuji různým aspektům z oblasti SW engineeringu a Sometimes Clojure, kde se věnuji… Clojure.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 2

Přehled komentářů

dmarko484 Co takhle SpringBoot ?
Vít Kotačka Re: Co takhle SpringBoot ?
Zdroj: https://www.zdrojak.cz/?p=20295