1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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://jakarta.apache.org/commons'>Jakarta 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://jakarta.apache.org/commons'>Jakarta 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://jakarta.apache.org/commons'>Jakarta 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 }