History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/beans/Encoder.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/beans/Encoder.java+345−0
@@ -0,0 +1,345 @@
1+/*
2+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package java.beans;
26+
27+import com.sun.beans.finder.PersistenceDelegateFinder;
28+
29+import java.util.HashMap;
30+import java.util.IdentityHashMap;
31+import java.util.Map;
32+
33+/**
34+ * An <code>Encoder</code> is a class which can be used to create
35+ * files or streams that encode the state of a collection of
36+ * JavaBeans in terms of their public APIs. The <code>Encoder</code>,
37+ * in conjunction with its persistence delegates, is responsible for
38+ * breaking the object graph down into a series of <code>Statements</code>s
39+ * and <code>Expression</code>s which can be used to create it.
40+ * A subclass typically provides a syntax for these expressions
41+ * using some human readable form - like Java source code or XML.
42+ *
43+ * @since 1.4
44+ *
45+ * @author Philip Milne
46+ */
47+
48+public class Encoder {
49+ private final PersistenceDelegateFinder finder = new PersistenceDelegateFinder();
50+ private Map bindings = new IdentityHashMap();
51+ private ExceptionListener exceptionListener;
52+ boolean executeStatements = true;
53+ private Map attributes;
54+
55+ /**
56+ * Write the specified object to the output stream.
57+ * The serialized form will denote a series of
58+ * expressions, the combined effect of which will create
59+ * an equivalent object when the input stream is read.
60+ * By default, the object is assumed to be a <em>JavaBean</em>
61+ * with a nullary constructor, whose state is defined by
62+ * the matching pairs of "setter" and "getter" methods
63+ * returned by the Introspector.
64+ *
65+ * @param o The object to be written to the stream.
66+ *
67+ * @see XMLDecoder#readObject
68+ */
69+ protected void writeObject(Object o) {
70+ if (o == this) {
71+ return;
72+ }
73+ PersistenceDelegate info = getPersistenceDelegate(o == null ? null : o.getClass());
74+ info.writeObject(o, this);
75+ }
76+
77+ /**
78+ * Sets the exception handler for this stream to <code>exceptionListener</code>.
79+ * The exception handler is notified when this stream catches recoverable
80+ * exceptions.
81+ *
82+ * @param exceptionListener The exception handler for this stream;
83+ * if <code>null</code> the default exception listener will be used.
84+ *
85+ * @see #getExceptionListener
86+ */
87+ public void setExceptionListener(ExceptionListener exceptionListener) {
88+ this.exceptionListener = exceptionListener;
89+ }
90+
91+ /**
92+ * Gets the exception handler for this stream.
93+ *
94+ * @return The exception handler for this stream;
95+ * Will return the default exception listener if this has not explicitly been set.
96+ *
97+ * @see #setExceptionListener
98+ */
99+ public ExceptionListener getExceptionListener() {
100+ return (exceptionListener != null) ? exceptionListener : Statement.defaultExceptionListener;
101+ }
102+
103+ Object getValue(Expression exp) {
104+ try {
105+ return (exp == null) ? null : exp.getValue();
106+ }
107+ catch (Exception e) {
108+ getExceptionListener().exceptionThrown(e);
109+ throw new RuntimeException("failed to evaluate: " + exp.toString());
110+ }
111+ }
112+
113+ /**
114+ * Returns the persistence delegate for the given type.
115+ * The persistence delegate is calculated by applying
116+ * the following rules in order:
117+ * <ol>
118+ * <li>
119+ * If a persistence delegate is associated with the given type
120+ * by using the {@link #setPersistenceDelegate} method
121+ * it is returned.
122+ * <li>
123+ * A persistence delegate is then looked up by the name
124+ * composed of the the fully qualified name of the given type
125+ * and the "PersistenceDelegate" postfix.
126+ * For example, a persistence delegate for the {@code Bean} class
127+ * should be named {@code BeanPersistenceDelegate}
128+ * and located in the same package.
129+ * <pre>
130+ * public class Bean { ... }
131+ * public class BeanPersistenceDelegate { ... }</pre>
132+ * The instance of the {@code BeanPersistenceDelegate} class
133+ * is returned for the {@code Bean} class.
134+ * <li>
135+ * If the type is {@code null},
136+ * a shared internal persistence delegate is returned
137+ * that encodes {@code null} value.
138+ * <li>
139+ * If the type is a {@code enum} declaration,
140+ * a shared internal persistence delegate is returned
141+ * that encodes constants of this enumeration
142+ * by their names.
143+ * <li>
144+ * If the type is a primitive type or the corresponding wrapper,
145+ * a shared internal persistence delegate is returned
146+ * that encodes values of the given type.
147+ * <li>
148+ * If the type is an array,
149+ * a shared internal persistence delegate is returned
150+ * that encodes an array of the appropriate type and length,
151+ * and each of its elements as if they are properties.
152+ * <li>
153+ * If the type is a proxy,
154+ * a shared internal persistence delegate is returned
155+ * that encodes a proxy instance by using
156+ * the {@link java.lang.reflect.Proxy#newProxyInstance} method.
157+ * <li>
158+ * If the {@link BeanInfo} for this type has a {@link BeanDescriptor}
159+ * which defined a "persistenceDelegate" attribute,
160+ * the value of this named attribute is returned.
161+ * <li>
162+ * In all other cases the default persistence delegate is returned.
163+ * The default persistence delegate assumes the type is a <em>JavaBean</em>,
164+ * implying that it has a default constructor and that its state
165+ * may be characterized by the matching pairs of "setter" and "getter"
166+ * methods returned by the {@link Introspector} class.
167+ * The default constructor is the constructor with the greatest number
168+ * of parameters that has the {@link ConstructorProperties} annotation.
169+ * If none of the constructors has the {@code ConstructorProperties} annotation,
170+ * then the nullary constructor (constructor with no parameters) will be used.
171+ * For example, in the following code fragment, the nullary constructor
172+ * for the {@code Foo} class will be used,
173+ * while the two-parameter constructor
174+ * for the {@code Bar} class will be used.
175+ * <pre>
176+ * public class Foo {
177+ * public Foo() { ... }
178+ * public Foo(int x) { ... }
179+ * }
180+ * public class Bar {
181+ * public Bar() { ... }
182+ * &#64;ConstructorProperties({"x"})
183+ * public Bar(int x) { ... }
184+ * &#64;ConstructorProperties({"x", "y"})
185+ * public Bar(int x, int y) { ... }
186+ * }</pre>
187+ * </ol>
188+ *
189+ * @param type the class of the objects
190+ * @return the persistence delegate for the given type
191+ *
192+ * @see #setPersistenceDelegate
193+ * @see java.beans.Introspector#getBeanInfo
194+ * @see java.beans.BeanInfo#getBeanDescriptor
195+ */
196+ public PersistenceDelegate getPersistenceDelegate(Class<?> type) {
197+ PersistenceDelegate pd = this.finder.find(type);
198+ return (pd != null) ? pd : MetaData.getPersistenceDelegate(type);
199+ }
200+
201+ /**
202+ * Associates the specified persistence delegate with the given type.
203+ *
204+ * @param type the class of objects that the specified persistence delegate applies to
205+ * @param delegate the persistence delegate for instances of the given type
206+ *
207+ * @see #getPersistenceDelegate
208+ * @see java.beans.Introspector#getBeanInfo
209+ * @see java.beans.BeanInfo#getBeanDescriptor
210+ */
211+ public void setPersistenceDelegate(Class<?> type, PersistenceDelegate delegate) {
212+ this.finder.register(type, delegate);
213+ }
214+
215+ /**
216+ * Removes the entry for this instance, returning the old entry.
217+ *
218+ * @param oldInstance The entry that should be removed.
219+ * @return The entry that was removed.
220+ *
221+ * @see #get
222+ */
223+ public Object remove(Object oldInstance) {
224+ Expression exp = (Expression)bindings.remove(oldInstance);
225+ return getValue(exp);
226+ }
227+
228+ /**
229+ * Returns a tentative value for <code>oldInstance</code> in
230+ * the environment created by this stream. A persistence
231+ * delegate can use its <code>mutatesTo</code> method to
232+ * determine whether this value may be initialized to
233+ * form the equivalent object at the output or whether
234+ * a new object must be instantiated afresh. If the
235+ * stream has not yet seen this value, null is returned.
236+ *
237+ * @param oldInstance The instance to be looked up.
238+ * @return The object, null if the object has not been seen before.
239+ */
240+ public Object get(Object oldInstance) {
241+ if (oldInstance == null || oldInstance == this ||
242+ oldInstance.getClass() == String.class) {
243+ return oldInstance;
244+ }
245+ Expression exp = (Expression)bindings.get(oldInstance);
246+ return getValue(exp);
247+ }
248+
249+ private Object writeObject1(Object oldInstance) {
250+ Object o = get(oldInstance);
251+ if (o == null) {
252+ writeObject(oldInstance);
253+ o = get(oldInstance);
254+ }
255+ return o;
256+ }
257+
258+ private Statement cloneStatement(Statement oldExp) {
259+ Object oldTarget = oldExp.getTarget();
260+ Object newTarget = writeObject1(oldTarget);
261+
262+ Object[] oldArgs = oldExp.getArguments();
263+ Object[] newArgs = new Object[oldArgs.length];
264+ for (int i = 0; i < oldArgs.length; i++) {
265+ newArgs[i] = writeObject1(oldArgs[i]);
266+ }
267+ Statement newExp = Statement.class.equals(oldExp.getClass())
268+ ? new Statement(newTarget, oldExp.getMethodName(), newArgs)
269+ : new Expression(newTarget, oldExp.getMethodName(), newArgs);
270+ newExp.loader = oldExp.loader;
271+ return newExp;
272+ }
273+
274+ /**
275+ * Writes statement <code>oldStm</code> to the stream.
276+ * The <code>oldStm</code> should be written entirely
277+ * in terms of the callers environment, i.e. the
278+ * target and all arguments should be part of the
279+ * object graph being written. These expressions
280+ * represent a series of "what happened" expressions
281+ * which tell the output stream how to produce an
282+ * object graph like the original.
283+ * <p>
284+ * The implementation of this method will produce
285+ * a second expression to represent the same expression in
286+ * an environment that will exist when the stream is read.
287+ * This is achieved simply by calling <code>writeObject</code>
288+ * on the target and all the arguments and building a new
289+ * expression with the results.
290+ *
291+ * @param oldStm The expression to be written to the stream.
292+ */
293+ public void writeStatement(Statement oldStm) {
294+ // System.out.println("writeStatement: " + oldExp);
295+ Statement newStm = cloneStatement(oldStm);
296+ if (oldStm.getTarget() != this && executeStatements) {
297+ try {
298+ newStm.execute();
299+ } catch (Exception e) {
300+ getExceptionListener().exceptionThrown(new Exception("Encoder: discarding statement "
301+ + newStm, e));
302+ }
303+ }
304+ }
305+
306+ /**
307+ * The implementation first checks to see if an
308+ * expression with this value has already been written.
309+ * If not, the expression is cloned, using
310+ * the same procedure as <code>writeStatement</code>,
311+ * and the value of this expression is reconciled
312+ * with the value of the cloned expression
313+ * by calling <code>writeObject</code>.
314+ *
315+ * @param oldExp The expression to be written to the stream.
316+ */
317+ public void writeExpression(Expression oldExp) {
318+ // System.out.println("Encoder::writeExpression: " + oldExp);
319+ Object oldValue = getValue(oldExp);
320+ if (get(oldValue) != null) {
321+ return;
322+ }
323+ bindings.put(oldValue, (Expression)cloneStatement(oldExp));
324+ writeObject(oldValue);
325+ }
326+
327+ void clear() {
328+ bindings.clear();
329+ }
330+
331+ // Package private method for setting an attributes table for the encoder
332+ void setAttribute(Object key, Object value) {
333+ if (attributes == null) {
334+ attributes = new HashMap();
335+ }
336+ attributes.put(key, value);
337+ }
338+
339+ Object getAttribute(Object key) {
340+ if (attributes == null) {
341+ return null;
342+ }
343+ return attributes.get(key);
344+ }
345+}