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 }