View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */ 
17  package org.apache.commons.betwixt.strategy;
18  
19  import java.io.Serializable;
20  import java.util.Date;
21  
22  /**
23   * Determines the way that a type (of object) should be bound
24   * by Betwixt.
25   * 
26   * @author <a href='http://commons.apache.org'>Apache Commons Team</a>, <a href='http://www.apache.org'>Apache Software Foundation</a>
27   */
28  public abstract class TypeBindingStrategy {
29      
30      /**
31       * The default Betwixt <code>TypeBindingStrategy</code> implementation.
32       * Since the default implementation has no state, 
33       * a singleton instance can be provided.
34       */
35      public static final TypeBindingStrategy DEFAULT = new Default();
36      
37      /**
38       * Gets the binding type to be used for the given Java type.
39       * @param type <code>Class</code> for which the binding type is to be determined,
40       * not null
41       * @return <code>BindingType</code> enumeration indicating the type of binding,
42       * not null
43       */
44      public abstract BindingType bindingType(Class type);
45      
46  
47      /**
48       * Enumerates the possible general ways that Betwixt can map a Java type to an XML type.
49       * @author <a href='http://commons.apache.org'>Apache Commons Team</a>, <a href='http://www.apache.org'>Apache Software Foundation</a>
50       */
51      public static final class BindingType implements Serializable {
52          
53          private static final int COMPLEX_INDICATOR = 1;
54          private static final int PRIMITIVE_INDICATOR = 2;
55          
56          /**
57           * Indicates that the java type should be bound to a complex xml type.
58           * A complex xml type may have child elements and attributes.
59           * Betwixt determines the mapping for a java bean bound to a complex type.  
60           */
61          public static final BindingType COMPLEX = new BindingType(COMPLEX_INDICATOR);
62          
63          /**
64           * Indicates that the type should be bound as a Java primitive.
65           * Betwixt may bind this to an attribute or a simple xml type.
66           * Which is determined by the configuration for binding primitives.
67           */
68          public static final BindingType PRIMITIVE = new BindingType(PRIMITIVE_INDICATOR);
69          
70          private int type;
71          
72          private BindingType(int type) {
73              this.type = type;
74          }
75          
76          
77          /**
78           * @see java.lang.Object#equals(java.lang.Object)
79           */
80          public boolean equals(Object object) {
81              boolean result = false;
82              if (object instanceof BindingType) {
83                  BindingType bindingType = (BindingType) object;
84                  result = (type == bindingType.type);
85              }
86              return result;
87          }
88          
89          /**
90           * @see java.lang.Object#hashCode()
91           */
92          public int hashCode() {
93              return type;
94          }
95          
96          /**
97           * @see java.lang.Object#toString()
98           */
99          public String toString() {
100             StringBuffer buffer = new StringBuffer();
101             buffer.append("BindingType: ");
102             switch (type) {
103       			case (COMPLEX_INDICATOR):
104       		    		buffer.append("COMPLEX");
105     		    			break;
106             
107             		case (PRIMITIVE_INDICATOR):
108             		    buffer.append("PRIMITIVE");
109             		    break;
110             }
111             
112             return buffer.toString();
113         }
114 }
115     
116     /**
117      * The default <code>TypeBindingStrategy</code> used by Betwixt.
118      * This implementation recognizes all the usual Java primitive wrappers 
119      * (plus a few more that will in most typical use cases be regarded in the same way). 
120      * @author <a href='http://commons.apache.org'>Apache Commons Team</a>, <a href='http://www.apache.org'>Apache Software Foundation</a>
121      */
122     public static final class Default extends TypeBindingStrategy {
123 
124         /**
125          * Class who are simple and whose subclass are also simple
126          */
127         private static final Class[] INHERITED_SIMPLE = {
128                                                         Number.class, 
129                                                         String.class,
130                                                         Date.class,
131                                                         java.sql.Date.class,
132                                                         java.sql.Time.class,
133                                                         java.sql.Timestamp.class,
134                                                         java.math.BigDecimal.class,
135                                                         java.math.BigInteger.class};
136                                                         
137         /**
138          * Classes who are complex and whose subclasses are also complex
139          */
140         private static final Class[] INHERITED_COMPLEX = {
141                 										Throwable.class
142         								};
143 
144         /**
145          * Gets the binding type to be used for the given Java type.
146          * This implementation recognizes all the usual Java primitive wrappers 
147          * (plus a few more that will in most typical use cases be regarded in the same way). 
148          * @param type <code>Class</code> for which the binding type is to be determined,
149          * not null
150          * @return <code>BindingType</code> enumeration indicating the type of binding,
151          * not null
152          */
153         public BindingType bindingType(Class type) {
154             BindingType result =  BindingType.COMPLEX;
155             if (isStandardPrimitive(type)) {
156                 result = BindingType.PRIMITIVE;
157             }
158        
159             return result;
160         }
161         
162         /**
163          * is the given type one of the standard Betwixt primitives?
164          * @param type <code>Class</code>, not null
165          * @return true if the type is one of the standard Betwixt primitives
166          */
167         protected boolean isStandardPrimitive(Class type) {
168             if ( type == null ) {
169                 return false;
170                 
171             } else if ( type.isPrimitive() ) {
172                 return true;
173                 
174             } else if ( type.equals( Object.class ) ) {
175                 return false;
176             }
177             for ( int i=0, size=INHERITED_SIMPLE.length; i<size; i++ ) {
178                 if ( INHERITED_SIMPLE[i].equals( type ) ) {
179                     return true;
180                 }
181             }
182     
183             for ( int i=0, size=INHERITED_COMPLEX.length; i<size; i++ ) {
184                 if ( INHERITED_COMPLEX[i].equals( type ) ) {
185                     return false;
186                 }
187             }
188             
189             for ( int i=0, size=INHERITED_COMPLEX.length; i<size; i++ ) {
190                 if ( INHERITED_COMPLEX[i].isAssignableFrom( type ) ) {
191                     return false;
192                 }
193             }     
194             
195             if (type.getName().startsWith( "java.lang." )) {
196                 return true;
197             }
198             
199             for ( int i=0, size=INHERITED_SIMPLE.length; i<size; i++ ) {
200                 if ( INHERITED_SIMPLE[i].isAssignableFrom( type ) ) {
201                     return true;
202                 }
203             }            
204             return false;
205         }
206     }
207 }