<?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>niekoniecznie...</title>
	<atom:link href="http://niekoniecznie.pl/feed" rel="self" type="application/rss+xml" />
	<link>http://niekoniecznie.pl</link>
	<description>... o programowaniu</description>
	<lastBuildDate>Wed, 28 Mar 2012 11:55:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Java Reflection + commons-beanutils = ciekawy problem</title>
		<link>http://niekoniecznie.pl/41/java-reflection-commons-beanutils-ciekawy-problem</link>
		<comments>http://niekoniecznie.pl/41/java-reflection-commons-beanutils-ciekawy-problem#comments</comments>
		<pubDate>Wed, 28 Mar 2012 11:10:32 +0000</pubDate>
		<dc:creator>dredzik</dc:creator>
				<category><![CDATA[wytwarzanie oprogramowania]]></category>
		<category><![CDATA[commons-beanutils]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Reflection]]></category>

		<guid isPermaLink="false">http://niekoniecznie.pl/?p=41</guid>
		<description><![CDATA[Ostatnio natrafiłem na dosyć ciekawą anomalię w zachowaniu projektu, nad którym pracuję w Wirtualnej Polsce. Część encji, które wysyłano z jednego systemu do drugiego, przychodziło bez wypełnionego pola id. Znalezienie rozwiązania zajęło mi trochę czasu, a sama przyczyna problemu jest dość zaskakująca, stąd też ten wpis. Ale od początku: W projekcie, wszystkie encje implementują interfejs [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio natrafiłem na dosyć ciekawą anomalię w zachowaniu projektu, nad którym pracuję w <a href="http://wp.pl/" target="_blank">Wirtualnej Polsce</a>. Część encji, które wysyłano z jednego systemu do drugiego, przychodziło bez wypełnionego pola <code>id</code>. Znalezienie rozwiązania zajęło mi trochę czasu, a sama przyczyna problemu jest dość zaskakująca, stąd też ten wpis. Ale od początku:<span id="more-41"></span></p>
<p>W projekcie, wszystkie encje implementują interfejs <code>Identifiable</code>, który określa metodę zwracającą identyfikator. Interfejs był mi potrzebny w jednym miejscu, żeby uprościć logikę. Kod interfejsu wygląda następująco:</p>
<pre class="brush:java">public interface Identifiable {

    Object getId();
}</pre>
<p>Encja, która z niego korzysta, ma identyfikator typu java.lang.Long oraz metody getter i setter, wygenerowane za pomocą lomboka. Kod encji:</p>
<pre class="brush:java">import lombok.Getter
import lombok.Setter

public class Entity implements Identifiable {

    @Getter
    @Setter
    private Long id;
}</pre>
<p>Na pierwszy rzut oka wszystko jest w porządku. Jednak co się stanie, gdy zaczniemy operować na metodach takiej klasy, za pomocą mechanizmu Java Reflection?</p>
<pre class="brush:java">for (Method method : new Entity().getClass().getMethods()) {
    System.out.println(method);
}</pre>
<p>Istotne elementy wyjścia, wygenerowanego przez taki kawałek kodu, to:</p>
<pre class="brush:java">Object getId();
Long getId();
void setId(Long);</pre>
<p>Kolejność, w jakiej zwracane są metody, jest stała w obrębie klasy (chociaż nikt o tym nie zapewnia i Java 7 ma to zmienić). Jednak nie jest stała w przypadku różnych klas. W związku z czym, dla jednej klasy, refleksja zwróci najpierw getter z typem <code>Object</code>, dla innej z <code>Long</code>.</p>
<p>Przyjrzyjmy się teraz bibliotece <a href="http://commons.apache.org/beanutils/" target="_blank">commons-beanutils</a>. Jest to biblioteka, którą wykorzystuję do wpisywania wartości właściwości obiektu, po jego inicjalizacji. Przykładowy kod, obrazujący tę funkcjonalność, wygląda tak:</p>
<pre class="brush:java">Entity e = new Entity();
Long id = 10L;

if (PropertyUtils.isWriteable(e, "id")) {
    PropertyUtils.setProperty(e, "id", id);
}</pre>
<p>Jest to bardzo pomocne, w przypadku generycznego kodu, który ma za zadanie utworzyć obiekt z XML-a, JSON-a czy zserializowanego obiektu PHP. Jednak właściwość <code>id</code> to nie to samo co atrybut <code>id</code>. Właściwość beana, jest przez bibliotekę określana na podstawie getterów zawartych w klasie definiującej bean i odpowiadających im setterów.</p>
<p>Czy już widać w czym tkwi problem? W zależności od kolejności, w której refleksja zwróci metody, PropertyUtils znajdzie właściwość <code>Object id</code>, która jest tylko do odczytu; lub <code>Long id</code>, która jest zapisywalna.</p>
<p>Rozwiązanie problemu jest dość proste. Wystarczyło, do interfejsu <code>Identifiable</code>, dodać setter (a w konsekwencji także i szablon) i jak ręką odjął wszystkie właściwości stały się na powrót zapisywalne:</p>
<pre class="brush:java">public interface Identifiable&lt;T&gt; {

    T getId();

    void setId(T id);
}</pre>
<pre class="brush:java">public class Entity implements Identifiable&lt;Long&gt; {

    @Getter
    @Setter
    private Long id;
}</pre>
<p>Lekcja na przyszłość: minimalizm nie zawsze jest dobry i może prowadzić do dość nieoczekiwanych skutków. Oraz do brainf*cka, przy debugowaniu czegokolwiek z <a href="http://commons.apache.org/" target="_blank">Apache Commons</a> ;-)</p>
]]></content:encoded>
			<wfw:commentRss>http://niekoniecznie.pl/41/java-reflection-commons-beanutils-ciekawy-problem/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

