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 }