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.apache.ojb.broker.core.proxy.ListProxyDefaultImpl;
30 import org.apache.ojb.broker.core.proxy.ProxyHelper;
31 import org.kuali.rice.krad.document.Document;
32 import org.kuali.rice.krad.service.DocumentSerializerService;
33 import org.kuali.rice.krad.service.PersistenceService;
34 import org.kuali.rice.krad.service.SerializerService;
35 import org.kuali.rice.krad.service.XmlObjectSerializerService;
36 import org.kuali.rice.krad.service.util.DateTimeConverter;
37 import org.kuali.rice.krad.util.documentserializer.AlwaysTruePropertySerializibilityEvaluator;
38 import org.kuali.rice.krad.util.documentserializer.PropertySerializabilityEvaluator;
39 import org.kuali.rice.krad.util.documentserializer.PropertyType;
40 import org.kuali.rice.krad.util.documentserializer.SerializationState;
41 import org.springframework.util.AutoPopulatingList;
42
43 import java.lang.reflect.Field;
44 import java.util.ArrayList;
45 import java.util.Iterator;
46 import java.util.List;
47
48
49
50
51
52
53
54
55
56
57 public abstract class SerializerServiceBase implements SerializerService {
58
59
60 protected PersistenceService persistenceService;
61 protected XmlObjectSerializerService xmlObjectSerializerService;
62
63 protected XStream xstream;
64 protected ThreadLocal<SerializationState> serializationStates;
65 protected ThreadLocal<PropertySerializabilityEvaluator> evaluators;
66
67 public SerializerServiceBase() {
68 serializationStates = new ThreadLocal<SerializationState>();
69 evaluators = new ThreadLocal<PropertySerializabilityEvaluator>();
70
71 xstream = new XStream(new ProxyAndStateAwareJavaReflectionProvider());
72 xstream.registerConverter(new ProxyConverter(xstream.getMapper(), xstream.getReflectionProvider() ));
73 xstream.addDefaultImplementation(ArrayList.class, ListProxyDefaultImpl.class);
74 xstream.addDefaultImplementation(AutoPopulatingList.class, ListProxyDefaultImpl.class);
75 xstream.registerConverter(new AutoPopulatingListConverter(xstream.getMapper()));
76 xstream.registerConverter(new DateTimeConverter());
77 }
78
79 public class ProxyConverter extends ReflectionConverter {
80 public ProxyConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
81 super(mapper, reflectionProvider);
82 }
83 public boolean canConvert(Class clazz) {
84 return clazz.getName().contains("CGLIB") || clazz.getName().equals("org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl");
85 }
86
87 public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {
88 if (obj instanceof ListProxyDefaultImpl) {
89 List copiedList = new ArrayList();
90 List proxiedList = (List) obj;
91 for (Iterator iter = proxiedList.iterator(); iter.hasNext();) {
92 copiedList.add(iter.next());
93 }
94 context.convertAnother( copiedList );
95 }
96 else {
97 super.marshal(getPersistenceService().resolveProxy(obj), writer, context);
98 }
99 }
100
101 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
102 return null;
103 }
104 }
105
106 public class ProxyAndStateAwareJavaReflectionProvider extends PureJavaReflectionProvider {
107 @Override
108 public void visitSerializableFields(Object object, Visitor visitor) {
109 SerializationState state = serializationStates.get();
110 PropertySerializabilityEvaluator evaluator = evaluators.get();
111
112 for (Iterator iterator = fieldDictionary.serializableFieldsFor(object.getClass()); iterator.hasNext();) {
113 Field field = (Field) iterator.next();
114 if (!fieldModifiersSupported(field)) {
115 continue;
116 }
117
118 if (ignoreField(field)) {
119 continue;
120 }
121
122 validateFieldAccess(field);
123
124 initializeField(object, field);
125
126 Object value = null;
127 try {
128 value = field.get(object);
129 } catch (IllegalArgumentException e) {
130 throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
131 } catch (IllegalAccessException e) {
132 throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
133 }
134
135 if (evaluator.isPropertySerializable(state, object, field.getName(), value)) {
136 if (value != null && ProxyHelper.isProxy(value)) {
137
138 value = getPersistenceService().resolveProxy(value);
139 }
140 PropertyType propertyType = evaluator.determinePropertyType(value);
141 state.addSerializedProperty(field.getName(), propertyType);
142 visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value);
143 state.removeSerializedProperty();
144 }
145 }
146 }
147
148 protected boolean ignoreField(Field field) {
149 return false;
150 }
151
152 protected void initializeField(Object object, Field field) {
153 }
154 }
155
156 public PersistenceService getPersistenceService() {
157 return this.persistenceService;
158 }
159
160 public void setPersistenceService(PersistenceService persistenceService) {
161 this.persistenceService = persistenceService;
162 }
163
164 public XmlObjectSerializerService getXmlObjectSerializerService() {
165 return this.xmlObjectSerializerService;
166 }
167
168 public void setXmlObjectSerializerService(XmlObjectSerializerService xmlObjectSerializerService) {
169 this.xmlObjectSerializerService = xmlObjectSerializerService;
170 }
171
172 protected SerializationState createNewDocumentSerializationState(Document document) {
173 return new SerializationState();
174 }
175
176 public class AutoPopulatingListConverter extends CollectionConverter {
177
178 public AutoPopulatingListConverter(Mapper mapper){
179 super(mapper);
180 }
181
182 @Override
183 public boolean canConvert(Class clazz) {
184 return clazz.equals(AutoPopulatingList.class);
185 }
186
187 }
188
189
190 }
191