<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Sergey Malenkov&apos;s Blog</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/" />
<modified>2008-07-25T14:29:49Z</modified>
<tagline></tagline>
<id>tag:weblogs.java.net,2008:/blog/malenkov/345</id>
<generator url="http://www.movabletype.org/" version="3.01D">Movable Type</generator>
<copyright>Copyright (c) 2008, malenkov</copyright>
<entry>
<title>How to load classes from JAR or ZIP?</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/archive/2008/07/how_to_load_cla.html" />
<modified>2008-07-25T14:29:49Z</modified>
<issued>2008-07-25T14:08:52Z</issued>
<id>tag:weblogs.java.net,2008:/blog/malenkov/345.10174</id>
<created>2008-07-25T14:08:52Z</created>
<summary type="text/plain">I needed to load the classes from the dt.jar archive on the fly. The path to the archive was generated automatically based on the &quot;java.home&quot; system property. The original idea was to use the URLClassLoader, but it could not find classes. I had to write a custom class loader which read an archive and loaded classes on demand. At that instant I realized why the URLClassLoader did not work: I had incorrectly generated the path to the archive and the URLClassLoader for a wonder provided no warning that the archive was not found.</summary>
<author>
<name>malenkov</name>

<email>Sergey.Malenkov@Sun.COM</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/malenkov/">
<![CDATA[<p>I needed to load the classes from the <code>dt.jar</code> archive on the fly. The path to the archive was generated automatically based on the "java.home" system property. The original idea was to use the <code><a href="https://java.sun.com/javase/6/docs/api/java/net/URLClassLoader.html">URLClassLoader</a></code>, but it could not find classes. I had to write a custom class loader which read an archive and loaded classes on demand. At that instant I realized why the <code>URLClassLoader</code> did not work: I had incorrectly generated the path to the archive and the <code>URLClassLoader</code> for a wonder provided no warning that the archive was not found.</p>
<p>Below is the code of the custom class loader for work with jar- and zip-archives:</p>
<blockquote><pre style="line-height: 120%;font-family:monospace;background-color:#ffffff"><span style="color:#000080;background-color:#ffffff;font-weight:bold;">public</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">final</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">class</span><span style="background-color:#ffffff;"> ZipClassLoader </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">extends</span><span style="background-color:#ffffff;"> ClassLoader {
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">private</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">final</span><span style="background-color:#ffffff;"> ZipFile </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">file;

</span><span style="background-color:#ffffff;">    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">public</span><span style="background-color:#ffffff;"> ZipClassLoader(String filename) </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">throws</span><span style="background-color:#ffffff;"> IOException {
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">file </span><span style="background-color:#ffffff;">= </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> ZipFile(filename);
    }

    </span><span style="color:#808000;background-color:#ffffff;">@Override
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">protected</span><span style="background-color:#ffffff;"> Class&lt;?&gt; findClass(String name) </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">throws</span><span style="background-color:#ffffff;"> ClassNotFoundException {
        ZipEntry entry = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">file.</span><span style="background-color:#ffffff;">getEntry(name.replace(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">'.'</span><span style="background-color:#ffffff;">, </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">'/'</span><span style="background-color:#ffffff;">) + </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">".class"</span><span style="background-color:#ffffff;">);
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">if</span><span style="background-color:#ffffff;"> (entry == </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">) {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">throw</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> ClassNotFoundException(name);
        }
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">try</span><span style="background-color:#ffffff;"> {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">byte</span><span style="background-color:#ffffff;">[] array = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">byte</span><span style="background-color:#ffffff;">[</span><span style="color:#0000ff;background-color:#ffffff;">1024</span><span style="background-color:#ffffff;">];
            InputStream in = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">file.</span><span style="background-color:#ffffff;">getInputStream(entry);
            ByteArrayOutputStream out = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> ByteArrayOutputStream(array.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">length)</span><span style="background-color:#ffffff;">;
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">int</span><span style="background-color:#ffffff;"> length = in.read(array);
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">while</span><span style="background-color:#ffffff;"> (length &gt; </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">) {
                out.write(array, </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, length);
                length = in.read(array);
            }
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> defineClass(name, out.toByteArray(), </span><span style="color:#0000ff;background-color:#ffffff;">0</span><span style="background-color:#ffffff;">, out.size());
        }
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">catch</span><span style="background-color:#ffffff;"> (IOException exception) {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">throw</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> ClassNotFoundException(name, exception);
        }
    }
}
</span></pre></blockquote>
<p>Note that it is not necessary to cache classes here, because the <code>ClassLoader</code> caches loaded classes automatically. Also you can override the following methods to search resources in the archive:</p>
<blockquote><pre style="width: 800px; line-height: 120%;font-family:monospace;background-color:#ffffff">    <span style="color:#808000;background-color:#ffffff;">@Override
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">protected</span><span style="background-color:#ffffff;"> URL findResource(String name) {
        ZipEntry entry = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">file.</span><span style="background-color:#ffffff;">getEntry(name);
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">if</span><span style="background-color:#ffffff;"> (entry == </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">) {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">;
        }
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">try</span><span style="background-color:#ffffff;"> {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> URL(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"jar:file:"</span><span style="background-color:#ffffff;"> + </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">file.</span><span style="background-color:#ffffff;">getName() + </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"!/"</span><span style="background-color:#ffffff;"> + entry.getName());
        }
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">catch</span><span style="background-color:#ffffff;"> (MalformedURLException exception) {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">;
        }
    }

    </span><span style="color:#808000;background-color:#ffffff;">@Override
    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">protected</span><span style="background-color:#ffffff;"> Enumeration&lt;URL&gt; findResources(</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">final</span><span style="background-color:#ffffff;"> String name) {
        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> Enumeration&lt;URL&gt;() {
            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">private</span><span style="background-color:#ffffff;"> URL </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">element </span><span style="background-color:#ffffff;">= findResource(name);

            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">public</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">boolean</span><span style="background-color:#ffffff;"> hasMoreElements() {
                </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">element </span><span style="background-color:#ffffff;">!= </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">;
            }

            </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">public</span><span style="background-color:#ffffff;"> URL nextElement() {
                </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">if</span><span style="background-color:#ffffff;"> (</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">element </span><span style="background-color:#ffffff;">!= </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">) {
                    URL element = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">element;
</span><span style="background-color:#ffffff;">                    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">this</span><span style="background-color:#ffffff;">.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">element </span><span style="background-color:#ffffff;">= </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">;
                    </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> element;
                }
                </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">throw</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> NoSuchElementException();
            }
        };
    }
</span></pre></blockquote>
<p>Perhaps someone may need it because it slightly faster. But I recommend to use the <code>URLClassLoader</code> which is able to work with remote archives and supports security:</p>
<blockquote><pre style="line-height: 120%;font-family:monospace;background-color:#ffffff"><span style="background-color:#ffffff;">URL[] urls = { </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> URL(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"jar:file:"</span><span style="background-color:#ffffff;"> + path + </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"!/"</span><span style="background-color:#ffffff;">) };
</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="background-color:#ffffff;">URLClassLoader.newInstance(urls);
</span></pre></blockquote>
<p>If the classes cannot be loaded, double check the correctness of the path.</p>]]>

</content>
</entry>
<entry>
<title>It is time to choose Color</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/archive/2007/12/it_is_time_to_c_1.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-12-19T18:09:01Z</issued>
<id>tag:weblogs.java.net,2007:/blog/malenkov/345.8855</id>
<created>2007-12-19T18:09:01Z</created>
<summary type="text/plain">I would like to discuss some proposed changes in the JColorChooser component.</summary>
<author>
<name>malenkov</name>

<email>Sergey.Malenkov@Sun.COM</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/malenkov/">
<![CDATA[<p>I would like to discuss some proposed changes in the <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JColorChooser.html">JColorChooser</a> component.</p>

<p>At present, the JColorChooser component contains the following default tabs:
<br>* <strong>Swatches</strong>: the predefined set of colors
<br>* <strong>HSB</strong>: color selection defined by hue, saturation, and brightness using a diagram
<br>* <strong>RGB</strong>: color selection defined by its constituents (Red, Green, and Blue) using a slider</p>

<p>My suggestion is to combine the last two tabs into a one. The proposed color selection approach applies the color diagram from the second tab, but enables using several color models: <a href="http://en.wikipedia.org/wiki/HSV_color_space">HSV</a>, <a href="http://en.wikipedia.org/wiki/HSL_color_space">HSL</a>, <a href="http://en.wikipedia.org/wiki/RGB_color_model">RGB</a>, and <a href="http://en.wikipedia.org/wiki/CMYK_color_model">CMYK</a>.</p>

<p><strong><large>Test diagram is available for the following L&amp;Fs: <a href="https://swinghelper.dev.java.net/bin/blog/sam/color/color1.jnlp">system</a>, <a href="https://swinghelper.dev.java.net/bin/blog/sam/color/metal1.jnlp">metal</a>, and <a href="https://swinghelper.dev.java.net/bin/blog/sam/color/motif1.jnlp">motif</a>.</large></strong></p>]]>
<![CDATA[<p>This tab has been developed for the <a href="http://bugs.sun.com/view_bug.do?bug_id=6552812">6552812</a> CR. However, I think that it is an improper solution to add a new tab which looks exactly the same as a previous one. That is why I decided to combine the HSV and HSL color spaces. Moreover, I added the means to select the RGB color in the same diagram.  What do you think about this integration? Do we need several separate tabs for each color model? Do you like the existing RGB tab?</p>

<p>Additionally, I developed CMYK support. However, this model consists of four constituents: cyan, magenta, yellow, and key (black), which are hardly laid out on a 3D diagram. Should I leave it as is, use CMY instead, or it will be better to remove CMYK at all?</p>

<p>Personally, I prefer not to use a slider, because we cannot identify the exact position the slider points to. Applying the Motif L&amp;F we may notice that the slider center does not coincide with line pointer on the extreme values. Do you really need the slider? My new tab fixes rendering of this slider in Windows Vista that is described in the <a href="http://bugs.sun.com/view_bug.do?bug_id=6579827">6579827</a> CR. However, I would like to remove the slider, because the new component enables mouse selection and possesses an accurate pointer. What kind of pointer would you prefer? Why?</p>

<p><img src="https://swinghelper.dev.java.net/bin/blog/sam/color/color1.png"></p>
<p><img src="https://swinghelper.dev.java.net/bin/blog/sam/color/color2.png"></p>
<p><img src="https://swinghelper.dev.java.net/bin/blog/sam/color/color3.png"></p>

<p>Let's review the design. The above screenshots show different means of color selection on the diagram. While I prefer the large dagger, other reviewers would like to see the current color in the dagger's center. Additionally, I can use a simple circle, as before. What is your choice? Why?</p>

<p>What is your opinion on the joining up the text fields in groups? Would it be better to remove the title border and use a simple label above the first field instead? Should we use the border around the diagram?</p>

<p>New implementation of the diagram rendering uses the <a href="http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.html">BufferedImage</a> class recommended by Java2D team. This technique is considered more stable than implementation of the <a href="http://java.sun.com/javase/6/docs/api/java/awt/image/ImageProducer.html">ImageProducer</a> interface, because it enables us to solve the problem described in the <a href="http://bugs.sun.com/view_bug.do?bug_id=6417055">6417055</a> CR.</p>

<p>Your feedbacks and comments will be greatly appreciated!</p>]]>
</content>
</entry>
<entry>
<title>How to veto a property change?</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/archive/2007/11/how_to_veto_a_p_1.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-11-22T11:01:24Z</issued>
<id>tag:weblogs.java.net,2007:/blog/malenkov/345.8672</id>
<created>2007-11-22T11:01:24Z</created>
<summary type="text/plain">Correct usage of constrained properties seems still remain unclear for many users.</summary>
<author>
<name>malenkov</name>

<email>Sergey.Malenkov@Sun.COM</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/malenkov/">
<![CDATA[<p>Correct usage of constrained properties seems still remain unclear for many users.</p>
<p>As is the convention in the Java, the <a href="http://java.sun.com/javase/6/docs/api/java/lang/IllegalArgumentException.html"><code>IllegalArgumentException</code></a> is thrown if a method receives illegal arguments which cannot be used to execute the method. However, this approach is not applicable for the <code>set</code> methods, since it is impossible to identify whether all values can be used or not. That is why using the <a href="http://java.sun.com/javase/6/docs/api/java/beans/PropertyVetoException.html"><code>PropertyVetoException</code></a> is considered the proper solution to identify constrained properties.</p>
<p>With constrained properties, an outside object (either the source bean itself or a listener) can veto a property change.</p>

<h2>How the bean can veto a property change?</h2>

<p>It is quite simple. The property setter should declare that it throws <code>PropertyVetoException</code>. Let's consider a bean that prohibits setting the negative value of a property:</p>

<pre>public class SimpleBean { 
    private int value; 

    public int getValue() { 
        return this.value; 
    } 

    public void setValue(int value) throws PropertyVetoException { 
        if (value < 0) { 
            throw new PropertyVetoException( 
                "the value change rejected", 
                new PropertyChangeEvent(this, "value", this.value, value)); 
        } 
        this.value = value; 
    } 
}</pre> 

<h2>How a listener can veto a property change?</h2>

<p>The JavaBeans API provides the event mechanism for handling constrained properties. The <a href="http://java.sun.com/javase/6/docs/api/java/beans/VetoableChangeSupport.html"><code>VetoableChangeSupport</code></a> class facilitates creating constrained properties. Also, this class supports adding  <a href="http://java.sun.com/javase/6/docs/api/java/beans/VetoableChangeListener.html"><code>VetoableChangeListener</code></a>s, which can veto a property change. Let's add a listener to manage a property change:</p>

<pre>public class VetoableBean { 
    private final VetoableChangeSupport vcs = new VetoableChangeSupport(this); 

    public void addVetoableChangeListener(VetoableChangeListener listener) { 
        this.vcs.addVetoableChangeListener(listener); 
    } 

    public void removeVetoableChangeListener(VetoableChangeListener listener) { 
        this.vcs.removeVetoableChangeListener(listener); 
    } 

    private int value; 

    public int getValue() { 
        return this.value; 
    } 

    public void setValue(int value) throws PropertyVetoException { 
        this.vcs.fireVetoableChange("value", this.value, value); 
        this.value = value; 
    } 
}</pre> 

<p>In this case, the bean examines all listeners. If one throws <code>PropertyVetoException</code>, the property value will not be set. The following example shows the class that vetoes setting the negative value of a property:</p>

<pre>private static class Listener implements VetoableChangeListener { 
    public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException { 
        if (event.getPropertyName().equals("value")) 
            if ((Integer) event.getNewValue() < 0) 
                throw new PropertyVetoException("I object!", event); 
    } 
}</pre> 

<p>Javadoc specification says: if anyone vetoes the change, then fire a new event reverting everyone to the old value and then rethrow the <code>PropertyVetoException</code>. Some developers consider this event as "undo" event and suppose it useless, because it is hard to distinguish between a normal event and an "undo" event. Actually, this is not so true. Let's modify the <code>Listener</code> class to skip "undo" events:</p>

<pre>private static class Listener implements VetoableChangeListener { 
    public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException { 
        if (!isUndo(event)) 
            if (event.getPropertyName().equals("value")) 
                if ((Integer) event.getNewValue() < 0) 
                    throw new PropertyVetoException("I object!", event); 
    } 

    private static boolean isUndo(PropertyChangeEvent event) { 
        try { 
            return event.getNewValue().equals(getCurrentValue(event)); 
        } catch (Exception exception) { 
            return false; 
        } 
    } 

    private static Object getCurrentValue(PropertyChangeEvent event) throws Exception { 
        Object bean = event.getSource(); 
        String name = event.getPropertyName(); 
        BeanInfo info = Introspector.getBeanInfo(bean.getClass()); 
        for (PropertyDescriptor pd : info.getPropertyDescriptors()) { 
            if (pd.getName().equals(name)) { 
                return pd.getReadMethod().invoke(bean); 
            } 
        } 
        throw new IllegalArgumentException(name); 
    } 
}</pre>

<p>This common solution could be optimized for the specific case.</p>

<h2>JDK 7 changes the behaviour</h2>

<p>Specification mentions that the new event will notify all listeners if the change is rolled back. I disagree with this statement. The "undo" events must be fired only for those listeners, which received and approved the property change event. This functionality is available in JDK7. For example, we have 3 listeners and the second listener vetoes the change. The following event sequence will be generated for this case:</p>
<ul>
<p>Old behavior in JDK 6:</p>
<li>first listener notified about changing A to B</li>
<li>second listener vetoes changing A to B</li>
<li>first listener notified about changing B to A (undo)</li>
<li>second listener notified about changing B to A (undo)</li>
<li>third listener notified about changing B to A (undo)</li>
</ul>

<ul>
<p>New behavior in JDK 7:</p>
<li>first listener notified about changing A to B</li>
<li>second listener vetoes changing A to B</li>
<li>first listener notified about changing B to A (undo)</li>
</ul>

<p>In other words, the second listener will be not notified, because it vetoed the property change, while the third listener will not be notified, because it simply does not know about the change.</p>]]>

</content>
</entry>
<entry>
<title>JavaBeans: feature attributes</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/archive/2007/10/javabeans_featu.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-10-04T15:29:03Z</issued>
<id>tag:weblogs.java.net,2007:/blog/malenkov/345.8350</id>
<created>2007-10-04T15:29:03Z</created>
<summary type="text/plain">Let&apos;s talk about the FeatureDescriptor class, the superclass for all other descriptors. It enables to add extra metadata to describe the beans. The builder tool could use such metadata to provide enhanced functionality.</summary>
<author>
<name>malenkov</name>

<email>Sergey.Malenkov@Sun.COM</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/malenkov/">
<![CDATA[Lets talk about <a href="http://java.sun.com/javase/6/docs/api/java/beans/FeatureDescriptor.html"><code>FeatureDescriptor</code></a>, the superclass for all other descriptors. It enables to add extra metadata to describe the beans. The builder tool could use such metadata to provide enhanced functionality. You can use the <a href="http://java.sun.com/javase/6/docs/api/java/beans/FeatureDescriptor.html#getValue(java.lang.String)"><code>getValue(String)</code></a> method to retrieve metadata. For example:
<pre>BeanInfo info = Introspector.getBeanInfo(JLabel.class);
Object value = info.getBeanDescriptor().getValue("isContainer");
boolean isContainer = (value instanceof Boolean) && (Boolean)value;</pre>
<p>The following attributes are supported in JDK. Other beans creators can use their own attributes and support them in own builder tools. See <a href="http://javadude.com/articles/javabeanattributes.html">JavaBean BeanInfo Attributes</a> and <a href="http://www.jformdesigner.com/doc/help/java_beans.html">JavaBeans in JFormDesigner</a> articles for details and examples on how to use attributes.</p>

<h2><code>isContainer</code></h2>
<p>The attribute must be a <code>Boolean</code> value in <a href="http://java.sun.com/javase/6/docs/api/java/beans/BeanDescriptor.html"><code>BeanDescriptor</code></a>. It specifies whether a component is a container or not (a container can have child components).</p>
<p><code>isContainer</code> was introduced primarily for the Swing library. All Swing components inherit the <a href="http://java.sun.com/javase/6/docs/api/java/awt/Container.html"><code>Container</code></a> class by design, so for the builder tool we assume that all Swing components are containers. Swing library provides <code>BeanInfo</code> classes with the <code>isContainer</code> attribute to fix this problem.</p>

<h2><code>containerDelegate</code></h2>
<p>The attribute must be a <code>String</code> value in <a href="http://java.sun.com/javase/6/docs/api/java/beans/BeanDescriptor.html"><code>BeanDescriptor</code></a>. It specifies the name of a method to retrieve an actual container for any subcomponents of the bean. This method should not have any parameters and should return an instance of the <a href="http://java.sun.com/javase/6/docs/api/java/awt/Container.html"><code>Container</code></a> class. For example: <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JScrollPane.html#getViewport()"><code>JScrollPane.getViewport()</code></a>.</p>

<h2><code>persistenceDelegate</code></h2>
<p>The attribute must be a <a href="http://java.sun.com/javase/6/docs/api/java/beans/PersistenceDelegate.html"><code>PersistenceDelegate</code></a> instance in <a href="http://java.sun.com/javase/6/docs/api/java/beans/BeanDescriptor.html"><code>BeanDescriptor</code></a>. It specifies an instance of a class that can be used to persist the described bean.</p>
<p>By default every bean could be encoded with the <a href="http://java.sun.com/javase/6/docs/api/java/beans/DefaultPersistenceDelegate.html"><code>DefaultPersistenceDelegate</code></a> class, howewer, some classes requires special processing. For example, the <a href="http://java.sun.com/javase/6/docs/api/java/util/HashMap.html"><code>HashMap</code></a> object should be encoded, but its content cannot be accessed through a property getter and setter.</p>

<h2><code>enumerationValues</code></h2>
<p>The attribute must be an array of <code>Object</code> values in <a href="http://java.sun.com/javase/6/docs/api/java/beans/PropertyDescriptor.html"><code>PropertyDescriptor</code></a>. It specifies a list of valid property values. For each property value, the array must contain three items:</p>
<ul>
<li><strong>Name</strong> &mdash; A displayable name for the property value.</li>
<li><strong>Value</strong> &mdash; The actual property value.</li>
<li><strong>Java Initialization String</strong> &mdash; A Java code piece used for code generating.</li>
</ul>
<p>For example, the <code>orientation</code> property of the <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JSlider.html#setOrientation(int)"><code>JSlider</code></a> class contains the following enumeration values:</p>
<pre>new Object[] {
    "horizontal", Integer.valueOf(JSlider.HORIZONTAL), "JSlider.HORIZONTAL",
    "vertical",   Integer.valueOf(JSlider.VERTICAL),   "JSlider.VERTICAL",
}
</pre>

<h2><code>transient</code></h2>
<p>The attribute must be a <code>Boolean</code> value in <a href="http://java.sun.com/javase/6/docs/api/java/beans/PropertyDescriptor.html"><code>PropertyDescriptor</code></a>. It specifies whether the property value should not be persisted and no code should be generated. For example, we should not encode the <code>location</code> property of the <a href="http://java.sun.com/javase/6/docs/api/java/awt/Point.html#setLocation(java.awt.Point)"><code>Point</code></a> class to avoid the <a href="http://java.sun.com/javase/6/docs/api/java/lang/StackOverflowError.html"><code>StackOverflowError</code></a>.</p>]]>

</content>
</entry>
<entry>
<title>How to use the @ConstructorProperties annotation</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/archive/2007/03/how_to_use_the_1.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2007-03-21T02:00:00Z</issued>
<id>tag:weblogs.java.net,2007:/blog/malenkov/345.6865</id>
<created>2007-03-21T02:00:00Z</created>
<summary type="text/plain">The @ConstructorProperties annotation for constructors was introduced in JDK version 6. This annotation shows how the parameters of annotated constructor correspond to object&apos;s properties.</summary>
<author>
<name>malenkov</name>

<email>Sergey.Malenkov@Sun.COM</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/malenkov/">
<![CDATA[The <a href="http://java.sun.com/javase/6/docs/api/java/beans/ConstructorProperties.html">@ConstructorProperties</a> annotation for constructors was introduced in JDK version 6. This annotation shows how the parameters of annotated constructor correspond to object's properties. The following code snippet shows the get methods of the <code>x</code> and <code>y</code> properties:
<pre>
public class Point {
    private final int x;
    private final int y;

    <strong>@ConstructorProperties({"x", "y"})</strong>
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return this.x;
    }

    public int getY() {
        return this.y;
    }
}
</pre>
The first parameter of the constructor corresponds to the <code>x</code> property and the second - to the <code>y</code> property.

The simplicity of the conception enables a developer to adopt  the <a href="http://java.sun.com/javase/6/docs/api/java/beans/ConstructorProperties.html">@ConstructorProperties</a> annotation easily. In particular this technique is applied to the Long-Term Persistence for JavaBeans (<a href="http://java.sun.com/products/jfc/tsc/articles/persistence4/index.html">LTP</a>) and Java Management Extensions (<a href="http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/">JMX</a>). Technically, an annotation is used for copying beans with read-only properties. Let's examine the encoding the beans into XML form.
<pre>
ByteArrayOutputStream stream = new ByteArrayOutputStream();

XMLEncoder encoder = new XMLEncoder(stream);
encoder.writeObject(new Point(10, 20));
encoder.close();

System.out.println(stream);
</pre>
In JDK version 5 and earlier, the object <code>Point(10, 20)</code> would not be encoded, because <a href="http://java.sun.com/javase/6/docs/api/java/beans/DefaultPersistenceDelegate.html">DefaultPersistenceDelegate</a> is applied by default. This delegate creates an object copy by using a constructor without parameters. Then values of properties are set by means of the setter methods.
In the given example the <code>Point</code> class is immutable: its properties are read only, and it does not have a constructor without parameters. So you need to register a separate persistence delegate each time you are coding such a class. For example:
<pre>
ByteArrayOutputStream stream = new ByteArrayOutputStream();

XMLEncoder encoder = new XMLEncoder(stream);
<strong>encoder.setPersistenceDelegate(Point.class, new DefaultPersistenceDelegate("x", "y"));</strong>
encoder.writeObject(new Point(10, 20));
encoder.close();

System.out.println(stream);
</pre>
However this approach does not work for library classes. There is a convention to create a <a href="http://java.sun.com/javase/6/docs/api/java/beans/BeanInfo.html">BeanInfo</a> class in the library and add the <code>persistenceDelegate</code> attribute to <a href="http://java.sun.com/javase/6/docs/api/java/beans/BeanDescriptor.html">BeanDescriptor</a>. The following code snippet illustrates how to apply the block of static initialization of a library class:
<pre>
<strong>import java.beans.DefaultPersistenceDelegate;
import java.beans.Introspector;</strong>

public class Point {
    private final int x;
    private final int y;

    <strong>static {
        DefaultPersistenceDelegate dpd = new DefaultPersistenceDelegate("x", "y");
        Introspector.getBeanInfo().getBeanDescriptor().setValue("persistenceDelegate", dpd);
    }</strong>

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return this.x;
    }

    public int getY() {
        return this.y;
    }
}
</pre>
As you see this approach is inconvenient and resource-intensive, because it requires the <a href="http://java.sun.com/javase/6/docs/api/java/beans/BeanInfo.html">BeanInfo</a> class to be created. In fact this class may never be needed. Use the <a href="http://java.sun.com/javase/6/docs/api/java/beans/ConstructorProperties.html">@ConstructorProperties</a> annotation to resolve this issue. This annotation enables you to resolve an issue of coding the immutable objects by facilitating the custom persistence delegates registration.
<p>Since the annotation describes the relationship between a constructor parameter and a property, but not an operational logic, it could be applied to other tasks, for example, <a href="http://weblogs.java.net/blog/emcmanus/archive/2006/11/a_helper_class.html">in JMX technology</a>.]]>

</content>
</entry>
<entry>
<title>XMLDecoder improvements</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/archive/2006/10/xmldecoder_impr.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2006-10-31T17:58:53Z</issued>
<id>tag:weblogs.java.net,2006:/blog/malenkov/345.5783</id>
<created>2006-10-31T17:58:53Z</created>
<summary type="text/plain">I would like to start a discussion about XMLDecoder improvements. Some requests can be found in RFE 4864117. I don&apos;t want to discuss improvements of persistence delegation (XMLEncoder) here.</summary>
<author>
<name>malenkov</name>

<email>Sergey.Malenkov@Sun.COM</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/malenkov/">
<![CDATA[<p>I would like to start a discussion about <a href="http://java.sun.com/products/jfc/tsc/articles/persistence3/index.html">XMLDecoder</a> improvements. Some requests can be found in <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4864117">RFE 4864117</a>. I don't want to discuss improvements of <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4474171">persistence delegation</a> (<a href="http://java.sun.com/products/jfc/tsc/articles/persistence4/index.html">XMLEncoder</a>) here.

<h2>How to read objects</h2>
<p>Usually the following code is used to read XML file that represents JavaBeans archive:
<pre>
public static Object[] readXML( InputStream stream ) {
    List list = new ArrayList();
    XMLDecoder decoder = new XMLDecoder( stream );
    try {
        while ( true ) {
            list.add( decoder.readObject() );
        }
    } catch ( ArrayIndexOutOfBoundsException exception ) {
    } finally {
        decoder.close();
    }
    return list.toArray();
}
</pre>
<p>This is the right way when you don't know about the amount of objects in JavaBeans archive. Also you can customize it with the class loader, the exception handler and the owner of this decoder. And you should do it every time for each file meant to parse.
<p>I want to suggest the following code:
<pre>
DocumentHandler handler = new DocumentHandler();
Object[] result1 = handler.parse( new InputSource( stream1 ) );
Object[] result2 = handler.parse( new InputSource( stream2 ) );
</pre>
<p>In this case you can parse each file with the same handler, so you don't need customize it before each usage. With InputSource you can use not only byte stream (InputStream), but you can use also character stream (Reader) or file name represented by String.
<p>DocumentHandler extends DefaultHandler. So you can use it within your own SAX parser.

<h2>How to pass an argument</h2>
<p>Each element that appears in the body of the outermost element (&lt;java&gt;) is evaluated in the context of the decoder itself. Typically this outer context is used to retrieve the owner of the decoder, which can be set before reading the archive. The owner is a property of the decoder and can be accessed in the usual way:
<pre>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;java version="1.4.0" class="java.beans.XMLDecoder"&gt;
  &lt;void id="myController" property="owner"/&gt;
  ...objects go here...
&lt;/java&gt;
</pre>
<p>I think this is a bad idea for security reasons. Now it is possible to set any property of XMLDecoder and execute any method. Do not do this below:
<pre>
&lt;java&gt;
  &lt;object method="readObject"/&gt;
&lt;/java&gt;
</pre>
<p>So I think that the context of &lt;java&gt; element should be an owner of DocumentHandler. There is no problem with backward incompatibility, because we can set appropriate owner depending of value of <code>class</code> attribute of &lt;java&gt; element.
<p>XMLDecoder was created to read JavaBeans archive generated by XMLEncoder, but some people prefer to create XML manually. In many cases JavaBeans archive contains only one element, that does not use the context. DocumentHandler does not require to use &lt;java&gt; element. For example, the following code
<pre>
&lt;java&gt;
  &lt;string&gt;text&lt;/string&gt;
&lt;/java&gt;
</pre>
<p>can be replaced with
<pre>
&lt;string&gt;text&lt;/string&gt;
</pre>

<h2>How to use variables</h2>
<p>When a graph contains cycles or multiple references to the same object, an identifier must be given to the object so that it can be referred to later. Identifiers are created using the <code>id</code> attribute, which binds a name to the expression value. The identifier has global scope extending from the last argument of the expression to the end of the file. The following expression creates an identifier <code>button1</code>, bound to an instance of JButton class:
<pre>
&lt;void id="button1" class="javax.swing.JButton"/&gt;
</pre>
<p>Reference is made to named instances by using an <code>idref</code> attribute in the &lt;object&gt; element. The following expression makes reference to a previously defined instance <code>button1</code>:
<pre>
&lt;object idref="button1"/&gt;
</pre>
<p>DocumentHandler allows the programmer to set the value of some variable before parsing and to get the value of some variable after parsing. Also you can parse some XML files by the same instance of DocumentHandler. The same variable can be used in all parsed XML files. For example:
<pre>
DocumentHandler handler = new DocumentHandler();
handler.setVariable("input1", "example");
handler.parse( new InputSource( stream1 ) );
handler.setVariable("input2", handler.getVariable( "output1" ));
handler.parse( new InputSource( stream2 ) );
</pre>
<p>This is a way to pass many arguments to parser.

<h2>How to add own elements</h2>
<p>XMLDecoder parses all elements and attributes in one method. It is very complex and hard to maintain. DocumentHandler uses separate ElementHandlers for each element. Such mechanism allows the programmer to create new elements easily. For example, the test application adds 4 custom elements:
<pre>
DocumentHandler handler = new DocumentHandler();
handler.setElementHandler( "music", handler.getElementHandler( "java" ) );
handler.setElementHandler( "group", GroupElement.class );
handler.setElementHandler( "album", AlbumElement.class );
handler.setElementHandler( "track", TrackElement.class );
</pre>
<ol>
<li>The &lt;music&gt; element is a topmost element. It uses the same ElementHandler like the &lt;java&gt; element.
<li>The &lt;group&gt; element specifies the music band. It uses <code>GroupElement</code> class to parse attributes <code>name</code> and <code>home</code>.
<li>The &lt;album&gt; element specifies the album of the music band. It uses <code>AlbumElement</code> class to parse attributes <code>year</code>, <code>name</code> and <code>time</code>.
<li>The &lt;track&gt; element specifies the track of the album. It uses <code>TrackElement</code> class to parse attributes <code>name</code> and <code>time</code>.
</ol>
<p>Note that it is possible to mix these elements with all basic ones.

<h2>How to include another XML file</h2>
<p>I am working on this feature now. And I should solve the following issues:
<ol>
<li>What should I use: element or processing instruction?
<ol type="a">
<li><code>&lt;include file="name.xml"&gt;</code>
<p>This way is more flexible. We can use attribute <code>file</code>, <code>idref</code> and others to specify how we should create InputSource for included data.
<li><code>&lt;?include name.xml?&gt;</code>
<p>This approach uses only one argument (file name in this case) and you can configure your XML creation tool to support such processing instruction (if it has such a feature).
</ol>
<li>How I can search file?
<p>It is simple when the file name is given by full path. But I should decide how to find the file by its short name using the system id from InputSource. Note that the system id can be <code>null</code>.
</ol>

<h2>About performance</h2>
<p>You can download the following files to test the performance:
<dl>
<dt><a href="http://malenkov.googlepages.com/performance.jar">performance.jar</a> (142&nbsp;887&nbsp;bytes)
<dd>This is a test application. It contains the following files to test performance:
<dl>
<dt>music.xml (162&nbsp;815&nbsp;bytes)
<dd>This file contains original data: the list of musical bands, their albums and songs.
<dt>music.old.xml (590&nbsp;765&nbsp;bytes)
<dd>This file is generated from the original one by the XSL-transformation by using the file music.old.xslt. It contains a set of XML elements for creation corresponding JavaBeans. This file is compatible with the old XMLDecoder.
<dt>music.new.xml (598&nbsp;833&nbsp;bytes)
<dd>This file is generated from the original one by the XSL-transformation by using the file music.new.xslt. It contains a set of commands that are analogue of commands from the file <code>music.old.xml</code>. But this file is optimized to be read by DocumentHandler.
</dl>
<dt><a href="http://malenkov.googlepages.com/decoder.jar">decoder.jar</a> (29&nbsp;648&nbsp;bytes)
<dd>This is the library needed for the application.
<dt><a href="http://malenkov.googlepages.com/decoder.zip">decoder.zip</a> (64&nbsp;244&nbsp;bytes)
<dd>This file contains documentation for API of the library and supported tags, but it is not completed yet.
<dt><a href="http://malenkov.googlepages.com/performance.zip">performance.zip</a> (37&nbsp;394&nbsp;bytes)
<dd>This file contains documentation for API of the application with source code.
</dl>
<p>Theare are 4 test cases:
<ol> 
<li>XMLDecoder parses music.old.xml:
<p><code>$ java -jar performance.jar old music.old.xml</code>
<li>DocumentHandler parses music.old.xml:
<p><code>$ java -jar performance.jar new music.old.xml</code> 
<li>DocumentHandler parses music.new.xml:
<p><code>$ java -jar performance.jar new music.new.xml</code> 
<li>DocumentHandler parses music.xml using own ElementHandlers:
<p><code>$ java -jar performance.jar mod music.xml</code> 
</ol>
<p>The following table contains results of testing (performance is better when time of parsing is less):
<table>
<tr><th>case<th>cold start<th>hot start
<tr><td align=right>1.<td align=right>703 ms<td align=right>406 ms
<tr><td align=right>2.<td align=right>563 ms<td align=right>281 ms
<tr><td align=right>3.<td align=right>484 ms<td align=right>187 ms
<tr><td align=right>4.<td align=right>187 ms<td align=right>31 ms
</table>
<p>The result table shows that DocumentHandler has better performance than XMLDecoder on the same data set. Performance is even better when new features of DocumentHandler are used.

<h2>Conclusions</h2>
<p>We cannot remove XMLDecoder because Java should be backward compatible, but we can rewrite it using DocumentHandler. I recommend to put DocumentHandler into the public domain, because it is much more flexible and usable than old XMLDecoder.
<p>I would appreciate your comments, what else should we add to DocumentHandler? I would like to make it more convenient at all. You can vote for the RFE 4864117 <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4864117">here</a>.]]>

</content>
</entry>
<entry>
<title>How to encode Type-Safe Enums?</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/archive/2006/08/how_to_encode_t.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2006-08-10T06:00:00Z</issued>
<id>tag:weblogs.java.net,2006:/blog/malenkov/345.5317</id>
<created>2006-08-10T06:00:00Z</created>
<summary type="text/plain">This is a sequel of my first article about Enums encoding. As you may know, Type-Safe Enums were proposed by Joshua Bloch in Effective Java, but they are not supported by XMLEncoder. This article describes how to encode them into XML properly.</summary>
<author>
<name>malenkov</name>

<email>Sergey.Malenkov@Sun.COM</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/malenkov/">
<![CDATA[<p>
This is a sequel of my <a href="http://weblogs.java.net/blog/malenkov/archive/2006/08/how_to_encode_e.html">first article</a> about Enums encoding.
<br>As you may know, Type-Safe Enums were proposed by Joshua Bloch in <a href="http://java.sun.com/docs/books/effective/">Effective Java</a>,
<br>but they are not supported by <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/beans/XMLEncoder.html">XMLEncoder</a>.
This article describes how to encode them into XML properly.
</p>
<p>
Let's create a simple Type-Safe Enum with static method to test encoding into XML:
</p>
<pre>
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;

public final class TestEnum {
    public static final TestEnum LEFT = new TestEnum( "move to left" );
    public static final TestEnum RIGHT = new TestEnum( "move to right" );

    private final String info;

    private TestEnum( String name ) {
        this.info = name;
    }

    public String getInfo() {
        return this.info;
    }

    public static void main( String[] args ) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        XMLEncoder encoder = new XMLEncoder( stream );
        encoder.writeObject( TestEnum.LEFT );
        encoder.writeObject( TestEnum.RIGHT );
        encoder.close();

        System.out.println( stream );
    }
}
</pre>
<p>
If the test method is executed it will print the following result:
</p>
<pre>
java.lang.InstantiationException: TestEnum
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(TestEnum);
Continuing ...
java.lang.InstantiationException: TestEnum
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(TestEnum);
Continuing ...
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;java version="1.5.0_07" class="java.beans.XMLDecoder"&gt;
&lt;/java&gt;
</pre>
<p>
As you can see, some exceptions were thrown during encoding and XML does not contain any object.
</p>
<p>
Let's change the test program.
We should create <a href="http://java.sun.com/products/jfc/tsc/articles/persistence4/#custompd">persistence delegate</a> and register it before encoding:
</p>
<pre>
<strong>import java.beans.Encoder;</strong>
<strong>import java.beans.Expression;</strong>
<strong>import java.beans.PersistenceDelegate;</strong>
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;
<strong>import java.lang.reflect.Field;</strong>
<strong>import java.lang.reflect.Modifier;</strong>

public final class TestEnum {
    public static final TestEnum LEFT = new TestEnum( "move to left" );
    public static final TestEnum RIGHT = new TestEnum( "move to right" );

    private final String info;

    private TestEnum( String name ) {
        this.info = name;
    }

    public String getInfo() {
        return this.info;
    }

    public static void main( String[] args ) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        XMLEncoder encoder = new XMLEncoder( stream );
        <strong>encoder.setPersistenceDelegate( TestEnum.class, new TypeSafeEnumPersistenceDelegate() );</strong>
        encoder.writeObject( TestEnum.LEFT );
        encoder.writeObject( TestEnum.RIGHT );
        encoder.close();

        System.out.println( stream );
    }
}

<strong>class TypeSafeEnumPersistenceDelegate extends PersistenceDelegate {
    protected boolean mutatesTo( Object oldInstance, Object newInstance ) {
        return oldInstance == newInstance;
    }

    protected Expression instantiate( Object oldInstance, Encoder out ) {
        Class type = oldInstance.getClass();
        if ( !Modifier.isPublic( type.getModifiers() ) )
            throw new IllegalArgumentException( "Could not instantiate instance of non-public class: " + oldInstance );

        for ( Field field : type.getFields() ) {
            int mod = field.getModifiers();
            if ( Modifier.isPublic( mod ) && Modifier.isStatic( mod ) && Modifier.isFinal( mod ) && ( type == field.getDeclaringClass() ) ) {
                try {
                    if ( oldInstance == field.get( null ) )
                        return new Expression( oldInstance, field, "get", new Object[]{null} );
                } catch ( IllegalAccessException exception ) {
                    throw new IllegalArgumentException( "Could not get value of the field: " + field, exception );
                }
            }
        }
        throw new IllegalArgumentException( "Could not instantiate value: " + oldInstance );
    }
}</strong>
</pre>
<p>
Note that <code>TypeSafeEnumPersistenceDelegate</code> does not depend on concrete class.
<br>So, it is possible to use one instance of such persistence delegate with any class,
<br>that contains public static final fields with the same type,
<br>but it is necessary to register it with this concrete class.
</p>
<p>
As a result, XML contains both encoded objects:
</p>
<pre>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;java version="1.5.0_07" class="java.beans.XMLDecoder"&gt;
 <strong>&lt;object class="TestEnum" field="LEFT"/&gt;
 &lt;object class="TestEnum" field="RIGHT"/&gt;</strong>
&lt;/java&gt;
</pre>
<p>
I have bad news for you: JDK 6 does not support Type-Safe Enum encoding.
<br>It is not so easy to integrate this code into <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/beans/DefaultPersistenceDelegate.html">DefaultPersistenceDelegate</a>,
<br>but I think I can do it for JDK 7 (it can affect other classes with public static final fields).
<br>So, you should create custom persistence delegate and register it for your Type-Safe Enum.
</p>]]>

</content>
</entry>
<entry>
<title>How to encode Enums?</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/malenkov/archive/2006/08/how_to_encode_e.html" />
<modified>2008-06-24T19:17:03Z</modified>
<issued>2006-08-08T02:00:00Z</issued>
<id>tag:weblogs.java.net,2006:/blog/malenkov/345.5308</id>
<created>2006-08-08T02:00:00Z</created>
<summary type="text/plain">As you may know, Enums were introduced in Tiger, but they are not supported by XMLEncoder. This article describes how to encode them into XML properly.</summary>
<author>
<name>malenkov</name>

<email>Sergey.Malenkov@Sun.COM</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/malenkov/">
<![CDATA[<p>
As you may know, Enums were introduced in Tiger, but they are not supported by <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/beans/XMLEncoder.html">XMLEncoder</a>.
<br>This article describes how to encode them into XML properly.
</p>
<p>
Let's create a simple Enum with static method to test encoding into XML:
</p>
<pre>
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;

public enum TestEnum {
    LEFT, RIGHT;

    public static void main( String[] args ) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        XMLEncoder encoder = new XMLEncoder( stream );
        encoder.writeObject( TestEnum.LEFT );
        encoder.writeObject( TestEnum.RIGHT );
        encoder.close();

        System.out.println( stream );
    }
}
</pre>
<p>
If the test method is executed it will print the following result:
</p>
<pre>
java.lang.InstantiationException: TestEnum
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(TestEnum);
Continuing ...
java.lang.InstantiationException: TestEnum
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(TestEnum);
Continuing ...
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;java version="1.5.0_07" class="java.beans.XMLDecoder"&gt;
&lt;/java&gt;
</pre>
<p>
As you can see, some exceptions were thrown during encoding and XML does not contain any object.
</p>
<p>
Let's change the test program.
We should create <a href="http://java.sun.com/products/jfc/tsc/articles/persistence4/#custompd">persistence delegate</a> and register it before encoding:
</p>
<pre>
<strong>import java.beans.Encoder;</strong>
<strong>import java.beans.Expression;</strong>
<strong>import java.beans.PersistenceDelegate;</strong>
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;

public enum TestEnum {
    LEFT, RIGHT;

    public static void main( String[] args ) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        XMLEncoder encoder = new XMLEncoder( stream );
        <strong>encoder.setPersistenceDelegate( TestEnum.class, new EnumPersistenceDelegate() );</strong>
        encoder.writeObject( TestEnum.LEFT );
        encoder.writeObject( TestEnum.RIGHT );
        encoder.close();

        System.out.println( stream );
    }
}

<strong>class EnumPersistenceDelegate extends PersistenceDelegate {
    protected boolean mutatesTo( Object oldInstance, Object newInstance ) {
        return oldInstance == newInstance;
    }

    protected Expression instantiate( Object oldInstance, Encoder out ) {
        Enum e = ( Enum )oldInstance;
        return new Expression( e, e.getClass(), "valueOf", new Object[]{e.name()} );
    }
}</strong>
</pre>
<p>
Note that <code>EnumPersistenceDelegate</code> does not depend on concrete Enum.
<br>So, it is possible to use one instance of such persistence delegate with any Enum,
<br>but it is necessary to register it with concrete class of required Enum.
</p>
<p>
As a result, XML contains both encoded objects:
</p>
<pre>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;java version="1.5.0_07" class="java.beans.XMLDecoder"&gt;
 <strong>&lt;object class="TestEnum" method="valueOf"&gt;
  &lt;string&gt;LEFT&lt;/string&gt;
 &lt;/object&gt;
 &lt;object class="TestEnum" method="valueOf"&gt;
  &lt;string&gt;RIGHT&lt;/string&gt;
 &lt;/object&gt;</strong>
&lt;/java&gt;
</pre>
<p>
I have good news for you: JDK 6 already supports Enum encoding.
<br>So, you should not create persistence delegate and register it for your Enum anymore.
</p>]]>

</content>
</entry>

</feed>