1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.rice.core.api.mo;
17  
18  import org.apache.commons.lang.builder.EqualsBuilder;
19  import org.apache.commons.lang.builder.HashCodeBuilder;
20  import org.apache.commons.lang.builder.ToStringBuilder;
21  import org.kuali.rice.core.api.CoreConstants;
22  import org.kuali.rice.core.api.util.collect.CollectionUtils;
23  
24  import javax.xml.bind.Unmarshaller;
25  import javax.xml.bind.annotation.XmlTransient;
26  import java.io.IOException;
27  import java.io.ObjectInputStream;
28  import java.io.ObjectOutputStream;
29  import java.lang.reflect.Field;
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  @XmlTransient 
46  public abstract class AbstractDataTransferObject implements ModelObjectComplete {
47  
48      private transient volatile Integer _hashCode;
49      private transient volatile String _toString;
50  
51      protected AbstractDataTransferObject() {
52          super();
53      }
54  
55      @Override
56      public int hashCode() {
57          
58          
59          Integer h = _hashCode;
60          if (h == null) {
61              synchronized (this) {
62                  h = _hashCode;
63                  if (h == null) {
64                      _hashCode = h = Integer.valueOf(HashCodeBuilder.reflectionHashCode(this, Constants.HASH_CODE_EQUALS_EXCLUDE));
65                  }
66              }
67          }
68  
69          return h.intValue();
70      }
71  
72      @Override
73      public boolean equals(Object obj) {
74          return EqualsBuilder.reflectionEquals(obj, this, Constants.HASH_CODE_EQUALS_EXCLUDE);
75      }
76  
77      @Override
78      public String toString() {
79          
80          
81          String t = _toString;
82          if (t == null) {
83              synchronized (this) {
84                  t = _toString;
85                  if (t == null) {
86                      _toString = t = ToStringBuilder.reflectionToString(this);
87                  }
88              }
89          }
90  
91          return t;
92      }
93  
94      @SuppressWarnings("unused")
95      protected void beforeUnmarshal(Unmarshaller u, Object parent) throws Exception {
96      }
97  
98      @SuppressWarnings("unused")
99      protected void afterUnmarshal(Unmarshaller u, Object parent) throws Exception {
100         CollectionUtils.makeUnmodifiableAndNullSafe(this);
101     }
102 
103     private transient Object serializationMutex = new Object();
104 
105     private void writeObject(ObjectOutputStream out) throws IOException {
106         synchronized (serializationMutex) {
107             clearFutureElements();
108             out.defaultWriteObject();
109         }
110     }
111 
112     private void readObject(ObjectInputStream ois) throws IOException,
113             ClassNotFoundException {
114         ois.defaultReadObject();
115         serializationMutex = new Object();
116     }
117 
118     
119 
120 
121 
122     private void clearFutureElements() {
123         try {
124             Field futureElementsField = getClass().getDeclaredField(CoreConstants.CommonElements.FUTURE_ELEMENTS);
125             boolean originalAccessible = futureElementsField.isAccessible();
126             futureElementsField.setAccessible(true);
127             try {
128                 futureElementsField.set(this, null);
129             } finally {
130                 futureElementsField.setAccessible(originalAccessible);
131             }
132         } catch (NoSuchFieldException e) {
133             
134         } catch (IllegalAccessException e) {
135             
136         }
137     }
138 
139 
140     
141 
142 
143     protected static class Constants {
144         final static String[] HASH_CODE_EQUALS_EXCLUDE = { CoreConstants.CommonElements.FUTURE_ELEMENTS, "_hashCode", "_toString" };
145     }
146 }