<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>jTechnics &#187; liquidform</title>
	<atom:link href="http://jtechnics.anzix.net/tag/liquidform/feed/" rel="self" type="application/rss+xml" />
	<link>http://jtechnics.anzix.net</link>
	<description>Java napló</description>
	<lastBuildDate>Fri, 17 Sep 2010 18:06:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Metamodellek</title>
		<link>http://jtechnics.anzix.net/2010/01/31/metamodelek/</link>
		<comments>http://jtechnics.anzix.net/2010/01/31/metamodelek/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 11:15:32 +0000</pubDate>
		<dc:creator>elek</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jpa2]]></category>
		<category><![CDATA[liquidform]]></category>
		<category><![CDATA[metamodel]]></category>
		<category><![CDATA[mockito]]></category>

		<guid isPermaLink="false">http://jtechnics.anzix.net/?p=370</guid>
		<description><![CDATA[Néha hasznos lenne, hogy ha egy objektum struktúra felépítésére tudnék típusosan hivatkozni. Nem találtam jobb nevet erre, mint a JPA 2.0 zsargonjából kölcsönzött Metamodel kifejezést, de talán egy példán keresztül világosabb lesz, mire gondolok. Tegyük fel hogy szeretnék egy Java Bean to Java Bean mapper-t, hasonlót a dozer-hez, csak egyrészt programmatikusan szeretném konfigurálni (nem XML-ből), [...]]]></description>
			<content:encoded><![CDATA[<p>Néha hasznos lenne, hogy ha egy objektum struktúra felépítésére tudnék típusosan hivatkozni.</p>
<p>Nem találtam jobb nevet erre, mint a JPA 2.0 zsargonjából kölcsönzött Metamodel kifejezést, de talán egy példán keresztül világosabb lesz, mire gondolok. Tegyük fel hogy szeretnék egy Java Bean to Java Bean mapper-t, hasonlót a <a href="http://dozer.sourceforge.net/">dozer</a>-hez, csak egyrészt programmatikusan szeretném konfigurálni (nem XML-ből), másrészt én akarom részletesen megmondani, hogy mit másoljon, és csak azt másolja, amit szeretnék.</p>
<p>Tegyük fel, hogy van egy managed JPA entitás struktúránk, amiből szeretnék egy detached változatot, de úgy, hogy én mondom meg, hogy az egyes objektum kapcsolatokból melyik legyen kifejtve és melyik ne. Ezt a vázolt mapper alkalmazással fogom elérni, belemondom, hogy melyik atribútuomkat másolja, és egy adott entitásból egy ugyanolyan detached állapotú osztályhierarchiát másol.</p>
<p>Hogy mit másol, azt megadhatom mondjuk Expression Language szerű kifejezéssekkel. Pl.:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">Mapper m <span style="color: #339933;">=</span> MapperFactory.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span>Partner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
m.<span style="color: #006633;">config</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;partner.nev&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
m.<span style="color: #006633;">config</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;partner.cim.varos&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Partner managed <span style="color: #339933;">=</span> ....
<span style="color: #006633;">Partner</span> detached <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Parner<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
m.<span style="color: #006633;">copy</span><span style="color: #009900;">&#40;</span>managed,detached<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>És itt szeretném elérni azt, hogy a 2. és a 3. sorban típusosan adhassam meg a másolási szabályokat.</p>
<p> Jelenleg két ötletem van erre:</p>
<p><strong>APT</strong></p>
<p>Az első az, amit a JPA2.0 is alkalmaz. Generálunk meta osztályokat mondjuk PartnerMeta, CimMeta, stb.néven, és azokba begeneráljuk a típusok leírását. Pl.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">Mapper m <span style="color: #339933;">=</span> MapperFactory.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span>Partner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
m.<span style="color: #006633;">config</span><span style="color: #009900;">&#40;</span>PartnerMeta.<span style="color: #006633;">nev</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
m.<span style="color: #006633;">config</span><span style="color: #009900;">&#40;</span>PartnerMeta.<span style="color: #006633;">cim</span>.<span style="color: #006633;">varos</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>A JPA2 mondjuk Partner_-nek hívná  metamodel osztályt, és nem lenne rekurzív, tehát a Partner_.cim az nem egy Cim_ a JPA2-ben, ezért a fenti definíciót nem is tudnánk használni. Persze nem egy ördöngősség saját metamodelt kitalálni és az APT eszközzel viszonylag elegánsan lehet generálni ezeket az osztályokat (már ha beszélhetünk eleganciáról bármilyen generált kód esetében): Elég egy jól irányzott jar-t elhelyezni a fordítás idejű classpathba és már generálódnak is az osztályaink (lásd még SPI).</p>
<p>A JPA2 API-ját még nem használtam, de azért idemásolom az íze kedvéért egy <a href="http://weblogs.java.net/blog/lancea/archive/2009/12/15/generating-jpa-20-static-metamodel-classes-using-eclipselink-20-and-n">cikkből</a>, hogy hogy megy ez:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">Root team <span style="color: #339933;">=</span> cq2.<span style="color: #006633;">from</span><span style="color: #009900;">&#40;</span>Team.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
cq2.<span style="color: #006633;">select</span><span style="color: #009900;">&#40;</span>team.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>Team_.<span style="color: #006633;">name</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">where</span><span style="color: #009900;">&#40;</span>cb.<span style="color: #006633;">like</span><span style="color: #009900;">&#40;</span>team.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>Team_.<span style="color: #006633;">name</span><span style="color: #009900;">&#41;</span>, <span style="color: #0000ff;">&quot;Longfellow%&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p><strong>cglib</strong></p>
<p>A másik megoldás a futás idejű byte-code generáláshoz vezet. Ezt csinálja pl. a <a href="http://code.google.com/p/liquidform/">liquidform</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">Person p <span style="color: #339933;">=</span> LiquidForm.<span style="color: #006633;">use</span><span style="color: #009900;">&#40;</span>Person.<span style="color: #000000; font-weight: bold;">class</span>, <span style="color: #0000ff;">&quot;p&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003399;">List</span> people <span style="color: #339933;">=</span> em.<span style="color: #006633;">createQuery</span><span style="color: #009900;">&#40;</span>
    select<span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">from</span><span style="color: #009900;">&#40;</span>Person.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">as</span><span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">where</span><span style="color: #009900;">&#40;</span>like<span style="color: #009900;">&#40;</span>p.<span style="color: #006633;">getSurname</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, <span style="color: #0000ff;">&quot;Smith%&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    .<span style="color: #006633;">getResultList</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>és a <a href="http://mockito.org/">Mockito</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">Partner partner <span style="color: #339933;">=</span> mock<span style="color: #009900;">&#40;</span>Partner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
when<span style="color: #009900;">&#40;</span>partner.<span style="color: #006633;">getNev</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">thenReturn</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;valami&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
assertEquals<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;valami&quot;</span>,partner.<span style="color: #006633;">getNev</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Látható, hogy egyes függvények paraméter gyanánt egy függvényhívást kapnak (pl. partner.getNev()) és nem a függvény hívás visszatérési értéke az érdekes, hanem maga a hívás, mintha egy metamodel egy elemét adnánk meg.</p>
<p>De hogy lehetséges ez? Nem tudom megállni, hogy ne <a href="http://monkeyisland.pl/2008/12/09/more-of-devoxx-more-on-interfaces/">idézzem</a> a Mockito szerőjét <a href="http://monkeyisland.pl">Szczepan Faber</a>-t:</p>
<blockquote><p>
&#8230;I was asked if Mockito is able to mock concrete classes? The answer is yes, Mockito doesn’t care if you mock an interface or a class. Mockito can do it thanks to primordial voodoo magic only ancient shamans understand these days (you guessed right – it’s the cglib library).
</p></blockquote>
<p>A <a href="http://cglib.sourceforge.net/">cglib</a> egy futási idejű bytecode generátor, ami az <a href="http://asm.ow2.org/">ASM</a> nevű bytecode manipulátort használja. Gyakorlatilag proxy szerű objektumokat tudunk vele létrehozni, amire mi mondhatjuk meg, hogy az egyes metódusok mit csináljanak. Mindkét megoldás úgy kezdődött, hogy csináltunk egy saját Partner osztályt a Mockito.mock vagy Liquidbase.use factory-val. Na ez az osztály már nem egy rendes Partner, hanem a memóriában összerakott saját bytecode-ból áll.</p>
<p>A mockito ebbe a bytecode-ba azt írja bele, hogy egy ThreadLocal polcra tedd el az adott hívás tényét (pl. partner.getNev meghívodott). Aztán a when metódus már meg se nézi milyen paramétert kapott (partner.getNev() visszatérési értékét), hanem erről a polcról megnézi, hogy épp mi futott le, és ezért már tudja, hogy amikor a mockolt osztályon legközelebb meghívódik a getNev(), akkor mit kell visszaadni. (A when metódus természetesen később hívódik meg, mint a partner.getNev(), mert előszőr a when argumentumait kell kiértékelni).</p>
<p>A liquidform ennél kicsit egyszerűbbet utat választott. A partner.getNev() meghívásakor ő is feljegyzi, hogy milyen hívás történik éppen, és visszaad egy visszatérési típusnak megfelelő objektumot, de előszőr egy globális Map-ben a kettőt összerendelni. A like(p.getNev(), &#8220;Smith%&#8221;) metódust ezért érdeklik a visszatérési értékek, mert ez alapján megkeresi, hogy a Map-ben van-e rá bejegyzés, és ha van, akkor onnan kimatekolja, hogy a p.nev értéket kell berakni majd String szinten a készülő Querybe.</p>
<p>A liquidform megoldásának azonban van egy nagy hátránya: nem tud primitív típusokat kezelni. Mivel a Map-ben létező objektum referenciákra tudja megmondani az elérési utat, ezért egy visszaadott long értékkel nem tud mit kezelni. Persze meg lehetne a liquidformot is okosítani a Mockito módszerével, de akkor egy másik  problémába ütközünk. A like(p.getNev(), &#8220;Smith%&#8221;) híváskor a polcon az szerepel, hogy egy pszeudó hívás érkezett a bytecode lekvárunkba, aki ezt gondosan feljegyezte. Majd ez után kapunk két String paramétert. Hogy melyik String paramétert kell feloldani a polcunkon lévő hívási információból, azt csak akkor tudnánk megmondani, hogy ha egy kitűntetett String értéket lefoglalnánk annak a jelzésére, hogy az a visszatérési érték nem számít, ehelyett használd a polcon lévő hívási információt. Másik lehetőség, hogy ha a paraméterek minden esetben felcserélhetők, akkor azt mondjuk, hogy a metamodeles hívás mindig az első kell, hogy legyen.</p>
<p>Hát itt tartok éppen a gondolataimban.</p>
]]></content:encoded>
			<wfw:commentRss>http://jtechnics.anzix.net/2010/01/31/metamodelek/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

