001: /**
002: *
003: */package clime.messadmin.providers.serializable;
004:
005: import java.io.Serializable;
006: import java.util.Collection;
007: import java.util.Iterator;
008: import java.util.Map;
009:
010: import clime.messadmin.providers.spi.SerializableProvider;
011: import clime.messadmin.utils.IdentityHashMap;
012:
013: /**
014: * Determines if an object is serializable by lookup if it implementes java.io.Serializable.
015: * While this implementation is quick, it may not be accurate:
016: * a return value of true does not waranty that such an object is really serializable.
017: * a return value of false is a 100% warranty that the object is not serializable.
018: * This implementation recurses into Collections and Arrays.
019: * @author Cédrik LIME
020: */
021: public class MaybeSerializableProvider implements SerializableProvider {
022:
023: /**
024: *
025: */
026: public MaybeSerializableProvider() {
027: super ();
028: }
029:
030: /**
031: * {@inheritDoc}
032: */
033: public boolean isSerializable(Object obj) {
034: return isMaybeSerializable(obj);
035: }
036:
037: /**
038: * {@inheritDoc}
039: */
040: public int getPriority() {
041: return 10;
042: }
043:
044: /**
045: * Determines if an object is serializable by lookup if it implementes java.io.Serializable.
046: * While this implementation is quick, it may not be accurate:
047: * a return value of true does not waranty that such an object is really serializable. Use {@link #isSerializable(Object)} for certainty.
048: * a return value of false is a 100% warranty that the object is not serializable.
049: * This implementation recurses into Collections and Arrays.
050: * @param o
051: * @return true if o is Serializable, false if not
052: */
053: private static boolean isMaybeSerializable(Object o) {
054: if (o == null) {
055: return true;
056: }
057: if (!(o instanceof Serializable)) {
058: return false;
059: }
060: IdentityHashMap visitedObjects = new IdentityHashMap();
061: return isMaybeSerializable(o, visitedObjects);
062: }
063:
064: /**
065: * Implementation note: we need to track a list of visited objects in order to
066: * avoid graph cycle problems.
067: * @see #isMaybeSerializable(Object)
068: * @param o
069: * @param visitedObjects
070: * @return true if o is Serializable, false if not
071: */
072: private static boolean isMaybeSerializable(Object o,
073: IdentityHashMap visitedObjects) {
074: if (o == null) {
075: return true;
076: }
077: if (!(o instanceof Serializable)) {
078: return false;
079: }
080: if (visitedObjects.containsKey(o)) {
081: return true;
082: }
083: visitedObjects.put(o, o);
084: // Collection: each member of the collection must be Serializable
085: if (o instanceof Collection) {
086: try {
087: Iterator iter = ((Collection) o).iterator();
088: while (iter.hasNext()) {
089: Object oo = iter.next();
090: if (!isMaybeSerializable(oo, visitedObjects)) {
091: return false;
092: }
093: }
094: } catch (RuntimeException rte) {
095: //e.g. Hibernate Lazy Exception
096: return false;
097: }
098: }
099: // Map: each entry (key and value) of the map must be Serializable
100: if (o instanceof Map) {
101: try {
102: Iterator iter = ((Map) o).entrySet().iterator();
103: while (iter.hasNext()) {
104: Map.Entry entry = (Map.Entry) iter.next();
105: if (!isMaybeSerializable(entry.getKey(),
106: visitedObjects)
107: || !isMaybeSerializable(entry.getValue(),
108: visitedObjects)) {
109: return false;
110: }
111: }
112: } catch (RuntimeException rte) {
113: //e.g. Hibernate Lazy Exception
114: return false;
115: }
116: }
117: // Array: each member of the collection must be Serializable
118: if (o.getClass().isArray()) {
119: // arrays of primitive types are Serializable
120: if (o.getClass().getComponentType().isPrimitive()) {
121: return true;
122: }
123: // // There's only 1 type for the Array. If this type is Serializable, then all objects in the array are Serializable
124: // // Note: this can't be that simple! E.g. array of Collection, with non-serializable items inside...
125: // if (Serializable.class.isAssignableFrom(o.getClass().getComponentType())) {
126: // return true;
127: // }
128: // if object type is not Serializable, no need to check inside the array
129: // if ((Object[]) o).length > 0 && ! Serializable.class.isAssignableFrom(o.getClass().getComponentType())) {
130: // return false;
131: // }
132: // Array type is not Serializable, but maybe all entries are. We need to check.
133: Object[] array = (Object[]) o;
134: for (int i = 0; i < array.length; ++i) {
135: Object object = array[i];
136: if (!isMaybeSerializable(object, visitedObjects)) {
137: return false;
138: }
139: }
140: }
141: return true;
142: }
143: }
|