001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.betwixt.strategy;
018
019 import java.io.Serializable;
020 import java.util.Date;
021
022 /**
023 * Determines the way that a type (of object) should be bound
024 * by Betwixt.
025 *
026 * @author <a href='http://commons.apache.org'>Apache Commons Team</a>, <a href='http://www.apache.org'>Apache Software Foundation</a>
027 */
028 public abstract class TypeBindingStrategy {
029
030 /**
031 * The default Betwixt <code>TypeBindingStrategy</code> implementation.
032 * Since the default implementation has no state,
033 * a singleton instance can be provided.
034 */
035 public static final TypeBindingStrategy DEFAULT = new Default();
036
037 /**
038 * Gets the binding type to be used for the given Java type.
039 * @param type <code>Class</code> for which the binding type is to be determined,
040 * not null
041 * @return <code>BindingType</code> enumeration indicating the type of binding,
042 * not null
043 */
044 public abstract BindingType bindingType(Class type);
045
046
047 /**
048 * Enumerates the possible general ways that Betwixt can map a Java type to an XML type.
049 * @author <a href='http://commons.apache.org'>Apache Commons Team</a>, <a href='http://www.apache.org'>Apache Software Foundation</a>
050 */
051 public static final class BindingType implements Serializable {
052
053 private static final int COMPLEX_INDICATOR = 1;
054 private static final int PRIMITIVE_INDICATOR = 2;
055
056 /**
057 * Indicates that the java type should be bound to a complex xml type.
058 * A complex xml type may have child elements and attributes.
059 * Betwixt determines the mapping for a java bean bound to a complex type.
060 */
061 public static final BindingType COMPLEX = new BindingType(COMPLEX_INDICATOR);
062
063 /**
064 * Indicates that the type should be bound as a Java primitive.
065 * Betwixt may bind this to an attribute or a simple xml type.
066 * Which is determined by the configuration for binding primitives.
067 */
068 public static final BindingType PRIMITIVE = new BindingType(PRIMITIVE_INDICATOR);
069
070 private int type;
071
072 private BindingType(int type) {
073 this.type = type;
074 }
075
076
077 /**
078 * @see java.lang.Object#equals(java.lang.Object)
079 */
080 public boolean equals(Object object) {
081 boolean result = false;
082 if (object instanceof BindingType) {
083 BindingType bindingType = (BindingType) object;
084 result = (type == bindingType.type);
085 }
086 return result;
087 }
088
089 /**
090 * @see java.lang.Object#hashCode()
091 */
092 public int hashCode() {
093 return type;
094 }
095
096 /**
097 * @see java.lang.Object#toString()
098 */
099 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 }