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 */
25package java.beans;
26
27import com.sun.beans.finder.PersistenceDelegateFinder;
28
29import java.util.HashMap;
30import java.util.IdentityHashMap;
31import 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
48public 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}