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 }