Source Code Cross Referenced for SerializableConverter.java in  » XML » xstream-1.3 » com » thoughtworks » xstream » converters » reflection » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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 geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » XML » xstream 1.3 » com.thoughtworks.xstream.converters.reflection 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright (C) 2004, 2005, 2006 Joe Walnes.
003:         * Copyright (C) 2006, 2007 XStream Committers.
004:         * All rights reserved.
005:         *
006:         * The software in this package is published under the terms of the BSD
007:         * style license a copy of which has been included with this distribution in
008:         * the LICENSE.txt file.
009:         * 
010:         * Created on 21. December 2004 by Joe Walnes
011:         */
012:        package com.thoughtworks.xstream.converters.reflection;
013:
014:        import java.io.IOException;
015:        import java.io.InvalidObjectException;
016:        import java.io.ObjectInputValidation;
017:        import java.io.ObjectStreamClass;
018:        import java.io.ObjectStreamField;
019:        import java.io.Serializable;
020:        import java.lang.reflect.Field;
021:        import java.util.ArrayList;
022:        import java.util.Collections;
023:        import java.util.HashMap;
024:        import java.util.Iterator;
025:        import java.util.List;
026:        import java.util.Map;
027:
028:        import com.thoughtworks.xstream.converters.ConversionException;
029:        import com.thoughtworks.xstream.converters.MarshallingContext;
030:        import com.thoughtworks.xstream.converters.UnmarshallingContext;
031:        import com.thoughtworks.xstream.core.util.CustomObjectInputStream;
032:        import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;
033:        import com.thoughtworks.xstream.io.HierarchicalStreamReader;
034:        import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
035:        import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
036:        import com.thoughtworks.xstream.mapper.Mapper;
037:
038:        /**
039:         * Emulates the mechanism used by standard Java Serialization for classes that implement java.io.Serializable AND
040:         * implement or inherit a custom readObject()/writeObject() method.
041:         *
042:         * <h3>Supported features of serialization</h3>
043:         * <ul>
044:         *   <li>readObject(), writeObject()</li>
045:         *   <li>class inheritance</li>
046:         *   <li>readResolve(), writeReplace()</li>
047:         * </ul>
048:         *
049:         * <h3>Currently unsupported features</h3>
050:         * <ul>
051:         *   <li>putFields(), writeFields(), readFields()</li>
052:         *   <li>ObjectStreamField[] serialPersistentFields</li>
053:         *   <li>ObjectInputValidation</li>
054:         * </ul>
055:         *
056:         * @author Joe Walnes
057:         * @author J&ouml;rg Schaible
058:         */
059:        public class SerializableConverter extends AbstractReflectionConverter {
060:
061:            private static final String ELEMENT_NULL = "null";
062:            private static final String ELEMENT_DEFAULT = "default";
063:            private static final String ELEMENT_UNSERIALIZABLE_PARENTS = "unserializable-parents";
064:            private static final String ATTRIBUTE_CLASS = "class";
065:            private static final String ATTRIBUTE_SERIALIZATION = "serialization";
066:            private static final String ATTRIBUTE_VALUE_CUSTOM = "custom";
067:            private static final String ELEMENT_FIELDS = "fields";
068:            private static final String ELEMENT_FIELD = "field";
069:            private static final String ATTRIBUTE_NAME = "name";
070:
071:            public SerializableConverter(Mapper mapper,
072:                    ReflectionProvider reflectionProvider) {
073:                super (mapper, new UnserializableParentsReflectionProvider(
074:                        reflectionProvider));
075:            }
076:
077:            public boolean canConvert(Class type) {
078:                return isSerializable(type);
079:            }
080:
081:            private boolean isSerializable(Class type) {
082:                return Serializable.class.isAssignableFrom(type)
083:                        && (serializationMethodInvoker.supportsReadObject(type,
084:                                true) || serializationMethodInvoker
085:                                .supportsWriteObject(type, true));
086:            }
087:
088:            public void doMarshal(final Object source,
089:                    final HierarchicalStreamWriter writer,
090:                    final MarshallingContext context) {
091:                writer.addAttribute(mapper
092:                        .aliasForAttribute(ATTRIBUTE_SERIALIZATION),
093:                        ATTRIBUTE_VALUE_CUSTOM);
094:
095:                // this is an array as it's a non final value that's accessed from an anonymous inner class.
096:                final Class[] currentType = new Class[1];
097:                final boolean[] writtenClassWrapper = { false };
098:
099:                CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() {
100:
101:                    public void writeToStream(Object object) {
102:                        if (object == null) {
103:                            writer.startNode(ELEMENT_NULL);
104:                            writer.endNode();
105:                        } else {
106:                            ExtendedHierarchicalStreamWriterHelper.startNode(
107:                                    writer, mapper.serializedClass(object
108:                                            .getClass()), object.getClass());
109:                            context.convertAnother(object);
110:                            writer.endNode();
111:                        }
112:                    }
113:
114:                    public void writeFieldsToStream(Map fields) {
115:                        ObjectStreamClass objectStreamClass = ObjectStreamClass
116:                                .lookup(currentType[0]);
117:
118:                        writer.startNode(ELEMENT_DEFAULT);
119:                        for (Iterator iterator = fields.keySet().iterator(); iterator
120:                                .hasNext();) {
121:                            String name = (String) iterator.next();
122:                            if (!mapper.shouldSerializeMember(currentType[0],
123:                                    name)) {
124:                                continue;
125:                            }
126:                            ObjectStreamField field = objectStreamClass
127:                                    .getField(name);
128:                            Object value = fields.get(name);
129:                            if (field == null) {
130:                                throw new ObjectAccessException("Class "
131:                                        + value.getClass().getName()
132:                                        + " may not write a field named '"
133:                                        + name + "'");
134:                            }
135:                            if (value != null) {
136:                                ExtendedHierarchicalStreamWriterHelper
137:                                        .startNode(writer, mapper
138:                                                .serializedMember(source
139:                                                        .getClass(), name),
140:                                                field.getType());
141:                                if (field.getType() != value.getClass()
142:                                        && !field.getType().isPrimitive()) {
143:                                    writer
144:                                            .addAttribute(
145:                                                    mapper
146:                                                            .aliasForAttribute(ATTRIBUTE_CLASS),
147:                                                    mapper
148:                                                            .serializedClass(value
149:                                                                    .getClass()));
150:                                }
151:                                context.convertAnother(value);
152:                                writer.endNode();
153:                            }
154:                        }
155:                        writer.endNode();
156:                    }
157:
158:                    public void defaultWriteObject() {
159:                        boolean writtenDefaultFields = false;
160:
161:                        ObjectStreamClass objectStreamClass = ObjectStreamClass
162:                                .lookup(currentType[0]);
163:
164:                        if (objectStreamClass == null) {
165:                            return;
166:                        }
167:
168:                        ObjectStreamField[] fields = objectStreamClass
169:                                .getFields();
170:                        for (int i = 0; i < fields.length; i++) {
171:                            ObjectStreamField field = fields[i];
172:                            Object value = readField(field, currentType[0],
173:                                    source);
174:                            if (value != null) {
175:                                if (!writtenClassWrapper[0]) {
176:                                    writer.startNode(mapper
177:                                            .serializedClass(currentType[0]));
178:                                    writtenClassWrapper[0] = true;
179:                                }
180:                                if (!writtenDefaultFields) {
181:                                    writer.startNode(ELEMENT_DEFAULT);
182:                                    writtenDefaultFields = true;
183:                                }
184:                                if (!mapper.shouldSerializeMember(
185:                                        currentType[0], field.getName())) {
186:                                    continue;
187:                                }
188:
189:                                ExtendedHierarchicalStreamWriterHelper
190:                                        .startNode(writer, mapper
191:                                                .serializedMember(source
192:                                                        .getClass(), field
193:                                                        .getName()), field
194:                                                .getType());
195:
196:                                Class actualType = value.getClass();
197:                                Class defaultType = mapper
198:                                        .defaultImplementationOf(field
199:                                                .getType());
200:                                if (!actualType.equals(defaultType)) {
201:                                    writer
202:                                            .addAttribute(
203:                                                    mapper
204:                                                            .aliasForAttribute(ATTRIBUTE_CLASS),
205:                                                    mapper
206:                                                            .serializedClass(actualType));
207:                                }
208:
209:                                context.convertAnother(value);
210:
211:                                writer.endNode();
212:                            }
213:                        }
214:                        if (writtenClassWrapper[0] && !writtenDefaultFields) {
215:                            writer.startNode(ELEMENT_DEFAULT);
216:                            writer.endNode();
217:                        } else if (writtenDefaultFields) {
218:                            writer.endNode();
219:                        }
220:                    }
221:
222:                    public void flush() {
223:                        writer.flush();
224:                    }
225:
226:                    public void close() {
227:                        throw new UnsupportedOperationException(
228:                                "Objects are not allowed to call ObjectOutputStream.close() from writeObject()");
229:                    }
230:                };
231:
232:                try {
233:                    boolean mustHandleUnserializableParent = false;
234:                    Iterator classHieararchy = hierarchyFor(source.getClass())
235:                            .iterator();
236:                    while (classHieararchy.hasNext()) {
237:                        currentType[0] = (Class) classHieararchy.next();
238:                        if (!Serializable.class
239:                                .isAssignableFrom(currentType[0])) {
240:                            mustHandleUnserializableParent = true;
241:                            continue;
242:                        } else {
243:                            if (mustHandleUnserializableParent) {
244:                                marshalUnserializableParent(writer, context,
245:                                        source);
246:                                mustHandleUnserializableParent = false;
247:                            }
248:                            if (serializationMethodInvoker.supportsWriteObject(
249:                                    currentType[0], false)) {
250:                                writtenClassWrapper[0] = true;
251:                                writer.startNode(mapper
252:                                        .serializedClass(currentType[0]));
253:                                CustomObjectOutputStream objectOutputStream = CustomObjectOutputStream
254:                                        .getInstance(context, callback);
255:                                serializationMethodInvoker.callWriteObject(
256:                                        currentType[0], source,
257:                                        objectOutputStream);
258:                                objectOutputStream.popCallback();
259:                                writer.endNode();
260:                            } else if (serializationMethodInvoker
261:                                    .supportsReadObject(currentType[0], false)) {
262:                                // Special case for objects that have readObject(), but not writeObject().
263:                                // The class wrapper is always written, whether or not this class in the hierarchy has
264:                                // serializable fields. This guarantees that readObject() will be called upon deserialization.
265:                                writtenClassWrapper[0] = true;
266:                                writer.startNode(mapper
267:                                        .serializedClass(currentType[0]));
268:                                callback.defaultWriteObject();
269:                                writer.endNode();
270:                            } else {
271:                                writtenClassWrapper[0] = false;
272:                                callback.defaultWriteObject();
273:                                if (writtenClassWrapper[0]) {
274:                                    writer.endNode();
275:                                }
276:                            }
277:                        }
278:                    }
279:                } catch (IOException e) {
280:                    throw new ObjectAccessException(
281:                            "Could not call defaultWriteObject()", e);
282:                }
283:            }
284:
285:            private void marshalUnserializableParent(
286:                    final HierarchicalStreamWriter writer,
287:                    final MarshallingContext context,
288:                    final Object replacedSource) {
289:                writer.startNode(ELEMENT_UNSERIALIZABLE_PARENTS);
290:                super .doMarshal(replacedSource, writer, context);
291:                writer.endNode();
292:            }
293:
294:            private Object readField(ObjectStreamField field, Class type,
295:                    Object instance) {
296:                try {
297:                    Field javaField = type.getDeclaredField(field.getName());
298:                    javaField.setAccessible(true);
299:                    return javaField.get(instance);
300:                } catch (IllegalArgumentException e) {
301:                    throw new ObjectAccessException("Could not get field "
302:                            + field.getClass() + "." + field.getName(), e);
303:                } catch (IllegalAccessException e) {
304:                    throw new ObjectAccessException("Could not get field "
305:                            + field.getClass() + "." + field.getName(), e);
306:                } catch (NoSuchFieldException e) {
307:                    throw new ObjectAccessException("Could not get field "
308:                            + field.getClass() + "." + field.getName(), e);
309:                } catch (SecurityException e) {
310:                    throw new ObjectAccessException("Could not get field "
311:                            + field.getClass() + "." + field.getName(), e);
312:                }
313:            }
314:
315:            protected List hierarchyFor(Class type) {
316:                List result = new ArrayList();
317:                while (type != Object.class) {
318:                    result.add(type);
319:                    type = type.getSuperclass();
320:                }
321:
322:                // In Java Object Serialization, the classes are deserialized starting from parent class and moving down.
323:                Collections.reverse(result);
324:
325:                return result;
326:            }
327:
328:            public Object doUnmarshal(final Object result,
329:                    final HierarchicalStreamReader reader,
330:                    final UnmarshallingContext context) {
331:                // this is an array as it's a non final value that's accessed from an anonymous inner class.
332:                final Class[] currentType = new Class[1];
333:
334:                if (!ATTRIBUTE_VALUE_CUSTOM.equals(reader.getAttribute(mapper
335:                        .aliasForAttribute(ATTRIBUTE_SERIALIZATION)))) {
336:                    throw new ConversionException(
337:                            "Cannot deserialize object with new readObject()/writeObject() methods");
338:                }
339:
340:                CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() {
341:                    public Object readFromStream() {
342:                        reader.moveDown();
343:                        Class type = mapper.realClass(reader.getNodeName());
344:                        Object value = context.convertAnother(result, type);
345:                        reader.moveUp();
346:                        return value;
347:                    }
348:
349:                    public Map readFieldsFromStream() {
350:                        final Map fields = new HashMap();
351:                        reader.moveDown();
352:                        if (reader.getNodeName().equals(ELEMENT_FIELDS)) {
353:                            // Maintain compatibility with XStream 1.1.0
354:                            while (reader.hasMoreChildren()) {
355:                                reader.moveDown();
356:                                if (!reader.getNodeName().equals(ELEMENT_FIELD)) {
357:                                    throw new ConversionException("Expected <"
358:                                            + ELEMENT_FIELD
359:                                            + "/> element inside <"
360:                                            + ELEMENT_FIELD + "/>");
361:                                }
362:                                String name = reader
363:                                        .getAttribute(ATTRIBUTE_NAME);
364:                                Class type = mapper.realClass(reader
365:                                        .getAttribute(ATTRIBUTE_CLASS));
366:                                Object value = context.convertAnother(result,
367:                                        type);
368:                                fields.put(name, value);
369:                                reader.moveUp();
370:                            }
371:                        } else if (reader.getNodeName().equals(ELEMENT_DEFAULT)) {
372:                            // New format introduced in XStream 1.1.1
373:                            ObjectStreamClass objectStreamClass = ObjectStreamClass
374:                                    .lookup(currentType[0]);
375:                            while (reader.hasMoreChildren()) {
376:                                reader.moveDown();
377:                                String name = mapper.realMember(currentType[0],
378:                                        reader.getNodeName());
379:                                if (mapper.shouldSerializeMember(
380:                                        currentType[0], name)) {
381:                                    String typeName = reader
382:                                            .getAttribute(mapper
383:                                                    .aliasForAttribute(ATTRIBUTE_CLASS));
384:                                    Class type;
385:                                    if (typeName != null) {
386:                                        type = mapper.realClass(typeName);
387:                                    } else {
388:                                        ObjectStreamField field = objectStreamClass
389:                                                .getField(name);
390:                                        if (field == null) {
391:                                            throw new ObjectAccessException(
392:                                                    "Class "
393:                                                            + currentType[0]
394:                                                            + " does not contain a field named '"
395:                                                            + name + "'");
396:                                        }
397:                                        type = field.getType();
398:                                    }
399:                                    Object value = context.convertAnother(
400:                                            result, type);
401:                                    fields.put(name, value);
402:                                }
403:                                reader.moveUp();
404:                            }
405:                        } else {
406:                            throw new ConversionException(
407:                                    "Expected <"
408:                                            + ELEMENT_FIELDS
409:                                            + "/> or <"
410:                                            + ELEMENT_DEFAULT
411:                                            + "/> element when calling ObjectInputStream.readFields()");
412:                        }
413:                        reader.moveUp();
414:                        return fields;
415:                    }
416:
417:                    public void defaultReadObject() {
418:                        if (!reader.hasMoreChildren()) {
419:                            return;
420:                        }
421:                        reader.moveDown();
422:                        if (!reader.getNodeName().equals(ELEMENT_DEFAULT)) {
423:                            throw new ConversionException("Expected <"
424:                                    + ELEMENT_DEFAULT
425:                                    + "/> element in readObject() stream");
426:                        }
427:                        while (reader.hasMoreChildren()) {
428:                            reader.moveDown();
429:
430:                            String fieldName = mapper.realMember(
431:                                    currentType[0], reader.getNodeName());
432:                            if (mapper.shouldSerializeMember(currentType[0],
433:                                    fieldName)) {
434:                                String classAttribute = reader
435:                                        .getAttribute(mapper
436:                                                .aliasForAttribute(ATTRIBUTE_CLASS));
437:                                final Class type;
438:                                if (classAttribute != null) {
439:                                    type = mapper.realClass(classAttribute);
440:                                } else {
441:                                    type = mapper
442:                                            .defaultImplementationOf(reflectionProvider
443:                                                    .getFieldType(result,
444:                                                            fieldName,
445:                                                            currentType[0]));
446:                                }
447:
448:                                Object value = context.convertAnother(result,
449:                                        type);
450:                                reflectionProvider.writeField(result,
451:                                        fieldName, value, currentType[0]);
452:                            }
453:
454:                            reader.moveUp();
455:                        }
456:                        reader.moveUp();
457:                    }
458:
459:                    public void registerValidation(
460:                            final ObjectInputValidation validation, int priority) {
461:                        context.addCompletionCallback(new Runnable() {
462:                            public void run() {
463:                                try {
464:                                    validation.validateObject();
465:                                } catch (InvalidObjectException e) {
466:                                    throw new ObjectAccessException(
467:                                            "Cannot validate object : "
468:                                                    + e.getMessage(), e);
469:                                }
470:                            }
471:                        }, priority);
472:                    }
473:
474:                    public void close() {
475:                        throw new UnsupportedOperationException(
476:                                "Objects are not allowed to call ObjectInputStream.close() from readObject()");
477:                    }
478:                };
479:
480:                while (reader.hasMoreChildren()) {
481:                    reader.moveDown();
482:                    String nodeName = reader.getNodeName();
483:                    if (nodeName.equals(ELEMENT_UNSERIALIZABLE_PARENTS)) {
484:                        super .doUnmarshal(result, reader, context);
485:                    } else {
486:                        currentType[0] = mapper.defaultImplementationOf(mapper
487:                                .realClass(nodeName));
488:                        if (serializationMethodInvoker.supportsReadObject(
489:                                currentType[0], false)) {
490:                            CustomObjectInputStream objectInputStream = CustomObjectInputStream
491:                                    .getInstance(context, callback);
492:                            serializationMethodInvoker.callReadObject(
493:                                    currentType[0], result, objectInputStream);
494:                            objectInputStream.popCallback();
495:                        } else {
496:                            try {
497:                                callback.defaultReadObject();
498:                            } catch (IOException e) {
499:                                throw new ObjectAccessException(
500:                                        "Could not call defaultWriteObject()",
501:                                        e);
502:                            }
503:                        }
504:                    }
505:                    reader.moveUp();
506:                }
507:
508:                return result;
509:            }
510:
511:            protected void doMarshalConditionally(final Object source,
512:                    final HierarchicalStreamWriter writer,
513:                    final MarshallingContext context) {
514:                if (isSerializable(source.getClass())) {
515:                    doMarshal(source, writer, context);
516:                } else {
517:                    super .doMarshal(source, writer, context);
518:                }
519:            }
520:
521:            protected Object doUnmarshalConditionally(final Object result,
522:                    final HierarchicalStreamReader reader,
523:                    final UnmarshallingContext context) {
524:                return isSerializable(result.getClass()) ? doUnmarshal(result,
525:                        reader, context) : super .doUnmarshal(result, reader,
526:                        context);
527:            }
528:
529:            private static class UnserializableParentsReflectionProvider extends
530:                    ReflectionProviderWrapper {
531:
532:                public UnserializableParentsReflectionProvider(
533:                        final ReflectionProvider reflectionProvider) {
534:                    super (reflectionProvider);
535:                }
536:
537:                public void visitSerializableFields(final Object object,
538:                        final Visitor visitor) {
539:                    wrapped.visitSerializableFields(object, new Visitor() {
540:                        public void visit(String name, Class type,
541:                                Class definedIn, Object value) {
542:                            if (!Serializable.class.isAssignableFrom(definedIn)) {
543:                                visitor.visit(name, type, definedIn, value);
544:                            }
545:                        }
546:                    });
547:                }
548:            }
549:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.