XMLEncoder.java revision 2574
2362N/A * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2362N/A * or visit www.oracle.com if you need additional information or have any 0N/A * The <code>XMLEncoder</code> class is a complementary alternative to 0N/A * the <code>ObjectOutputStream</code> and can used to generate 0N/A * a textual representation of a <em>JavaBean</em> in the same 0N/A * way that the <code>ObjectOutputStream</code> can 0N/A * be used to create binary representation of <code>Serializable</code> 0N/A * objects. For example, the following fragment can be used to create 0N/A * a textual representation the supplied <em>JavaBean</em> 0N/A * and all its properties: 0N/A * XMLEncoder e = new XMLEncoder( 0N/A * new BufferedOutputStream( 0N/A * e.writeObject(new JButton("Hello, world")); 0N/A * Despite the similarity of their APIs, the <code>XMLEncoder</code> 0N/A * class is exclusively designed for the purpose of archiving graphs 0N/A * of <em>JavaBean</em>s as textual representations of their public 0N/A * properties. Like Java source files, documents written this way 0N/A * have a natural immunity to changes in the implementations of the classes 0N/A * involved. The <code>ObjectOutputStream</code> continues to be recommended 0N/A * for interprocess communication and general purpose serialization. 0N/A * The <code>XMLEncoder</code> class provides a default denotation for 0N/A * <em>JavaBean</em>s in which they are represented as XML documents 0N/A * complying with version 1.0 of the XML specification and the 0N/A * UTF-8 character encoding of the Unicode/ISO 10646 character set. 0N/A * The XML documents produced by the <code>XMLEncoder</code> class are: 0N/A * <em>Portable and version resilient</em>: they have no dependencies 0N/A * on the private implementation of any class and so, like Java source 0N/A * files, they may be exchanged between environments which may have 0N/A * different versions of some of the classes and between VMs from 0N/A * different vendors. 0N/A * <em>Structurally compact</em>: The <code>XMLEncoder</code> class 0N/A * uses a <em>redundancy elimination</em> algorithm internally so that the 0N/A * default values of a Bean's properties are not written to the stream. 0N/A * <em>Fault tolerant</em>: Non-structural errors in the file, 0N/A * caused either by damage to the file or by API changes 0N/A * made to classes in an archive remain localized 0N/A * so that a reader can report the error and continue to load the parts 0N/A * of the document which were not affected by the error. 0N/A * Below is an example of an XML archive containing 0N/A * some user interface components from the <em>swing</em> toolkit: 0N/A * <?xml version="1.0" encoding="UTF-8"?> 0N/A * <object class="javax.swing.JFrame"> 0N/A * <void property="name"> 0N/A * <string>frame1</string> 0N/A * <void property="bounds"> 0N/A * <object class="java.awt.Rectangle"> 0N/A * <int>0</int> 0N/A * <int>0</int> 0N/A * <int>200</int> 0N/A * <int>200</int> 0N/A * <void property="contentPane"> 0N/A * <void method="add"> 0N/A * <object class="javax.swing.JButton"> 0N/A * <void property="label"> 0N/A * <string>Hello</string> 0N/A * <void property="visible"> 0N/A * <boolean>true</boolean> 0N/A * The XML syntax uses the following conventions: 0N/A * Each element represents a method call. 0N/A * The "object" tag denotes an <em>expression</em> whose value is 0N/A * to be used as the argument to the enclosing element. 0N/A * The "void" tag denotes a <em>statement</em> which will 0N/A * be executed, but whose result will not be used as an 0N/A * argument to the enclosing method. 0N/A * Elements which contain elements use those elements as arguments, 0N/A * unless they have the tag: "void". 0N/A * The name of the method is denoted by the "method" attribute. 0N/A * XML's standard "id" and "idref" attributes are used to make 0N/A * references to previous expressions - so as to deal with 0N/A * circularities in the object graph. 0N/A * The "class" attribute is used to specify the target of a static 0N/A * method or constructor explicitly; its value being the fully 0N/A * qualified name of the class. 0N/A * Elements with the "void" tag are executed using 0N/A * the outer context as the target if no target is defined 0N/A * by a "class" attribute. 0N/A * Java's String class is treated specially and is 0N/A * written <string>Hello, world</string> where 0N/A * the characters of the string are converted to bytes 0N/A * using the UTF-8 character encoding. 0N/A * Although all object graphs may be written using just these three 0N/A * tags, the following definitions are included so that common 0N/A * data structures can be expressed more concisely: 0N/A * The default method name is "new". 0N/A * A reference to a java class is written in the form 0N/A * <class>javax.swing.JButton</class>. 0N/A * Instances of the wrapper classes for Java's primitive types are written 0N/A * using the name of the primitive type as the tag. For example, an 0N/A * instance of the <code>Integer</code> class could be written: 0N/A * <int>123</int>. Note that the <code>XMLEncoder</code> class 0N/A * uses Java's reflection package in which the conversion between 0N/A * Java's primitive types and their associated "wrapper classes" 0N/A * is handled internally. The API for the <code>XMLEncoder</code> class 0N/A * itself deals only with <code>Object</code>s. 0N/A * In an element representing a nullary method whose name 0N/A * starts with "get", the "method" attribute is replaced 0N/A * with a "property" attribute whose value is given by removing 0N/A * the "get" prefix and decapitalizing the result. 0N/A * In an element representing a monadic method whose name 0N/A * starts with "set", the "method" attribute is replaced 0N/A * with a "property" attribute whose value is given by removing 0N/A * the "set" prefix and decapitalizing the result. 0N/A * In an element representing a method named "get" taking one 0N/A * integer argument, the "method" attribute is replaced 0N/A * with an "index" attribute whose value the value of the 0N/A * In an element representing a method named "set" taking two arguments, 0N/A * the first of which is an integer, the "method" attribute is replaced 0N/A * with an "index" attribute whose value the value of the 0N/A * A reference to an array is written using the "array" 0N/A * tag. The "class" and "length" attributes specify the 0N/A * sub-type of the array and its length respectively. 0N/A * For more information you might also want to check out 0N/A * an article in <em>The Swing Connection.</em> 0N/A * @see java.io.ObjectOutputStream 0N/A * @author Philip Milne 0N/A public boolean marked =
false;
// Marked -> refs > 0 unless ref was a target. 0N/A * Creates a new XML encoder to write out <em>JavaBeans</em> 0N/A * to the stream <code>out</code> using an XML encoding. 0N/A * @param out the stream to which the XML representation of 0N/A * the objects will be written 0N/A * @throws IllegalArgumentException 0N/A * if <code>out</code> is <code>null</code> 0N/A * @see XMLDecoder#XMLDecoder(InputStream) 0N/A * Creates a new XML encoder to write out <em>JavaBeans</em> 0N/A * to the stream <code>out</code> using the given <code>charset</code> 0N/A * starting from the given <code>indentation</code>. 0N/A * @param out the stream to which the XML representation of 0N/A * the objects will be written 0N/A * @param charset the name of the requested charset; 0N/A * may be either a canonical name or an alias 0N/A * @param declaration whether the XML declaration should be generated; 0N/A * set this to <code>false</code> 0N/A * when embedding the contents in another XML document 0N/A * @param indentation the number of space characters to indent the entire XML document by 0N/A * @throws IllegalArgumentException 0N/A * if <code>out</code> or <code>charset</code> is <code>null</code>, 0N/A * or if <code>indentation</code> is less than 0 0N/A * @throws IllegalCharsetNameException 0N/A * if <code>charset</code> name is illegal 0N/A * @throws UnsupportedCharsetException 0N/A * if no support for the named charset is available 0N/A * in this instance of the Java virtual machine 0N/A * @throws UnsupportedOperationException 0N/A * if loaded charset does not support encoding 0N/A * @see Charset#forName(String) 0N/A * Sets the owner of this encoder to <code>owner</code>. 0N/A * @param owner The owner of this encoder. 0N/A * Gets the owner of this encoder. 0N/A * @return The owner of this encoder. 0N/A * Write an XML representation of the specified object to the output. 0N/A * @param o The object to be written to the stream. 0N/A * @see XMLDecoder#readObject 0N/A // Do not mark liternal strings. Other strings, which might, 0N/A // for example, come from resource bundles should still be marked. 0N/A // Bump the reference counts of all arguments 0N/A // Pending: Why does the reference count need to 0N/A // be incremented here? 0N/A * Records the Statement so that the Encoder will 0N/A * produce the actual output when the stream is flushed. 0N/A * This method should only be invoked within the context 0N/A * of initializing a persistence delegate. 0N/A * @param oldStm The statement that will be written 0N/A * @see java.beans.PersistenceDelegate#initialize 0N/A // System.out.println("XMLEncoder::writeStatement: " + oldStm); 0N/A Note we must do the mark first as we may 0N/A require the results of previous values in 0N/A this context for this statement. 0N/A os.writeObject(this); 0N/A * Records the Expression so that the Encoder will 0N/A * produce the actual output when the stream is flushed. 0N/A * This method should only be invoked within the context of 0N/A * initializing a persistence delegate or setting up an encoder to 0N/A * read from a resource bundle. 0N/A * For more information about using resource bundles with the 0N/A * @param oldExp The expression that will be written 0N/A * @see java.beans.PersistenceDelegate#initialize 0N/A * This method writes out the preamble associated with the 0N/A * XML encoding if it has not been written already and 0N/A * then writes out all of the values that been 0N/A * written to the stream since the last time <code>flush</code> 0N/A * was called. After flushing, all internal references to the 0N/A * values that were written to this stream are cleared. 0N/A * This method calls <code>flush</code>, writes the closing 0N/A * postamble and then closes the output stream associated 0N/A return "\"" + s +
"\"";
0N/A * Returns <code>true</code> if the argument, 0N/A * a Unicode code point, is valid in XML documents. 0N/A * Unicode characters fit into the low sixteen bits of a Unicode code point, 0N/A * and pairs of Unicode <em>surrogate characters</em> can be combined 0N/A * to encode Unicode code point in documents containing only Unicode. 0N/A * (The <code>char</code> datatype in the Java Programming Language 0N/A * represents Unicode characters, including unpaired surrogates.) 0N/A * [2] Char ::= #x0009 | #x000A | #x000D 0N/A * | [#x10000-#x10ffff] 0N/A * @param code the 32-bit Unicode code point being tested 0N/A * @return <code>true</code> if the Unicode code point is valid, 0N/A * <code>false</code> otherwise 0N/A "methodName") +
" should not be null");
0N/A // Make sure that character types are quoted correctly. 0N/A case '&':
return "&";
0N/A case '<':
return "<";
0N/A case '>':
return ">";
0N/A case '"':
return """;
0N/A case '\'':
return "'";
0N/A case '\r':
return " ";
0N/A "methodName") +
" should not be null");
0N/A // Special cases for targets. 0N/A // Special cases for methods. 0N/A // Use XML's short form when there is no body.