1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.kuali.rice.krad.service.impl;
18
19 import com.thoughtworks.xstream.XStream;
20 import com.thoughtworks.xstream.converters.MarshallingContext;
21 import com.thoughtworks.xstream.converters.UnmarshallingContext;
22 import com.thoughtworks.xstream.converters.collections.CollectionConverter;
23 import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
24 import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
25 import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
26 import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
27 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
28 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
29 import com.thoughtworks.xstream.mapper.Mapper;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl;
33 import org.apache.ojb.broker.core.proxy.SetProxyDefaultImpl;
34 import org.kuali.rice.krad.service.KRADServiceLocator;
35 import org.kuali.rice.krad.service.PersistenceService;
36 import org.kuali.rice.krad.service.XmlObjectSerializerService;
37
38 import java.lang.reflect.Field;
39 import java.util.ArrayList;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.Set;
44
45
46
47
48
49
50
51 public class XmlObjectSerializerServiceImpl implements XmlObjectSerializerService {
52 private static final Log LOG = LogFactory.getLog(XmlObjectSerializerServiceImpl.class);
53
54 private PersistenceService persistenceService;
55
56 private XStream xstream;
57
58 public XmlObjectSerializerServiceImpl() {
59 xstream = new XStream(new ProxyAwareJavaReflectionProvider());
60 xstream.registerConverter(new ProxyConverter(xstream.getMapper(), xstream.getReflectionProvider() ));
61
62
63
64 xstream.registerConverter(new ListProxyDefaultImplConverter(xstream.getMapper()));
65 xstream.registerConverter(new SetProxyDefaultImplConverter(xstream.getMapper()));
66 }
67
68
69
70
71 public String toXml(Object object) {
72 if ( LOG.isDebugEnabled() ) {
73 LOG.debug( "toXml(" + object + ") : \n" + xstream.toXML(object) );
74 }
75 return xstream.toXML(object);
76 }
77
78
79
80
81 public Object fromXml(String xml) {
82 if ( LOG.isDebugEnabled() ) {
83 LOG.debug( "fromXml() : \n" + xml );
84 }
85 if ( xml != null ) {
86 xml = xml.replaceAll( "--EnhancerByCGLIB--[0-9a-f]{0,8}", "" );
87 }
88 return xstream.fromXML(xml);
89 }
90
91
92
93
94
95 public class ProxyConverter extends ReflectionConverter {
96 public ProxyConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
97 super(mapper, reflectionProvider);
98 }
99
100 @Override
101
102
103 @SuppressWarnings("unchecked")
104 public boolean canConvert(Class clazz) {
105 return clazz.getName().contains("CGLIB");
106 }
107
108 @Override
109 public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {
110 super.marshal(getPersistenceService().resolveProxy(obj), writer, context);
111 }
112
113
114 }
115
116 public class ProxyAwareJavaReflectionProvider extends PureJavaReflectionProvider {
117
118 public ProxyAwareJavaReflectionProvider() {
119 super();
120 }
121
122
123
124 @Override
125 public void visitSerializableFields(Object object, Visitor visitor) {
126 for (Iterator iterator = fieldDictionary.fieldsFor(object.getClass()); iterator.hasNext();) {
127 Field field = (Field) iterator.next();
128 if (!fieldModifiersSupported(field)) {
129 continue;
130 }
131 validateFieldAccess(field);
132 Object value = null;
133 try {
134 value = field.get(object);
135 if (value != null && getPersistenceService().isProxied(value)) {
136 value = getPersistenceService().resolveProxy(value);
137 }
138 } catch (IllegalArgumentException e) {
139 throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
140 } catch (IllegalAccessException e) {
141 throw new ObjectAccessException("Could not get field " + field.getClass() + "." + field.getName(), e);
142 }
143 visitor.visit(field.getName(), field.getType(), field.getDeclaringClass(), value);
144 }
145 }
146
147 }
148
149 public PersistenceService getPersistenceService() {
150 if ( persistenceService == null ) {
151 persistenceService = KRADServiceLocator.getPersistenceService();
152 }
153 return persistenceService;
154 }
155
156
157
158
159
160 private static class ListProxyDefaultImplConverter extends CollectionConverter {
161
162 ListProxyDefaultImplConverter(Mapper mapper) {
163 super(mapper);
164 }
165
166 @Override @SuppressWarnings("unchecked")
167 public boolean canConvert(Class type) {
168 return ListProxyDefaultImpl.class.equals(type);
169 }
170
171
172
173
174 @Override @SuppressWarnings("unchecked")
175 public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
176
177
178 ArrayList altered = new ArrayList((List)source);
179
180 super.marshal(altered, writer, context);
181 }
182
183
184
185
186
187
188
189 @Override @SuppressWarnings("unchecked")
190 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
191
192 ArrayList result = null;
193
194 while (reader.hasMoreChildren()) {
195 try {
196 reader.moveDown();
197
198 if (reader.getNodeName().startsWith("_")) {
199
200 } else {
201 if (result == null) { result = new ArrayList(); }
202 addCurrentElementToCollection(reader, context, result, result);
203 }
204 } finally {
205 reader.moveUp();
206 }
207 }
208
209 return result;
210 }
211 }
212
213
214
215
216
217
218 private static class SetProxyDefaultImplConverter extends CollectionConverter {
219
220 SetProxyDefaultImplConverter(Mapper mapper) {
221 super(mapper);
222 }
223
224 @Override @SuppressWarnings("unchecked")
225 public boolean canConvert(Class type) {
226 return SetProxyDefaultImpl.class.equals(type);
227 }
228
229
230
231
232 @Override @SuppressWarnings("unchecked")
233 public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
234
235
236 HashSet altered = new HashSet((Set)source);
237
238 super.marshal(altered, writer, context);
239 }
240
241
242
243
244
245
246
247 @Override @SuppressWarnings("unchecked")
248 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
249
250 HashSet result = null;
251
252 while (reader.hasMoreChildren()) {
253 try {
254 reader.moveDown();
255
256 if (reader.getNodeName().startsWith("_")) {
257
258 } else {
259 if (result == null) { result = new HashSet(); }
260 addCurrentElementToCollection(reader, context, result, result);
261 }
262 } finally {
263 reader.moveUp();
264 }
265 }
266
267 return result;
268 }
269 }
270
271 }