1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.service.impl;
17
18 import com.thoughtworks.xstream.XStream;
19 import com.thoughtworks.xstream.converters.MarshallingContext;
20 import com.thoughtworks.xstream.converters.UnmarshallingContext;
21 import com.thoughtworks.xstream.converters.collections.CollectionConverter;
22 import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
23 import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
24 import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
25 import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
26 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
27 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
28 import com.thoughtworks.xstream.mapper.Mapper;
29 import org.kuali.rice.krad.document.Document;
30 import org.kuali.rice.krad.service.DocumentSerializerService;
31 import org.kuali.rice.krad.service.LegacyDataAdapter;
32 import org.kuali.rice.krad.service.SerializerService;
33 import org.kuali.rice.krad.service.XmlObjectSerializerService;
34 import org.kuali.rice.krad.service.util.DateTimeConverter;
35 import org.kuali.rice.krad.util.documentserializer.AlwaysTruePropertySerializibilityEvaluator;
36 import org.kuali.rice.krad.util.documentserializer.PropertySerializabilityEvaluator;
37 import org.kuali.rice.krad.util.documentserializer.PropertyType;
38 import org.kuali.rice.krad.util.documentserializer.SerializationState;
39 import org.springframework.beans.factory.annotation.Required;
40 import org.springframework.util.AutoPopulatingList;
41
42 import java.lang.reflect.Field;
43 import java.util.ArrayList;
44 import java.util.Iterator;
45 import java.util.List;
46
47
48
49
50
51
52
53
54
55
56 public abstract class SerializerServiceBase implements SerializerService {
57
58 protected LegacyDataAdapter legacyDataAdapter;
59 protected XmlObjectSerializerService xmlObjectSerializerService;
60
61 protected XStream xstream;
62 protected ThreadLocal<SerializationState> serializationStates;
63 protected ThreadLocal<PropertySerializabilityEvaluator> evaluators;
64
65 public SerializerServiceBase() {
66 serializationStates = new ThreadLocal<SerializationState>();
67 evaluators = new ThreadLocal<PropertySerializabilityEvaluator>();
68
69 xstream = new XStream(new ProxyAndStateAwareJavaReflectionProvider());
70 xstream.registerConverter(new ProxyConverter(xstream.getMapper(), xstream.getReflectionProvider() ));
71 try {
72 Class<?> objListProxyClass = Class.forName("org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl");
73 xstream.addDefaultImplementation(ArrayList.class, objListProxyClass);
74 xstream.addDefaultImplementation(AutoPopulatingList.class, objListProxyClass);
75 } catch ( Exception ex ) {
76
77 }
78 xstream.registerConverter(new AutoPopulatingListConverter(xstream.getMapper()));
79 xstream.registerConverter(new DateTimeConverter());
80 }
81
82
83
84
85 public String serializeBusinessObjectToXml(Object businessObject) {
86 PropertySerializabilityEvaluator propertySerizabilityEvaluator =
87 getPropertySerizabilityEvaluator(businessObject);
88 evaluators.set(propertySerizabilityEvaluator);
89 SerializationState state = new SerializationState();
90 serializationStates.set(state);
91
92
93 String xml;
94 if (propertySerizabilityEvaluator instanceof AlwaysTruePropertySerializibilityEvaluator) {
95 xml = getXmlObjectSerializerService().toXml(businessObject);
96 } else {
97 xml = xstream.toXML(businessObject);
98 }
99
100 evaluators.set(null);
101 serializationStates.set(null);
102 return xml;
103 }
104
105
106
107
108
109
110
111
112
113
114
115 protected boolean ignoreField(Field field) {
116 return false;
117 }
118
119
120
121
122
123
124
125 protected abstract PropertySerializabilityEvaluator getPropertySerizabilityEvaluator(Object dataObject);
126
127 public class ProxyConverter extends ReflectionConverter {
128 public ProxyConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
129 super(mapper, reflectionProvider);
130 }
131 @Override
132 public boolean canConvert(Class clazz) {
133 return clazz.getName().contains("CGLIB") || clazz.getName().equals("org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl");
134 }
135
136 @Override
137 public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {
138 if (obj.getClass().getName().equals("org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl")) {
139 List copiedList = new ArrayList();
140 List proxiedList = (List) obj;
141 for (Iterator iter = proxiedList.iterator(); iter.hasNext();) {
142 copiedList.add(iter.next());
143 }
144 context.convertAnother( copiedList );
145 }
146 else {
147 super.marshal(legacyDataAdapter.resolveProxy(obj), writer, context);
148 }
149 }
150
151 @Override
152 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
153 return null;
154 }
155 }
156
157 public class ProxyAndStateAwareJavaReflectionProvider extends PureJavaReflectionProvider {
158 @Override
159 public void visitSerializableFields(Object object, Visitor visitor) {
160 SerializationState state = serializationStates.get();
161 PropertySerializabilityEvaluator evaluator = evaluators.get();
162
163 for (Iterator iterator = fieldDictionary.serializableFieldsFor(object.getClass()); iterator.hasNext();) {
164 Field field = (Field) iterator.next();
165 if (!fieldModifiersSupported(field)) {
166 continue;
167 }
168
169 if (ignoreField(field)) {
170 continue;
171 }
172
173 validateFieldAccess(field);
174
175 initializeField(object, field);
176
177 Object value = null;
178 try {
179 value = field.get(object);
180 } catch (IllegalArgumentException e) {
181 throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
182 } catch (IllegalAccessException e) {
183 throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
184 }
185
186 if (evaluator.isPropertySerializable(state, object, field.getName(), value)) {
187 if (value != null && legacyDataAdapter.isProxied(value)) {
188
189 value = legacyDataAdapter.resolveProxy(value);
190 }
191 PropertyType propertyType = evaluator.determinePropertyType(value);
192 state.addSerializedProperty(field.getName(), propertyType);
193 visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value);
194 state.removeSerializedProperty();
195 }
196 }
197 }
198
199 protected void initializeField(Object object, Field field) {
200 }
201 }
202
203 public class AutoPopulatingListConverter extends CollectionConverter {
204
205 public AutoPopulatingListConverter(Mapper mapper){
206 super(mapper);
207 }
208
209 @Override
210 public boolean canConvert(Class clazz) {
211 return clazz.equals(AutoPopulatingList.class);
212 }
213
214 }
215
216 protected XmlObjectSerializerService getXmlObjectSerializerService() {
217 return this.xmlObjectSerializerService;
218 }
219
220 @Required
221 public void setXmlObjectSerializerService(XmlObjectSerializerService xmlObjectSerializerService) {
222 this.xmlObjectSerializerService = xmlObjectSerializerService;
223 }
224
225 protected SerializationState createNewDocumentSerializationState(Document document) {
226 return new SerializationState();
227 }
228
229 @Required
230 public void setLegacyDataAdapter(LegacyDataAdapter legacyDataAdapter) {
231 this.legacyDataAdapter = legacyDataAdapter;
232 }
233 }
234