View Javadoc

1   package org.codehaus.xfire.java.type;
2   
3   import java.beans.BeanInfo;
4   import java.beans.IntrospectionException;
5   import java.beans.Introspector;
6   import java.beans.PropertyDescriptor;
7   import java.lang.reflect.InvocationTargetException;
8   
9   import org.codehaus.xfire.SOAPConstants;
10  import org.codehaus.xfire.XFireRuntimeException;
11  import org.codehaus.xfire.java.message.MessageReader;
12  import org.codehaus.xfire.java.message.MessageWriter;
13  import org.codehaus.xfire.util.NamespaceHelper;
14  import org.dom4j.Element;
15  import org.dom4j.Namespace;
16  
17  /***
18   * Serializes JavaBeans.
19   * 
20   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
21   */
22  public class BeanType
23      extends Type
24  {
25      public Object readObject(MessageReader reader)
26          throws XFireRuntimeException
27      {
28          try
29          {
30              Class clazz = getTypeClass();
31              Object object = clazz.newInstance();
32              
33              BeanInfo info = Introspector.getBeanInfo( clazz, Object.class );
34              
35              PropertyDescriptor[] pds = info.getPropertyDescriptors();
36              
37              while( reader.hasMoreChildReaders() )
38              {
39                  MessageReader childReader = reader.getNextChildReader();
40                  String name = childReader.getLocalName();
41                  
42                  PropertyDescriptor pd = findPropertyDescriptor( name, pds );
43                  
44                  if ( pd == null )
45                      throw new XFireRuntimeException( "Couldn't find property for " + name );
46                      
47                  Type type = getTypeMapping().getType( pd.getPropertyType() );
48  
49                  if ( type == null )
50                      throw new XFireRuntimeException( "Couldn't find type for " 
51                              + pd.getPropertyType() + " for property " + name );
52  
53                  Object writeObj = type.readObject( childReader );
54                  
55                  pd.getWriteMethod().invoke( object , new Object[] { writeObj } );
56              }
57              
58              return object;
59          }
60          catch (IntrospectionException e)
61          {
62              throw new XFireRuntimeException("Couldn't introspect.", e);
63          }
64          catch (IllegalArgumentException e)
65          {
66              throw new XFireRuntimeException("Illegal argument.", e);
67          } 
68          catch (IllegalAccessException e)
69          {
70              throw new XFireRuntimeException("Illegal access.", e);
71          }
72          catch (InvocationTargetException e)
73          {
74              throw new XFireRuntimeException("Couldn't invoke.", e);
75          }
76  		catch (InstantiationException e)
77  		{
78              throw new XFireRuntimeException("Couldn't instantiate.", e);
79  		}
80      }
81  
82      protected PropertyDescriptor findPropertyDescriptor(String name, PropertyDescriptor[] pd)
83      {
84          for ( int i = 0; i < pd.length; i++ )
85          {
86              if ( pd[i].getName().equals(name) )
87                  return pd[i];
88          }
89          return null;
90      }
91  
92      /***
93       * @see org.codehaus.xfire.java.type.Type#writeObject(java.lang.Object)
94       */
95      public void writeObject(Object object, MessageWriter writer)
96          throws XFireRuntimeException
97      {
98          try
99          {
100         	// TODO: could be an exception as well.
101             BeanInfo info = Introspector.getBeanInfo( getTypeClass(), Object.class );
102             
103             PropertyDescriptor[] pd = info.getPropertyDescriptors();
104             
105             for ( int i = 0; i < pd.length; i++ )
106             {
107                 Class typeClass = pd[i].getPropertyType();
108                 Type type = getTypeMapping().getType( typeClass );
109 
110                 if ( type == null )
111                     throw new XFireRuntimeException( "Couldn't find type for " + typeClass + " for property " + pd[i].getName() );
112 
113                 MessageWriter cwriter = writer.getChildWriter( pd[i].getName() );
114                 type.writeObject( pd[i].getReadMethod().invoke( object , new Object[0] ),
115                                   cwriter );
116                 cwriter.close();
117             }
118         }
119         catch (IntrospectionException e)
120         {
121             throw new XFireRuntimeException("Couldn't introspect.", e);
122         }
123         catch (IllegalArgumentException e)
124         {
125             throw new XFireRuntimeException("Illegal argument.", e);
126         } 
127         catch (IllegalAccessException e)
128         {
129             throw new XFireRuntimeException("Illegal access.", e);
130         }
131         catch (InvocationTargetException e)
132         {
133             // TODO: remember ITEs can go funny sometimes...
134             throw new XFireRuntimeException("Couldn't invoke.", e);
135         }
136     }
137 
138     /***
139      * @see org.codehaus.xfire.java.type.Type#writeSchema()
140      */
141     public void writeSchema( Element root )
142     {
143         try
144         {
145             // TODO: this bean could be an exception as well.
146             BeanInfo info = Introspector.getBeanInfo( getTypeClass(), Object.class );
147             
148             Namespace xsdNs = root.getNamespaceForURI( SOAPConstants.XSD );
149             org.dom4j.QName complexQ = new org.dom4j.QName("complexType", xsdNs); 
150             
151             Element complex = root.addElement( complexQ );
152             
153             complex.addAttribute( "name", this.getSchemaType().getName() );
154 
155             org.dom4j.QName seqQ = new org.dom4j.QName("sequence", xsdNs); 
156             Element seq = complex.addElement( seqQ );
157             
158             PropertyDescriptor[] pd = info.getPropertyDescriptors();
159             
160             org.dom4j.QName elementQ = new org.dom4j.QName("element", xsdNs); 
161             
162             for ( int i = 0; i < pd.length; i++ )
163             {
164                 Class typeClass = pd[i].getPropertyType();
165                 
166                 Element element = seq.addElement( elementQ );
167                 
168                 Type type = getTypeMapping().getType( typeClass );
169                 
170                 Namespace typeNS = NamespaceHelper.getNamespace( root, type.getSchemaType().getNamespaceURI() );
171                 
172                 element.addAttribute( "name", pd[i].getDisplayName() );
173                 // TODO: Add config support for nillable
174                 element.addAttribute( "nillable", "true" );
175                 element.addAttribute("type", typeNS.getPrefix() + ":" + type.getSchemaType().getName());
176             }
177         }
178         catch (IntrospectionException e)
179         {
180             throw new XFireRuntimeException("Couldn't introspect.", e);
181         }
182         catch (IllegalArgumentException e)
183         {
184             throw new XFireRuntimeException("Illegal argument.", e);
185         } 
186     }
187     
188     /***
189      * We need to write a complex type schema for Beans, so return true.
190      * 
191      * @see org.codehaus.xfire.java.type.Type#isComplex()
192      */
193     public boolean isComplex()
194     {
195         return true;
196     }
197 }