1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shindig.social.core.util.xstream;
19
20 import com.google.inject.Injector;
21
22 import com.thoughtworks.xstream.converters.ConversionException;
23 import com.thoughtworks.xstream.converters.Converter;
24 import com.thoughtworks.xstream.converters.MarshallingContext;
25 import com.thoughtworks.xstream.converters.UnmarshallingContext;
26 import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
27 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
28 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
29 import com.thoughtworks.xstream.mapper.Mapper;
30
31 import org.apache.shindig.social.opensocial.model.Exportablebean;
32
33 import java.util.Collection;
34 import java.util.Iterator;
35
36 /***
37 *
38 */
39 public class GuiceBeanConverter implements Converter {
40 private Mapper mapper;
41 private GuiceBeanProvider beanProvider;
42
43 public GuiceBeanConverter(Mapper mapper, Injector injector) {
44 this(mapper, new GuiceBeanProvider(injector));
45 }
46
47 public GuiceBeanConverter(Mapper mapper, GuiceBeanProvider beanProvider) {
48 this.mapper = mapper;
49 this.beanProvider = beanProvider;
50 }
51
52 /***
53 * Only checks for the availability of a public default constructor. If you
54 * need stricter checks, subclass JavaBeanConverter
55 */
56 public boolean canConvert(Class type) {
57 if ( type == null ) {
58 return false;
59 }
60 if (Object.class.equals(type)) {
61 return false;
62 }
63 if ( type.isInterface() ) {
64 return true;
65 }
66 for (Class<?> iff : type.getInterfaces()) {
67 if (iff.isAnnotationPresent(Exportablebean.class)) {
68 return true;
69 }
70 }
71 return canConvert(type.getSuperclass());
72 }
73
74 public void marshal(final Object source,
75 final HierarchicalStreamWriter writer, final MarshallingContext context) {
76 beanProvider.visitSerializableProperties(source,
77 new GuiceBeanProvider.Visitor() {
78 public boolean shouldVisit(String name, Class<?> definedIn) {
79 return mapper.shouldSerializeMember(definedIn, name);
80 }
81
82 public void visit(String propertyName, Class<?> fieldType,
83 Class<?> definedIn, Object newObj) {
84 if (newObj != null) {
85 Mapper.ImplicitCollectionMapping mapping = mapper
86 .getImplicitCollectionDefForFieldName(source.getClass(),
87 propertyName);
88 if (mapping != null) {
89 if (mapping.getItemFieldName() != null) {
90 Collection<?> list = (Collection<?>) newObj;
91 for (Iterator<?> iter = list.iterator(); iter.hasNext();) {
92 Object obj = iter.next();
93 writeField(propertyName, mapping.getItemFieldName(),
94 mapping.getItemType(), definedIn, obj);
95 }
96 } else {
97 context.convertAnother(newObj);
98 }
99 } else {
100 writeField(propertyName, propertyName, fieldType, definedIn,
101 newObj);
102 }
103 }
104 }
105
106 private void writeField(String propertyName, String aliasName,
107 Class<?> fieldType, Class<?> definedIn, Object newObj) {
108 ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper
109 .serializedMember(source.getClass(), aliasName), fieldType);
110 context.convertAnother(newObj);
111 writer.endNode();
112
113 }
114 });
115 }
116
117 public Object unmarshal(final HierarchicalStreamReader reader,
118 final UnmarshallingContext context) {
119 final Object result = instantiateNewInstance(context);
120
121 while (reader.hasMoreChildren()) {
122 reader.moveDown();
123
124 String propertyName = mapper.realMember(result.getClass(), reader
125 .getNodeName());
126
127 boolean propertyExistsInClass = beanProvider.propertyDefinedInClass(
128 propertyName, result.getClass());
129
130 if (propertyExistsInClass) {
131 Class<?> type = determineType(reader, result, propertyName);
132 Object value = context.convertAnother(result, type);
133 beanProvider.writeProperty(result, propertyName, value);
134 } else if (mapper.shouldSerializeMember(result.getClass(), propertyName)) {
135 throw new ConversionException("Property '" + propertyName
136 + "' not defined in class " + result.getClass().getName());
137 }
138
139 reader.moveUp();
140 }
141
142 return result;
143 }
144
145 private Object instantiateNewInstance(UnmarshallingContext context) {
146 Object result = context.currentObject();
147 if (result == null) {
148 result = beanProvider.newInstance(context.getRequiredType());
149 }
150 return result;
151 }
152
153 private Class<?> determineType(HierarchicalStreamReader reader,
154 Object result, String fieldName) {
155 final String classAttributeName = mapper.attributeForAlias("class");
156 String classAttribute = reader.getAttribute(classAttributeName);
157 if (classAttribute != null) {
158 return mapper.realClass(classAttribute);
159 } else {
160 return mapper.defaultImplementationOf(beanProvider.getPropertyType(
161 result, fieldName));
162 }
163 }
164
165 /***
166 * @deprecated since 1.3
167 */
168 public static class DuplicateFieldException extends ConversionException {
169 public DuplicateFieldException(String msg) {
170 super(msg);
171 }
172 }
173
174 }