V práci  pro dotahování dat ze serveru na klienta používáme Web servisy, konkrétně framework CXF, což je implementace Jax-WS. Jelikož potřebujeme aby jednotliví klienti byli schopní fungovat i v offline módu, dotahuje se v jednu chvíli poměrně velké množství dat. Vyvinul jsem tedy rozhraní na serveru, naklepal funkcionalitu na klientovi, a spustil vývojářský test. Pár chyb tam klasicky bylo, ale v zásadě nic co by stálo za řeč. Celé operace trvá přibližně hodinu, a nejdřív to vypadalo nadějně. Aplikace běžela, a nic nenaznačovalo že by se mělo stát něco nepatřičného. Pak jsem si došel pro kafe, a při návratu na mě zírala chybová hláška. Začal jsem pátrat v konzoli kde by mohl být problém, a stack trace co jsem tam objevil mě opravdu nepotěšil. Nebudu ho zde uveřejňovat celý, podstatná část je tato :

com.ctc.wstx.exc.WstxUnexpectedCharException: Illegal character ((CTRL-CHAR, code 5)).

Nejdřív jsem samozřejmě netušil, kde by mohl být zakopaný pes, ale strejda Google opět nezklamal. Chyba byla v tom, že moje Soap zpráva obsahovala znak pro ,,Ctrl+v", který je ve specifikaci XML  1.0 zakázaný znak. I kdyby jste mě rozkrájeli, nemám nejmenší tušení jak se tento znak do mých dat dostal. Zprvu jsem měl podezření že je špatně nastaveno kódování u JDBC driveru, ale při kontrole jsem nic špatného neobjevil.  Přidal jsem si tedy logování abych zjistil kde přesně chyba je, a zjistil  jsem, že znak se nachází u jednoho záznamu v ručně psané poznámce. No, nejspíš bych měl vysvětlit tu ručně psanou poznámku. Při provozu jí samozřejmě uživatel zadává do GUI, ale Peťánek jako tvor v zásadě velmi líný umí samozřejmě použít update nad databází :-). Je tedy možné, že se tam balast dostal při mých čachrech s daty, ale ruku do ohně bych za to samozřejmě nedal.

Uvažoval jsem co s tím tedy udělám. Spoléhat se na to, že při provozu se do aplikace nahrajou data, která podobné znaky nebudou obsahovat je v zásadě možné, a s vysokou pravděpodobností to tak i bude. Chtěl jsem ale mít absolutní jistotu, a tak jsem uvažoval, co s tím.V mé aplikaci nemají podobné znaky žádný význam, a tak jsem se je rozhodl prostě odstranit. Nejjednodušší, a samozřejmě špatné řešení je použít metodu replaceAll() ze Stringu následujícím způsobem :

replaceAll("\\p{Cntrl}"""); 

Samozřejmě otevřeně přiznávám, že přidávat tento kód do všech setterů na stringové proměnné v DTO objektech mě příliš neláká. V zásadě se stydím za to, že mě to vůbec napadlo. Hledal jsem tedy na Google dál. Doufal jsem že by mohl existovat nějaké prostředek frameworku CXF, který podobnou šlamastiku řeší, jelikož dle mého názoru nejsem první, ani poslední, který toto řešil. Po chvíli jsem narazil na jistý příspěvek na blogu, který doporučoval v podobných případech použít tento snippet kódu :

XMLOutputFactory f = new WstxOutputFactory();

f.setProperty(WstxOutputProperties.P_OUTPUT_INVALID_CHAR_HANDLER,new InvalidCharHandler.ReplacingHandler(' ')),

XMLStreamWriter sw = f.createXMLStreamWriter(...);

Účel je v zásadě velmi prostý, a to během serializace do XML vyhodit všechny znaky, které by mohly na klientovi během deserializace působyt problémy. Poté samozřejmě nebylo problémem vytvořit konfiguraci pro Spring, který InvalidCharHandler.ReplacingHandler('') CXFku podstrčí. Konfigurace v zásadě vypadá takto :

 <jaxws:endpoint id="kservice"  
                   
implementor="#kostrounService"
                   
address="/call_kostroun" >
                   
<jaxws:properties>
                           
<entry key="javax.xml.stream.XMLOutputFactory"  valueref="xmlOutputFactory" />
                     
</jaxws:properties>      
   
</jaxws:endpoint>
 
<bean id="invalidCharHandler"   class="com.ctc.wstx.api.InvalidCharHandler$ReplacingHandler">
         
<constructor-arg value=" "/>
   
</bean>

   
<bean id="xmlOutputFactory" class="com.ctc.wstx.stax.WstxOutputFactory"/>

   
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
       
<property name="targetObject">
           
<ref local="xmlOutputFactory" />
       
</property>
       
<property name="targetMethod">
           
<value>setProperty</value>
       
</property>
       
<property name="arguments">
           
<list>
                 
<util:constant static-field="com.ctc.wstx.api.WstxOutputProperties.P_OUTPUT_INVALID_CHAR_HANDLER"/>
                 
<ref bean="invalidCharHandler" />
           
</list>
       
</property>
   
</bean>

Funguje to dobře, chápu že to nezabraňuje aby se mlíko rozlilo, nýbrž jen to, aby po rozlití bylo zase utřeno, ale co člověk nadělá.  Budu samozřejmě vděčný za komentáře, jelikož si myslím že je důležité dostat zpětnou vazbu, kritiku nevyjímaje.