| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| Factory |
|
| 2.5;2.5 |
| 1 | /* | |
| 2 | * Factory.java July 2006 | |
| 3 | * | |
| 4 | * Copyright (C) 2006, Niall Gallagher <niallg@users.sf.net> | |
| 5 | * | |
| 6 | * This library is free software; you can redistribute it and/or | |
| 7 | * modify it under the terms of the GNU Lesser General Public | |
| 8 | * License as published by the Free Software Foundation. | |
| 9 | * | |
| 10 | * This library is distributed in the hope that it will be useful, | |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | * GNU Lesser General Public License for more details. | |
| 14 | * | |
| 15 | * You should have received a copy of the GNU Lesser General | |
| 16 | * Public License along with this library; if not, write to the | |
| 17 | * Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |
| 18 | * Boston, MA 02111-1307 USA | |
| 19 | */ | |
| 20 | ||
| 21 | package org.simpleframework.xml.load; | |
| 22 | ||
| 23 | import org.simpleframework.xml.transform.Transformer; | |
| 24 | import org.simpleframework.xml.stream.InputNode; | |
| 25 | import org.simpleframework.xml.stream.OutputNode; | |
| 26 | import java.lang.reflect.Modifier; | |
| 27 | import java.beans.Introspector; | |
| 28 | ||
| 29 | /** | |
| 30 | * The <code>Factory</code> object provides a base class for factories | |
| 31 | * used to produce field values from XML elements. The goal of this | |
| 32 | * type of factory is to make use of the <code>Strategy</code> object | |
| 33 | * to determine the type of the field value. The strategy class must be | |
| 34 | * assignable to the field class type, that is, it must extend it or | |
| 35 | * implement it if it represents an interface. If the strategy returns | |
| 36 | * a null <code>Type</code> then the subclass implementation determines | |
| 37 | * the type used to populate the object field value. | |
| 38 | * | |
| 39 | * @author Niall Gallagher | |
| 40 | */ | |
| 41 | abstract class Factory { | |
| 42 | ||
| 43 | /** | |
| 44 | * Caches the constructors used to transform primitive types. | |
| 45 | * | |
| 46 | * @see org.simpleframework.xml.load.Primitive | |
| 47 | */ | |
| 48 | protected static Transformer transform; | |
| 49 | ||
| 50 | static { | |
| 51 | 54 | transform = new Transformer(); |
| 52 | 54 | } |
| 53 | ||
| 54 | /** | |
| 55 | * This is the source object used for the serialization process. | |
| 56 | */ | |
| 57 | protected Source source; | |
| 58 | ||
| 59 | /** | |
| 60 | * This is the field type that the class must be assignable to. | |
| 61 | */ | |
| 62 | protected Class field; | |
| 63 | ||
| 64 | /** | |
| 65 | * Constructor for the <code>Factory</code> object. This is given | |
| 66 | * the class type for the field that this factory will determine | |
| 67 | * the actual type for. The actual type must be assignable to the | |
| 68 | * field type to insure that any instance can be set. | |
| 69 | * | |
| 70 | * @param source the contextual object used by the persister | |
| 71 | * @param field this is the field type to determine the value of | |
| 72 | */ | |
| 73 | 1333167 | protected Factory(Source source, Class field) { |
| 74 | 1333167 | this.source = source; |
| 75 | 1333167 | this.field = field; |
| 76 | 1333167 | } |
| 77 | ||
| 78 | /** | |
| 79 | * This is used to get a possible override from the provided node. | |
| 80 | * If the node provided is an element then this checks for a | |
| 81 | * specific class override using the <code>Strategy</code> object. | |
| 82 | * If the strategy cannot resolve a class then this will return | |
| 83 | * null. If the resolved <code>Type</code> is not assignable to | |
| 84 | * the field then this will thrown an exception. | |
| 85 | * | |
| 86 | * @param node this is the node used to search for the override | |
| 87 | * | |
| 88 | * @return this returns null if no override type can be found | |
| 89 | * | |
| 90 | * @throws Exception if the override type is not compatible | |
| 91 | */ | |
| 92 | public Type getOverride(InputNode node) throws Exception { | |
| 93 | 766301 | Type type = getConversion(node); |
| 94 | ||
| 95 | 766300 | if(type != null) { |
| 96 | 43590 | Class real = type.getType(); |
| 97 | ||
| 98 | 43590 | if(!isCompatible(field, real)) { |
| 99 | 3 | throw new InstantiationException("Type %s is not compatible with %s", real, field); |
| 100 | } | |
| 101 | } | |
| 102 | 766297 | return type; |
| 103 | } | |
| 104 | ||
| 105 | /** | |
| 106 | * This method is used to set the override class within an element. | |
| 107 | * This delegates to the <code>Strategy</code> implementation, which | |
| 108 | * depending on the implementation may add an attribute of a child | |
| 109 | * element to describe the type of the object provided to this. | |
| 110 | * | |
| 111 | * @param field this is the class of the field type being serialized | |
| 112 | * @param node the XML element that is to be given the details | |
| 113 | * | |
| 114 | * @throws Exception thrown if an error occurs within the strategy | |
| 115 | */ | |
| 116 | public boolean setOverride(Class field, Object value, OutputNode node) throws Exception { | |
| 117 | 197337 | if(!field.isPrimitive()) { |
| 118 | 197240 | return source.setOverride(field, value, node); |
| 119 | } | |
| 120 | 97 | return false; |
| 121 | } | |
| 122 | ||
| 123 | /** | |
| 124 | * This performs the conversion from the element node to a type. This | |
| 125 | * is where the <code>Strategy</code> object is consulted and asked | |
| 126 | * for a class that will represent the provided XML element. This will, | |
| 127 | * depending on the strategy implementation, make use of attributes | |
| 128 | * and/or elements to determine the type for the field. | |
| 129 | * | |
| 130 | * @param node this is the element used to extract the override | |
| 131 | * | |
| 132 | * @return this returns null if no override type can be found | |
| 133 | * | |
| 134 | * @throws Exception thrown if the override class cannot be loaded | |
| 135 | */ | |
| 136 | public Type getConversion(InputNode node) throws Exception { | |
| 137 | 766301 | return source.getOverride(field, node); |
| 138 | } | |
| 139 | ||
| 140 | /** | |
| 141 | * This creates a <code>Scanner</code> object that can be used to | |
| 142 | * examine the fields within the XML class schema. The scanner | |
| 143 | * maintains information when a field from within the scanner is | |
| 144 | * visited, this allows the serialization and deserialization | |
| 145 | * process to determine if all required XML annotations are used. | |
| 146 | * | |
| 147 | * @param type the schema class the scanner is created for | |
| 148 | * | |
| 149 | * @return a scanner that can maintains information on the type | |
| 150 | * | |
| 151 | * @throws Exception if the class contains an illegal schema | |
| 152 | */ | |
| 153 | private static Scanner getScanner(Class type) throws Exception { | |
| 154 | 200012 | return ScannerFactory.getInstance(type); |
| 155 | } | |
| 156 | ||
| 157 | /** | |
| 158 | * This is used to acquire the name of the specified type using | |
| 159 | * the <code>Root</code> annotation for the class. This will | |
| 160 | * use either the name explicitly provided by the annotation or | |
| 161 | * it will use the name of the class that the annotation was | |
| 162 | * placed on if there is no explicit name for the root. | |
| 163 | * | |
| 164 | * @param type this is the type to acquire the root name for | |
| 165 | * | |
| 166 | * @return this returns the name of the type from the root | |
| 167 | * | |
| 168 | * @throws Exception if the class contains an illegal schema | |
| 169 | */ | |
| 170 | public static String getName(Class type) throws Exception { | |
| 171 | 200012 | Scanner schema = getScanner(type); |
| 172 | 200012 | String name = schema.getName(); |
| 173 | ||
| 174 | 200012 | if(name != null) { |
| 175 | 199781 | return name; |
| 176 | } | |
| 177 | 231 | return getClassName(type); |
| 178 | } | |
| 179 | ||
| 180 | /** | |
| 181 | * This returns the name of the class specified. If there is a root | |
| 182 | * annotation on the type, then this is ignored in favour of the | |
| 183 | * actual class name. This is typically used when the type is a | |
| 184 | * primitive or if there is no <code>Root</code> annotation present. | |
| 185 | * | |
| 186 | * @param type this is the type to acquire the root name for | |
| 187 | * | |
| 188 | * @return this returns the name of the type from the root | |
| 189 | */ | |
| 190 | public static String getClassName(Class type) throws Exception { | |
| 191 | 231 | if(type.isArray()) { |
| 192 | 0 | type = type.getComponentType(); |
| 193 | } | |
| 194 | 231 | String name = type.getSimpleName(); |
| 195 | ||
| 196 | 231 | if(type.isPrimitive()) { |
| 197 | 0 | return name; |
| 198 | } | |
| 199 | 231 | return Introspector.decapitalize(name); |
| 200 | } | |
| 201 | ||
| 202 | /** | |
| 203 | * This is used to determine whether the scanned class represents | |
| 204 | * a primitive type. A primitive type is a type that contains no | |
| 205 | * XML annotations and so cannot be serialized with an XML form. | |
| 206 | * Instead primitives a serialized using transformations. | |
| 207 | * | |
| 208 | * @param type this is the type to determine if it is primitive | |
| 209 | * | |
| 210 | * @return this returns true if no XML annotations were found | |
| 211 | */ | |
| 212 | public static boolean isPrimitive(Class type) throws Exception { | |
| 213 | 1078369 | if(type.isEnum()) { |
| 214 | 98 | return true; |
| 215 | } | |
| 216 | 1078271 | return transform.valid(type); |
| 217 | } | |
| 218 | ||
| 219 | /** | |
| 220 | * This is used to determine whether the provided base class can be | |
| 221 | * assigned from the issued type. For an override to be compatible | |
| 222 | * with the field type an instance of the override type must be | |
| 223 | * assignable to the field value. | |
| 224 | * | |
| 225 | * @param field this is the field value present the the object | |
| 226 | * @param type this is the specialized type that will be assigned | |
| 227 | * | |
| 228 | * @return true if the field type can be assigned the type value | |
| 229 | */ | |
| 230 | public static boolean isCompatible(Class field, Class type) { | |
| 231 | 43590 | if(field.isArray()) { |
| 232 | 124 | field = field.getComponentType(); |
| 233 | } | |
| 234 | 43590 | return field.isAssignableFrom(type); |
| 235 | } | |
| 236 | ||
| 237 | /** | |
| 238 | * This is used to determine whether the type given is instantiable, | |
| 239 | * that is, this determines if an instance of that type can be | |
| 240 | * created. If the type is an interface or an abstract class then | |
| 241 | * this will return false. | |
| 242 | * | |
| 243 | * @param type this is the type to check the modifiers of | |
| 244 | * | |
| 245 | * @return false if the type is an interface or an abstract class | |
| 246 | */ | |
| 247 | public static boolean isInstantiable(Class type) { | |
| 248 | 332539 | int modifiers = type.getModifiers(); |
| 249 | ||
| 250 | 332539 | if(Modifier.isAbstract(modifiers)) { |
| 251 | 56 | return false; |
| 252 | } | |
| 253 | 332483 | return !Modifier.isInterface(modifiers); |
| 254 | } | |
| 255 | } |