1   /* ====================================================================
2    * Bigyo Software License, version 1.1
3    * 
4    * Copyright (c) 2004, Zsombor Gegesy. All rights reserved.
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions 
7    * are met:
8    *
9    * 1. Redistributions of source code must retain the above copyright 
10   *    notice, this list of conditions and the following disclaimer.
11   *
12   * 2. Redistributions in binary form must reproduce the above copyright 
13   *    notice, this list of conditions and the following disclaimer in 
14   *    the documentation and/or other materials provided with the 
15   *    distribution.
16   *
17   * 3. Neither the name of the Bigyo Group nor the name "Bigyo" nor
18   *    the names of its contributors may be used to endorse or promote
19   *    products derived from this software without specific prior
20   *    written permission.
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
23   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26   * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
27   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
28   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
31   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32   * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33   * POSSIBILITY OF SUCH DAMAGE.
34   *
35   * ====================================================================
36   */
37  
38  package net.sf.bigyo.container;
39  
40  import java.util.ArrayList;
41  import java.util.Iterator;
42  import java.util.List;
43  
44  import com.thoughtworks.xstream.XStream;
45  import com.thoughtworks.xstream.alias.ClassMapper;
46  import com.thoughtworks.xstream.converters.Converter;
47  import com.thoughtworks.xstream.converters.ConverterLookup;
48  import com.thoughtworks.xstream.converters.ErrorWriter;
49  import com.thoughtworks.xstream.converters.MarshallingContext;
50  import com.thoughtworks.xstream.converters.UnmarshallingContext;
51  import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
52  import com.thoughtworks.xstream.core.JVM;
53  import com.thoughtworks.xstream.io.HierarchicalStreamReader;
54  import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
55  
56  /***
57   * Creates a more 'compact' xml, instead of the verbose default. Usage: XStream
58   * xs = .... xs.registerConverter(new CompactReflectionConverter(xs));
59   * 
60   * Created on 2004.04.17.
61   * @author zombi@mailbox.hu
62   * 
63   *  
64   */
65  public class CompactReflectionConverter implements Converter {
66  
67      private ClassMapper classMapper;
68      private String classAttributeIdentifier;
69      ReflectionProvider reflectionProvider;
70      ConverterLookup lookup;
71      private String definedInAttributeIdentifier = "defined-in";
72      private boolean accept = true;
73  
74      public CompactReflectionConverter(ClassMapper classMapper, String classAttributeIdentifier,
75              ReflectionProvider reflectionProvider, ConverterLookup lookup) {
76          this.classMapper = classMapper;
77          this.classAttributeIdentifier = classAttributeIdentifier;
78          this.reflectionProvider = reflectionProvider;
79          this.lookup = lookup;
80      }
81  
82      /***
83       * @param xstream
84       */
85      public CompactReflectionConverter(XStream xstream) {
86          this(xstream.getClassMapper(), "class-name", new JVM().bestReflectionProvider(), xstream.getConverterLookup());
87      }
88  
89      /*
90       * (non-Javadoc)
91       * 
92       * @see com.thoughtworks.xstream.converters.reflection.ReflectionConverter#canConvert(java.lang.Class)
93       */
94      public boolean canConvert(Class cls) {
95          if (accept) {
96              if (!cls.isPrimitive() && !cls.isArray() && !cls.isInterface()) {
97                  return !cls.getName().startsWith("java.");
98              }
99          }
100         return false;
101     }
102 
103     public void setAccept(boolean b) {
104         this.accept = b;
105     }
106 
107 
108     static class Record {
109         String fieldName;
110         Class fieldType;
111         Object newObj;
112 
113         /***
114          * @param fieldName
115          * @param fieldType
116          * @param newObj
117          */
118         public Record(String fieldName, Class fieldType, Object newObj) {
119             super();
120             this.fieldName = fieldName;
121             this.fieldType = fieldType;
122             this.newObj = newObj;
123         }
124     }
125 
126     public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
127         final List complexFields = new ArrayList();
128         reflectionProvider.visitSerializableFields(source, new ReflectionProvider.Visitor() {
129 
130             public void visit(String fieldName, Class fieldType, Class definedIn, Object value) {
131 
132                 /*
133                  * Object newObj = reflectionProvider.readField(source,
134                  * fieldName); if (newObj != null) { Class actualType =
135                  * newObj.getClass(); if
136                  * (actualType.getName().startsWith("java.lang.")) {
137                  * writer.addAttribute(fieldName, newObj.toString()); } else {
138                  * complexFields.add(new Record(fieldName, fieldType, newObj));
139                  *  } }
140                  */
141 
142                 if (value != null) {
143                     Class actualType = value.getClass();
144                     if (actualType.getName().startsWith("java.lang.")) {
145                         writer.addAttribute(fieldName, value.toString());
146                     } else {
147                         complexFields.add(new Record(fieldName, fieldType, value));
148                     }
149                 }
150             }
151         });
152         for (Iterator iter = complexFields.iterator(); iter.hasNext();) {
153             Record r = (Record) iter.next();
154             writer.startNode(classMapper.mapNameToXML(r.fieldName));
155             Class defaultType = classMapper.lookupDefaultType(r.fieldType);
156             Class actualType = r.newObj.getClass();
157             if (!actualType.equals(defaultType)) {
158                 writer.addAttribute(classAttributeIdentifier, classMapper.lookupName(actualType));
159             }
160 
161             context.convertAnother(r.newObj);
162 
163             writer.endNode();
164 
165         }
166 
167     }
168 
169     public Object unmarshal(final HierarchicalStreamReader reader, UnmarshallingContext context) {
170         // copy from ReflectionProvider
171         Object result = context.currentObject();
172 
173         if (result == null) {
174             result = reflectionProvider.newInstance(context.getRequiredType());
175         }
176         // de-serialize simple fields
177 
178         final Object finalResult = result;
179         reflectionProvider.visitSerializableFields(result, new ReflectionProvider.Visitor() {
180 
181             /*
182              * (non-Javadoc)
183              * 
184              * @see com.thoughtworks.xstream.converters.reflection.ReflectionProvider.Visitor#visit(java.lang.String,
185              *      java.lang.Class, java.lang.Class, java.lang.Object)
186              */
187             public void visit(String fieldName, Class fieldType, Class definedIn, Object value) {
188                 if (fieldType.getName().startsWith("java.lang.") || fieldType.isPrimitive()) {
189                     Converter converter = lookup.lookupConverterForType(fieldType);
190                     final String fieldAttr = reader.getAttribute(fieldName);
191                     if (fieldAttr != null) {
192 
193                         Object fieldValue = converter.unmarshal(new HierarchicalStreamReader() {
194                             /*
195                              * (non-Javadoc)
196                              * 
197                              * @see com.thoughtworks.xstream.io.HierarchicalStreamReader#getValue()
198                              */
199                             public String getValue() {
200                                 return fieldAttr;
201                             }
202 
203                             public boolean hasMoreChildren() {
204                                 return false;
205                             }
206 
207                             public void moveDown() {
208 
209                             }
210 
211                             public void moveUp() {
212 
213                             }
214 
215                             public String getNodeName() {
216                                 return null;
217                             }
218 
219                             public String getAttribute(String arg0) {
220                                 return null;
221                             }
222 
223                             public Object peekUnderlyingNode() {
224                                 return null;
225                             }
226 
227                             public void appendErrors(ErrorWriter errorWriter) {
228                                 // TODO Auto-generated method stub
229 
230                             }
231                         }, null);
232                         reflectionProvider.writeField(finalResult, fieldName, fieldValue, definedIn);
233                         //writeField(finalResult, fieldName, fieldValue);
234                     }
235                 }
236             }
237         });
238 
239         // copy from ReflectionProvider
240 
241         while (reader.hasMoreChildren()) {
242             reader.moveDown();
243 
244             String fieldName = classMapper.mapNameFromXML(reader.getNodeName());
245 
246             String definedIn = reader.getAttribute(definedInAttributeIdentifier);
247             Class definedInCls = definedIn == null ? null : classMapper.lookupType(definedIn);
248 
249             Class type;
250             String classAttribute = reader.getAttribute(classAttributeIdentifier);
251             if (classAttribute == null) {
252                 type = classMapper.lookupDefaultType(reflectionProvider.getFieldType(result, fieldName, definedInCls));
253             } else {
254                 type = classMapper.lookupType(classAttribute);
255             }
256 
257             Object fieldValue = context.convertAnother(result, type);
258 
259             reflectionProvider.writeField(result, fieldName, fieldValue, definedInCls);
260 
261             reader.moveUp();
262         }
263 
264         return result;
265     }
266 }
This page was automatically generated by Maven