KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > extras > HashMapperStringToComplex


1 /*
2 Copyright (c) 2003-2005, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.extras;
30
31 import java.util.HashMap JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.Map JavaDoc;
34
35 import org.jibx.runtime.IAliasable;
36 import org.jibx.runtime.IMarshallable;
37 import org.jibx.runtime.IMarshaller;
38 import org.jibx.runtime.IMarshallingContext;
39 import org.jibx.runtime.IUnmarshaller;
40 import org.jibx.runtime.IUnmarshallingContext;
41 import org.jibx.runtime.JiBXException;
42 import org.jibx.runtime.impl.MarshallingContext;
43 import org.jibx.runtime.impl.UnmarshallingContext;
44
45 /**
46  * <p>Custom marshaller/unmarshaller for <code>java.util.Map</code>
47  * instances. This handles mapping hash maps with simple keys and complex values
48  * to and from XML. There are a number of limitations, though. First off, the
49  * key objects are marshalled as simple text values, using the
50  * <code>toString()</code> method to convert them to <code>String</code>. When
51  * unmarshalling the keys are always treated as <code>String</code> values. The
52  * corresponding values can be any complex type with a &lt;mapping> defined in
53  * the binding. The name of the top-level element in the XML structure can be
54  * configured in the binding definition, but the rest of the names are
55  * predefined and set in the code (though the namespace configured for the
56  * top-level element will be used with all the names).</p>
57  *
58  * <p>The net effect is that the XML structure will always be of the form:</p>
59  *
60  * <pre>&lt;map-name size="3">
61  * &lt;entry key="38193">
62  * &lt;customer state="WA" zip="98059">
63  * &lt;name first-name="John" last-name="Smith"/>
64  * &lt;street>12345 Happy Lane&lt;/street>
65  * &lt;city>Plunk&lt;/city>
66  * &lt;/customer>
67  * &lt;/entry>
68  * &lt;entry key="39122">
69  * &lt;customer state="WA" zip="98094">
70  * &lt;name first-name="Sally" last-name="Port"/>
71  * &lt;street>932 Easy Street&lt;/street>
72  * &lt;city>Fort Lewis&lt;/city>
73  * &lt;/customer>
74  * &lt;/entry>
75  * &lt;entry key="83132">
76  * &lt;customer state="WA" zip="98059">
77  * &lt;name first-name="Mary" last-name="Smith"/>
78  * &lt;street>12345 Happy Lane&lt;/street>
79  * &lt;city>Plunk&lt;/city>
80  * &lt;/customer>
81  * &lt;/entry>
82  * &lt;/map-name></pre>
83  *
84  * <p>where "map-name" is the configured top-level element name, the "size"
85  * attribute is the number of pairs in the hash map, and the "entry" elements
86  * are the actual entries in the hash map.</p>
87  *
88  * <p>This is obviously not intended to handle all types of hash maps, but it
89  * should be useful as written for many applications and easily customized to
90  * handle other requirements.</p>
91  *
92  * @author Dennis M. Sosnoski
93  * @version 1.0
94  */

95
96 public class HashMapperStringToComplex
97     implements IMarshaller, IUnmarshaller, IAliasable {
98         
99     private static final int DEFAULT_SIZE = 10;
100     
101     private String JavaDoc m_uri;
102     private int m_index;
103     private String JavaDoc m_name;
104     
105     /**
106      * Default constructor. This uses a pre-defined name for the top-level
107      * element. It'll be used by JiBX when no name information is supplied by
108      * the mapping which references this custom marshaller/unmarshaller.
109      */

110     public HashMapperStringToComplex() {
111         m_uri = null;
112         m_index = 0;
113         m_name = "hashmap";
114     }
115     
116     /**
117      * Aliased constructor. This takes a name definition for the top-level
118      * element. It'll be used by JiBX when a name is supplied by the mapping
119      * which references this custom marshaller/unmarshaller.
120      *
121      * @param uri namespace URI for the top-level element (also used for all
122      * other names within the binding)
123      * @param index namespace index corresponding to the defined URI within the
124      * marshalling context definitions
125      * @param name local name for the top-level element
126      */

127     public HashMapperStringToComplex(String JavaDoc uri, int index, String JavaDoc name) {
128         m_uri = uri;
129         m_index = index;
130         m_name = name;
131     }
132     
133     /**
134      * Method which can be overridden to supply a different name for the wrapper
135      * element attribute used to give the number of items present. If present,
136      * this attribute is used when unmarshalling to set the initial size of the
137      * hashmap. It will be generated when marshalling if the supplied name is
138      * non-<code>null</code>.
139      */

140     protected String JavaDoc getSizeAttributeName() {
141         return "size";
142     }
143     
144     /**
145      * Method which can be overridden to supply a different name for the element
146      * used to represent each item in the map.
147      */

148     protected String JavaDoc getEntryElementName() {
149         return "entry";
150     }
151     
152     /**
153      * Method which can be overridden to supply a different name for the
154      * attribute defining the key value for each item in the map.
155      */

156     protected String JavaDoc getKeyAttributeName() {
157         return "key";
158     }
159     
160     /* (non-Javadoc)
161      * @see org.jibx.runtime.IMarshaller#isExtension(int)
162      */

163     public boolean isExtension(int index) {
164         return false;
165     }
166
167     /* (non-Javadoc)
168      * @see org.jibx.runtime.IMarshaller#marshal(java.lang.Object,
169      * org.jibx.runtime.IMarshallingContext)
170      */

171     public void marshal(Object JavaDoc obj, IMarshallingContext ictx)
172         throws JiBXException {
173         
174         // make sure the parameters are as expected
175
if (!(obj instanceof Map JavaDoc)) {
176             throw new JiBXException("Invalid object type for marshaller");
177         } else if (!(ictx instanceof MarshallingContext)) {
178             throw new JiBXException("Invalid object type for marshaller");
179         } else {
180             
181             // start by generating start tag for container
182
MarshallingContext ctx = (MarshallingContext)ictx;
183             Map JavaDoc map = (Map JavaDoc)obj;
184             ctx.startTagAttributes(m_index, m_name).
185                 attribute(m_index, getSizeAttributeName(), map.size()).
186                 closeStartContent();
187             
188             // loop through all entries in map
189
Iterator JavaDoc iter = map.entrySet().iterator();
190             while (iter.hasNext()) {
191                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
192                 ctx.startTagAttributes(m_index, getEntryElementName());
193                 ctx.attribute(m_index, getKeyAttributeName(),
194                     entry.getKey().toString());
195                 ctx.closeStartContent();
196                 if (entry.getValue() instanceof IMarshallable) {
197                     ((IMarshallable)entry.getValue()).marshal(ctx);
198                     ctx.endTag(m_index, getEntryElementName());
199                 } else {
200                     throw new JiBXException("Mapped value is not marshallable");
201                 }
202             }
203             
204             // finish with end tag for container element
205
ctx.endTag(m_index, m_name);
206         }
207     }
208
209     /* (non-Javadoc)
210      * @see org.jibx.runtime.IUnmarshaller#isPresent(org.jibx.runtime.IUnmarshallingContext)
211      */

212     public boolean isPresent(IUnmarshallingContext ctx) throws JiBXException {
213         return ctx.isAt(m_uri, m_name);
214     }
215
216     /* (non-Javadoc)
217      * @see org.jibx.runtime.IUnmarshaller#unmarshal(java.lang.Object,
218      * org.jibx.runtime.IUnmarshallingContext)
219      */

220     public Object JavaDoc unmarshal(Object JavaDoc obj, IUnmarshallingContext ictx)
221         throws JiBXException {
222         
223         // make sure we're at the appropriate start tag
224
UnmarshallingContext ctx = (UnmarshallingContext)ictx;
225         if (!ctx.isAt(m_uri, m_name)) {
226             ctx.throwStartTagNameError(m_uri, m_name);
227         }
228         
229         // create new hashmap if needed
230
int size = ctx.attributeInt(m_uri,
231             getSizeAttributeName(), DEFAULT_SIZE);
232         Map JavaDoc map = (Map JavaDoc)obj;
233         if (map == null) {
234             map = new HashMap JavaDoc(size);
235         }
236         
237         // process all entries present in document
238
ctx.parsePastStartTag(m_uri, m_name);
239         while (ctx.isAt(m_uri, getEntryElementName())) {
240             Object JavaDoc key = ctx.attributeText(m_uri, getKeyAttributeName(), null);
241             ctx.parsePastStartTag(m_uri, getEntryElementName());
242             Object JavaDoc value = ctx.unmarshalElement();
243             map.put(key, value);
244             ctx.parsePastEndTag(m_uri, getEntryElementName());
245         }
246         ctx.parsePastEndTag(m_uri, m_name);
247         return map;
248     }
249 }
Popular Tags