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