Source Code Cross Referenced for XMLEncoder.java in  » 6.0-JDK-Core » beans » java » beans » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » beans » java.beans 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025        package java.beans;
026
027        import java.io.*;
028        import java.util.*;
029        import java.lang.reflect.*;
030        import java.nio.charset.Charset;
031        import java.nio.charset.CharsetEncoder;
032        import java.nio.charset.IllegalCharsetNameException;
033        import java.nio.charset.UnsupportedCharsetException;
034
035        /**
036         * The <code>XMLEncoder</code> class is a complementary alternative to
037         * the <code>ObjectOutputStream</code> and can used to generate
038         * a textual representation of a <em>JavaBean</em> in the same
039         * way that the <code>ObjectOutputStream</code> can
040         * be used to create binary representation of <code>Serializable</code>
041         * objects. For example, the following fragment can be used to create
042         * a textual representation the supplied <em>JavaBean</em>
043         * and all its properties:
044         * <pre>
045         *       XMLEncoder e = new XMLEncoder(
046         *                          new BufferedOutputStream(
047         *                              new FileOutputStream("Test.xml")));
048         *       e.writeObject(new JButton("Hello, world"));
049         *       e.close();
050         * </pre>
051         * Despite the similarity of their APIs, the <code>XMLEncoder</code>
052         * class is exclusively designed for the purpose of archiving graphs
053         * of <em>JavaBean</em>s as textual representations of their public
054         * properties. Like Java source files, documents written this way
055         * have a natural immunity to changes in the implementations of the classes
056         * involved. The <code>ObjectOutputStream</code> continues to be recommended
057         * for interprocess communication and general purpose serialization.
058         * <p>
059         * The <code>XMLEncoder</code> class provides a default denotation for
060         * <em>JavaBean</em>s in which they are represented as XML documents
061         * complying with version 1.0 of the XML specification and the
062         * UTF-8 character encoding of the Unicode/ISO 10646 character set.
063         * The XML documents produced by the <code>XMLEncoder</code> class are:
064         * <ul>
065         * <li>
066         * <em>Portable and version resilient</em>: they have no dependencies
067         * on the private implementation of any class and so, like Java source
068         * files, they may be exchanged between environments which may have
069         * different versions of some of the classes and between VMs from
070         * different vendors.
071         * <li>
072         * <em>Structurally compact</em>: The <code>XMLEncoder</code> class
073         * uses a <em>redundancy elimination</em> algorithm internally so that the
074         * default values of a Bean's properties are not written to the stream.
075         * <li>
076         * <em>Fault tolerant</em>: Non-structural errors in the file,
077         * caused either by damage to the file or by API changes
078         * made to classes in an archive remain localized
079         * so that a reader can report the error and continue to load the parts
080         * of the document which were not affected by the error.
081         * </ul>
082         * <p>
083         * Below is an example of an XML archive containing
084         * some user interface components from the <em>swing</em> toolkit:
085         * <pre>
086         * &lt;?xml version="1.0" encoding="UTF-8"?&gt;
087         * &lt;java version="1.0" class="java.beans.XMLDecoder"&gt;
088         * &lt;object class="javax.swing.JFrame"&gt;
089         *   &lt;void property="name"&gt;
090         *     &lt;string&gt;frame1&lt;/string&gt;
091         *   &lt;/void&gt;
092         *   &lt;void property="bounds"&gt;
093         *     &lt;object class="java.awt.Rectangle"&gt;
094         *       &lt;int&gt;0&lt;/int&gt;
095         *       &lt;int&gt;0&lt;/int&gt;
096         *       &lt;int&gt;200&lt;/int&gt;
097         *       &lt;int&gt;200&lt;/int&gt;
098         *     &lt;/object&gt;
099         *   &lt;/void&gt;
100         *   &lt;void property="contentPane"&gt;
101         *     &lt;void method="add"&gt;
102         *       &lt;object class="javax.swing.JButton"&gt;
103         *         &lt;void property="label"&gt;
104         *           &lt;string&gt;Hello&lt;/string&gt;
105         *         &lt;/void&gt;
106         *       &lt;/object&gt;
107         *     &lt;/void&gt;
108         *   &lt;/void&gt;
109         *   &lt;void property="visible"&gt;
110         *     &lt;boolean&gt;true&lt;/boolean&gt;
111         *   &lt;/void&gt;
112         * &lt;/object&gt;
113         * &lt;/java&gt;
114         * </pre>
115         * The XML syntax uses the following conventions:
116         * <ul>
117         * <li>
118         * Each element represents a method call.
119         * <li>
120         * The "object" tag denotes an <em>expression</em> whose value is
121         * to be used as the argument to the enclosing element.
122         * <li>
123         * The "void" tag denotes a <em>statement</em> which will
124         * be executed, but whose result will not be used as an
125         * argument to the enclosing method.
126         * <li>
127         * Elements which contain elements use those elements as arguments,
128         * unless they have the tag: "void".
129         * <li>
130         * The name of the method is denoted by the "method" attribute.
131         * <li>
132         * XML's standard "id" and "idref" attributes are used to make
133         * references to previous expressions - so as to deal with
134         * circularities in the object graph.
135         * <li>
136         * The "class" attribute is used to specify the target of a static
137         * method or constructor explicitly; its value being the fully
138         * qualified name of the class.
139         * <li>
140         * Elements with the "void" tag are executed using
141         * the outer context as the target if no target is defined
142         * by a "class" attribute.
143         * <li>
144         * Java's String class is treated specially and is
145         * written &lt;string&gt;Hello, world&lt;/string&gt; where
146         * the characters of the string are converted to bytes
147         * using the UTF-8 character encoding.
148         * </ul>
149         * <p>
150         * Although all object graphs may be written using just these three
151         * tags, the following definitions are included so that common
152         * data structures can be expressed more concisely:
153         * <p>
154         * <ul>
155         * <li>
156         * The default method name is "new".
157         * <li>
158         * A reference to a java class is written in the form
159         *  &lt;class&gt;javax.swing.JButton&lt;/class&gt;.
160         * <li>
161         * Instances of the wrapper classes for Java's primitive types are written
162         * using the name of the primitive type as the tag. For example, an
163         * instance of the <code>Integer</code> class could be written:
164         * &lt;int&gt;123&lt;/int&gt;. Note that the <code>XMLEncoder</code> class
165         * uses Java's reflection package in which the conversion between
166         * Java's primitive types and their associated "wrapper classes"
167         * is handled internally. The API for the <code>XMLEncoder</code> class
168         * itself deals only with <code>Object</code>s.
169         * <li>
170         * In an element representing a nullary method whose name
171         * starts with "get", the "method" attribute is replaced
172         * with a "property" attribute whose value is given by removing
173         * the "get" prefix and decapitalizing the result.
174         * <li>
175         * In an element representing a monadic method whose name
176         * starts with "set", the "method" attribute is replaced
177         * with a "property" attribute whose value is given by removing
178         * the "set" prefix and decapitalizing the result.
179         * <li>
180         * In an element representing a method named "get" taking one
181         * integer argument, the "method" attribute is replaced
182         * with an "index" attribute whose value the value of the
183         * first argument.
184         * <li>
185         * In an element representing a method named "set" taking two arguments,
186         * the first of which is an integer, the "method" attribute is replaced
187         * with an "index" attribute whose value the value of the
188         * first argument.
189         * <li>
190         * A reference to an array is written using the "array"
191         * tag. The "class" and "length" attributes specify the
192         * sub-type of the array and its length respectively.
193         * </ul>
194         *
195         *<p>
196         * For more information you might also want to check out 
197         * <a
198         href="http://java.sun.com/products/jfc/tsc/articles/persistence4">Using XMLEncoder</a>,
199         * an article in <em>The Swing Connection.</em>
200         * @see XMLDecoder
201         * @see java.io.ObjectOutputStream
202         *
203         * @since 1.4
204         *
205         * @version 1.44 05/09/07
206         * @author Philip Milne
207         */
208        public class XMLEncoder extends Encoder {
209
210            private final CharsetEncoder encoder;
211            private final String charset;
212            private final boolean declaration;
213
214            private OutputStreamWriter out;
215            private Object owner;
216            private int indentation = 0;
217            private boolean internal = false;
218            private Map valueToExpression;
219            private Map targetToStatementList;
220            private boolean preambleWritten = false;
221            private NameGenerator nameGenerator;
222
223            private class ValueData {
224                public int refs = 0;
225                public boolean marked = false; // Marked -> refs > 0 unless ref was a target.
226                public String name = null;
227                public Expression exp = null;
228            }
229
230            /**
231             * Creates a new XML encoder to write out <em>JavaBeans</em>
232             * to the stream <code>out</code> using an XML encoding.
233             *
234             * @param out  the stream to which the XML representation of
235             *             the objects will be written
236             *
237             * @throws  IllegalArgumentException
238             *          if <code>out</code> is <code>null</code>
239             *
240             * @see XMLDecoder#XMLDecoder(InputStream)
241             */
242            public XMLEncoder(OutputStream out) {
243                this (out, "UTF-8", true, 0);
244            }
245
246            /**
247             * Creates a new XML encoder to write out <em>JavaBeans</em>
248             * to the stream <code>out</code> using the given <code>charset</code>
249             * starting from the given <code>indentation</code>.
250             *
251             * @param out          the stream to which the XML representation of
252             *                     the objects will be written
253             * @param charset      the name of the requested charset;
254             *                     may be either a canonical name or an alias
255             * @param declaration  whether the XML declaration should be generated;
256             *                     set this to <code>false</code>
257             *                     when embedding the contents in another XML document
258             * @param indentation  the number of space characters to indent the entire XML document by
259             *
260             * @throws  IllegalArgumentException
261             *          if <code>out</code> or <code>charset</code> is <code>null</code>,
262             *          or if <code>indentation</code> is less than 0
263             *
264             * @throws  IllegalCharsetNameException
265             *          if <code>charset</code> name is illegal
266             *
267             * @throws  UnsupportedCharsetException
268             *          if no support for the named charset is available
269             *          in this instance of the Java virtual machine
270             *
271             * @throws  UnsupportedOperationException
272             *          if loaded charset does not support encoding
273             *
274             * @see Charset#forName(String)
275             *
276             * @since 1.7
277             */
278            public XMLEncoder(OutputStream out, String charset,
279                    boolean declaration, int indentation) {
280                if (out == null) {
281                    throw new IllegalArgumentException(
282                            "the output stream cannot be null");
283                }
284                if (indentation < 0) {
285                    throw new IllegalArgumentException(
286                            "the indentation must be >= 0");
287                }
288                Charset cs = Charset.forName(charset);
289                this .encoder = cs.newEncoder();
290                this .charset = charset;
291                this .declaration = declaration;
292                this .indentation = indentation;
293                this .out = new OutputStreamWriter(out, cs.newEncoder());
294                valueToExpression = new IdentityHashMap();
295                targetToStatementList = new IdentityHashMap();
296                nameGenerator = new NameGenerator();
297            }
298
299            /**
300             * Sets the owner of this encoder to <code>owner</code>.
301             *
302             * @param owner The owner of this encoder.
303             *
304             * @see #getOwner
305             */
306            public void setOwner(Object owner) {
307                this .owner = owner;
308                writeExpression(new Expression(this , "getOwner", new Object[0]));
309            }
310
311            /**
312             * Gets the owner of this encoder.
313             *
314             * @return The owner of this encoder.
315             *
316             * @see #setOwner
317             */
318            public Object getOwner() {
319                return owner;
320            }
321
322            /**
323             * Write an XML representation of the specified object to the output.
324             *
325             * @param o The object to be written to the stream.
326             *
327             * @see XMLDecoder#readObject
328             */
329            public void writeObject(Object o) {
330                if (internal) {
331                    super .writeObject(o);
332                } else {
333                    writeStatement(new Statement(this , "writeObject",
334                            new Object[] { o }));
335                }
336            }
337
338            private Vector statementList(Object target) {
339                Vector list = (Vector) targetToStatementList.get(target);
340                if (list != null) {
341                    return list;
342                }
343                list = new Vector();
344                targetToStatementList.put(target, list);
345                return list;
346            }
347
348            private void mark(Object o, boolean isArgument) {
349                if (o == null || o == this ) {
350                    return;
351                }
352                ValueData d = getValueData(o);
353                Expression exp = d.exp;
354                // Do not mark liternal strings. Other strings, which might,  
355                // for example, come from resource bundles should still be marked. 
356                if (o.getClass() == String.class && exp == null) {
357                    return;
358                }
359
360                // Bump the reference counts of all arguments
361                if (isArgument) {
362                    d.refs++;
363                }
364                if (d.marked) {
365                    return;
366                }
367                d.marked = true;
368                Object target = exp.getTarget();
369                if (!(target instanceof  Class)) {
370                    statementList(target).add(exp);
371                    // Pending: Why does the reference count need to
372                    // be incremented here?
373                    d.refs++;
374                }
375                mark(exp);
376            }
377
378            private void mark(Statement stm) {
379                Object[] args = stm.getArguments();
380                for (int i = 0; i < args.length; i++) {
381                    Object arg = args[i];
382                    mark(arg, true);
383                }
384                mark(stm.getTarget(), false);
385            }
386
387            /**
388             * Records the Statement so that the Encoder will
389             * produce the actual output when the stream is flushed.
390             * <P>
391             * This method should only be invoked within the context
392             * of initializing a persistence delegate.
393             *
394             * @param oldStm The statement that will be written
395             *               to the stream.
396             * @see java.beans.PersistenceDelegate#initialize
397             */
398            public void writeStatement(Statement oldStm) {
399                // System.out.println("XMLEncoder::writeStatement: " + oldStm);
400                boolean internal = this .internal;
401                this .internal = true;
402                try {
403                    super .writeStatement(oldStm);
404                    /*
405                       Note we must do the mark first as we may
406                       require the results of previous values in
407                       this context for this statement.
408                       Test case is:
409                           os.setOwner(this);
410                           os.writeObject(this);
411                     */
412                    mark(oldStm);
413                    statementList(oldStm.getTarget()).add(oldStm);
414                } catch (Exception e) {
415                    getExceptionListener().exceptionThrown(
416                            new Exception("XMLEncoder: discarding statement "
417                                    + oldStm, e));
418                }
419                this .internal = internal;
420            }
421
422            /**
423             * Records the Expression so that the Encoder will
424             * produce the actual output when the stream is flushed.
425             * <P>
426             * This method should only be invoked within the context of
427             * initializing a persistence delegate or setting up an encoder to
428             * read from a resource bundle.
429             * <P>
430             * For more information about using resource bundles with the
431             * XMLEncoder, see 
432             * http://java.sun.com/products/jfc/tsc/articles/persistence4/#i18n
433             *
434             * @param oldExp The expression that will be written
435             *               to the stream.
436             * @see java.beans.PersistenceDelegate#initialize
437             */
438            public void writeExpression(Expression oldExp) {
439                boolean internal = this .internal;
440                this .internal = true;
441                Object oldValue = getValue(oldExp);
442                if (get(oldValue) == null
443                        || (oldValue instanceof  String && !internal)) {
444                    getValueData(oldValue).exp = oldExp;
445                    super .writeExpression(oldExp);
446                }
447                this .internal = internal;
448            }
449
450            /**
451             * This method writes out the preamble associated with the
452             * XML encoding if it has not been written already and
453             * then writes out all of the values that been
454             * written to the stream since the last time <code>flush</code>
455             * was called. After flushing, all internal references to the
456             * values that were written to this stream are cleared.
457             */
458            public void flush() {
459                if (!preambleWritten) { // Don't do this in constructor - it throws ... pending.
460                    if (this .declaration) {
461                        writeln("<?xml version=" + quote("1.0") + " encoding="
462                                + quote(this .charset) + "?>");
463                    }
464                    writeln("<java version="
465                            + quote(System.getProperty("java.version"))
466                            + " class=" + quote(XMLDecoder.class.getName())
467                            + ">");
468                    preambleWritten = true;
469                }
470                indentation++;
471                Vector roots = statementList(this );
472                for (int i = 0; i < roots.size(); i++) {
473                    Statement s = (Statement) roots.get(i);
474                    if ("writeObject".equals(s.getMethodName())) {
475                        outputValue(s.getArguments()[0], this , true);
476                    } else {
477                        outputStatement(s, this , false);
478                    }
479                }
480                indentation--;
481
482                try {
483                    out.flush();
484                } catch (IOException e) {
485                    getExceptionListener().exceptionThrown(e);
486                }
487                clear();
488            }
489
490            void clear() {
491                super .clear();
492                nameGenerator.clear();
493                valueToExpression.clear();
494                targetToStatementList.clear();
495            }
496
497            /**
498             * This method calls <code>flush</code>, writes the closing
499             * postamble and then closes the output stream associated
500             * with this stream.
501             */
502            public void close() {
503                flush();
504                writeln("</java>");
505                try {
506                    out.close();
507                } catch (IOException e) {
508                    getExceptionListener().exceptionThrown(e);
509                }
510            }
511
512            private String quote(String s) {
513                return "\"" + s + "\"";
514            }
515
516            private ValueData getValueData(Object o) {
517                ValueData d = (ValueData) valueToExpression.get(o);
518                if (d == null) {
519                    d = new ValueData();
520                    valueToExpression.put(o, d);
521                }
522                return d;
523            }
524
525            /**
526             * Returns <code>true</code> if the argument,
527             * a Unicode code point, is valid in XML documents.
528             * Unicode characters fit into the low sixteen bits of a Unicode code point,
529             * and pairs of Unicode <em>surrogate characters</em> can be combined
530             * to encode Unicode code point in documents containing only Unicode.
531             * (The <code>char</code> datatype in the Java Programming Language
532             * represents Unicode characters, including unpaired surrogates.)
533             * <par>
534             * [2] Char ::= #x0009 | #x000A | #x000D
535             *            | [#x0020-#xD7FF]
536             *            | [#xE000-#xFFFD]
537             *            | [#x10000-#x10ffff]
538             * </par>
539             *
540             * @param code  the 32-bit Unicode code point being tested
541             * @return  <code>true</code> if the Unicode code point is valid,
542             *          <code>false</code> otherwise
543             */
544            private static boolean isValidCharCode(int code) {
545                return (0x0020 <= code && code <= 0xD7FF) || (0x000A == code)
546                        || (0x0009 == code) || (0x000D == code)
547                        || (0xE000 <= code && code <= 0xFFFD)
548                        || (0x10000 <= code && code <= 0x10ffff);
549            }
550
551            private void writeln(String exp) {
552                try {
553                    StringBuilder sb = new StringBuilder();
554                    for (int i = 0; i < indentation; i++) {
555                        sb.append(' ');
556                    }
557                    sb.append(exp);
558                    sb.append('\n');
559                    this .out.write(sb.toString());
560                } catch (IOException e) {
561                    getExceptionListener().exceptionThrown(e);
562                }
563            }
564
565            private void outputValue(Object value, Object outer,
566                    boolean isArgument) {
567                if (value == null) {
568                    writeln("<null/>");
569                    return;
570                }
571
572                if (value instanceof  Class) {
573                    writeln("<class>" + ((Class) value).getName() + "</class>");
574                    return;
575                }
576
577                ValueData d = getValueData(value);
578                if (d.exp != null) {
579                    Object target = d.exp.getTarget();
580                    String methodName = d.exp.getMethodName();
581
582                    if (target == null || methodName == null) {
583                        throw new NullPointerException(
584                                (target == null ? "target" : "methodName")
585                                        + " should not be null");
586                    }
587
588                    if (target instanceof  Field && methodName.equals("get")) {
589                        Field f = (Field) target;
590                        writeln("<object class="
591                                + quote(f.getDeclaringClass().getName())
592                                + " field=" + quote(f.getName()) + "/>");
593                        return;
594                    }
595
596                    Class primitiveType = ReflectionUtils
597                            .primitiveTypeFor(value.getClass());
598                    if (primitiveType != null && target == value.getClass()
599                            && methodName.equals("new")) {
600                        String primitiveTypeName = primitiveType.getName();
601                        // Make sure that character types are quoted correctly.
602                        if (primitiveType == Character.TYPE) {
603                            char code = ((Character) value).charValue();
604                            if (!isValidCharCode(code)) {
605                                writeln(createString(code));
606                                return;
607                            }
608                            value = quoteCharCode(code);
609                            if (value == null) {
610                                value = Character.valueOf(code);
611                            }
612                        }
613                        writeln("<" + primitiveTypeName + ">" + value + "</"
614                                + primitiveTypeName + ">");
615                        return;
616                    }
617
618                } else if (value instanceof  String) {
619                    writeln(createString((String) value));
620                    return;
621                }
622
623                if (d.name != null) {
624                    writeln("<object idref=" + quote(d.name) + "/>");
625                    return;
626                }
627
628                outputStatement(d.exp, outer, isArgument);
629            }
630
631            private static String quoteCharCode(int code) {
632                switch (code) {
633                case '&':
634                    return "&amp;";
635                case '<':
636                    return "&lt;";
637                case '>':
638                    return "&gt;";
639                case '"':
640                    return "&quot;";
641                case '\'':
642                    return "&apos;";
643                case '\r':
644                    return "&#13;";
645                default:
646                    return null;
647                }
648            }
649
650            private static String createString(int code) {
651                return "<char code=\"#" + Integer.toString(code, 16) + "\"/>";
652            }
653
654            private String createString(String string) {
655                StringBuilder sb = new StringBuilder();
656                sb.append("<string>");
657                int index = 0;
658                while (index < string.length()) {
659                    int point = string.codePointAt(index);
660                    int count = Character.charCount(point);
661
662                    if (isValidCharCode(point)
663                            && this .encoder.canEncode(string.substring(index,
664                                    index + count))) {
665                        String value = quoteCharCode(point);
666                        if (value != null) {
667                            sb.append(value);
668                        } else {
669                            sb.appendCodePoint(point);
670                        }
671                        index += count;
672                    } else {
673                        sb.append(createString(string.charAt(index)));
674                        index++;
675                    }
676                }
677                sb.append("</string>");
678                return sb.toString();
679            }
680
681            private void outputStatement(Statement exp, Object outer,
682                    boolean isArgument) {
683                Object target = exp.getTarget();
684                String methodName = exp.getMethodName();
685
686                if (target == null || methodName == null) {
687                    throw new NullPointerException((target == null ? "target"
688                            : "methodName")
689                            + " should not be null");
690                }
691
692                Object[] args = exp.getArguments();
693                boolean expression = exp.getClass() == Expression.class;
694                Object value = (expression) ? getValue((Expression) exp) : null;
695
696                String tag = (expression && isArgument) ? "object" : "void";
697                String attributes = "";
698                ValueData d = getValueData(value);
699                if (expression) {
700                    if (d.refs > 1) {
701                        String instanceName = nameGenerator.instanceName(value);
702                        d.name = instanceName;
703                        attributes = attributes + " id=" + quote(instanceName);
704                    }
705                }
706
707                // Special cases for targets.
708                if (target == outer) {
709                } else if (target == Array.class
710                        && methodName.equals("newInstance")) {
711                    tag = "array";
712                    attributes = attributes + " class="
713                            + quote(((Class) args[0]).getName());
714                    attributes = attributes + " length="
715                            + quote(args[1].toString());
716                    args = new Object[] {};
717                } else if (target.getClass() == Class.class) {
718                    attributes = attributes + " class="
719                            + quote(((Class) target).getName());
720                } else {
721                    d.refs = 2;
722                    getValueData(target).refs++;
723                    outputValue(target, outer, false);
724                    if (isArgument) {
725                        outputValue(value, outer, false);
726                    }
727                    return;
728                }
729
730                // Special cases for methods.
731                if ((!expression && methodName.equals("set")
732                        && args.length == 2 && args[0] instanceof  Integer)
733                        || (expression && methodName.equals("get")
734                                && args.length == 1 && args[0] instanceof  Integer)) {
735                    attributes = attributes + " index="
736                            + quote(args[0].toString());
737                    args = (args.length == 1) ? new Object[] {}
738                            : new Object[] { args[1] };
739                } else if ((!expression && methodName.startsWith("set") && args.length == 1)
740                        || (expression && methodName.startsWith("get") && args.length == 0)) {
741                    attributes = attributes
742                            + " property="
743                            + quote(Introspector.decapitalize(methodName
744                                    .substring(3)));
745                } else if (!methodName.equals("new")
746                        && !methodName.equals("newInstance")) {
747                    attributes = attributes + " method=" + quote(methodName);
748                }
749
750                Vector statements = statementList(value);
751                // Use XML's short form when there is no body.
752                if (args.length == 0 && statements.size() == 0) {
753                    writeln("<" + tag + attributes + "/>");
754                    return;
755                }
756
757                writeln("<" + tag + attributes + ">");
758                indentation++;
759
760                for (int i = 0; i < args.length; i++) {
761                    outputValue(args[i], null, true);
762                }
763
764                for (int i = 0; i < statements.size(); i++) {
765                    Statement s = (Statement) statements.get(i);
766                    outputStatement(s, value, false);
767                }
768
769                indentation--;
770                writeln("</" + tag + ">");
771            }
772        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.