1 /* 2 * Redistribution and use of this software and associated documentation 3 * ("Software"), with or without modification, are permitted provided 4 * that the following conditions are met: 5 * 6 * 1. Redistributions of source code must retain copyright 7 * statements and notices. Redistributions must also contain a 8 * copy of this document. 9 * 10 * 2. Redistributions in binary form must reproduce the 11 * above copyright notice, this list of conditions and the 12 * following disclaimer in the documentation and/or other 13 * materials provided with the distribution. 14 * 15 * 3. The name "Exolab" must not be used to endorse or promote 16 * products derived from this Software without prior written 17 * permission of Intalio, Inc. For written permission, 18 * please contact info@exolab.org. 19 * 20 * 4. Products derived from this Software may not be called "Exolab" 21 * nor may "Exolab" appear in their names without prior written 22 * permission of Intalio, Inc. Exolab is a registered 23 * trademark of Intalio, Inc. 24 * 25 * 5. Due credit should be given to the Exolab Project 26 * (http://www.exolab.org/). 27 * 28 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 32 * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 39 * OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Copyright 1999 (C) Intalio, Inc. All Rights Reserved. 42 * 43 * Portions of this file developed by Keith Visco after Jan 19 2005 are 44 * Copyright (C) 2005 Keith Visco. All Rights Reserverd. 45 * 46 * $Id$ 47 */ 48 package org.exolab.castor.xml.handlers; 49 50 import java.lang.reflect.Array; 51 import java.lang.reflect.InvocationTargetException; 52 import java.lang.reflect.Method; 53 import java.lang.reflect.Modifier; 54 55 import org.exolab.castor.mapping.FieldHandler; 56 import org.exolab.castor.mapping.ValidityException; 57 58 /** 59 * A specialized FieldHandler for the XML Schema enumeration types. 60 * 61 * @author <a href="keith AT kvisco DOT com">Keith Visco</a> 62 * @version $Revision$ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $ 63 */ 64 public class EnumFieldHandler implements FieldHandler { 65 66 /** Used to find the method "valueOf" taking an argument of type String. */ 67 private static final Class[] STRING_ARGS = new Class[] {String.class}; 68 /** The Factory Method name. */ 69 private static final String METHOD_VALUEOF = "valueOf"; 70 private static final String METHOD_FROMVALUE = "fromValue"; 71 private static final String METHOD_VALUE = "value"; 72 private static final String METHOD_TOSTRING = "toString"; 73 74 /** The <code>valueOf(String)</code> method for the provided enumtype. */ 75 private final Method _valueOf; 76 /** The field handler to which we delegate. */ 77 private final FieldHandler _handler; 78 79 //----------------/ 80 //- Constructors -/ 81 //----------------/ 82 83 /** 84 * Creates a new EnumFieldHandler with the given type and FieldHandler. 85 * 86 * @param enumType the Class type of the described field 87 * @param handler the FieldHandler to delegate to 88 */ 89 public EnumFieldHandler(final Class enumType, final FieldHandler handler) { 90 this._handler = handler; 91 this._valueOf = getUnmarshallMethod(enumType); 92 } //-- EnumFieldHandler 93 94 /** 95 * Reflectively finds the <code>valueOf(String)</code> method for the 96 * provided class type. 97 * 98 * @param type the Class for which to locate the valueOf method. 99 * @return the Method <code>valueOf(String)</code> 100 */ 101 private Method getUnmarshallMethod(final Class type) { 102 if (type == null) { 103 String err = "The Class argument passed to the " 104 + "constructor of EnumMarshalDescriptor cannot be null."; 105 throw new IllegalArgumentException(err); 106 } 107 108 Method method = null; 109 110 // try the fromValue method to support enums with value object 111 try { 112 method = type.getMethod(METHOD_FROMVALUE, STRING_ARGS); 113 return method; 114 } catch(NoSuchMethodException exception) { 115 // do nothing, check valueOf 116 } 117 118 // 119 try { 120 method = type.getMethod(METHOD_VALUEOF, STRING_ARGS); 121 } catch (NoSuchMethodException nsme) { 122 String err = type.getName() 123 + " does not contain one of the required methods public static " 124 + type.getName() + " valueOf(String); " + 125 "or public static " + type.getName() + ".fromvalue(String value)"; 126 throw new IllegalArgumentException(err); 127 } 128 129 if (!Modifier.isStatic(method.getModifiers())) { 130 String err = type.getName() + " public " + type.getName() 131 + " valueOf(String); exists but is not static"; 132 throw new IllegalArgumentException(err); 133 } 134 return method; 135 } 136 137 private Method getMarshallMethod(final Class type) { 138 if (type == null) { 139 String err = "The Class argument passed to the " 140 + "constructor of EnumMarshalDescriptor cannot be null."; 141 throw new IllegalArgumentException(err); 142 } 143 144 Method method = null; 145 146 // try the value() method to support enums with value object 147 try { 148 method = type.getMethod(METHOD_VALUE, null); 149 return method; 150 } catch(NoSuchMethodException exception) { 151 // do nothing, use toString 152 } 153 154 // 155 try { 156 method = type.getMethod(METHOD_TOSTRING, null); 157 } catch (NoSuchMethodException nsme) { 158 String err = type.getName() 159 + " does not contain one of the required methods value() or toString() "; 160 throw new IllegalArgumentException(err); 161 } 162 163 return method; 164 } 165 166 //------------------/ 167 //- Public Methods -/ 168 //------------------/ 169 170 /** 171 * Returns the value of the field associated with this descriptor from the 172 * given target object. 173 * 174 * @param target the object to get the value from 175 * @return the value of the field associated with this descriptor from the 176 * given target object. 177 * @throws IllegalStateException The Java object has changed and is no 178 * longer supported by this handler, or the handler is not 179 * compatible with the Java object 180 */ 181 public Object getValue(final Object target) throws java.lang.IllegalStateException { 182 Object val = _handler.getValue(target); 183 if (val == null) { 184 return val; 185 } 186 187 Object result = null; 188 if (val.getClass().isArray()) { 189 int size = Array.getLength(val); 190 String[] values = new String[size]; 191 192 for (int i = 0; i < size; i++) { 193 Object obj = Array.get(val, i); 194 try { 195 values[i] = (String) getMarshallMethod(obj.getClass()).invoke(obj, null); 196 } catch (Exception e) { 197 throw new IllegalStateException(e.toString()); 198 } 199 } 200 result = values; 201 } else { 202 try { 203 result = getMarshallMethod(val.getClass()).invoke(val, null); 204 } catch (Exception e) { 205 throw new IllegalStateException(e.toString()); 206 } 207 } 208 return result; 209 } //-- getValue 210 211 /** 212 * Sets the value of the field associated with this descriptor. 213 * 214 * @param target the object in which to set the value 215 * @param value the value of the field 216 * @throws IllegalStateException The Java object has changed and is no 217 * longer supported by this handler, or the handler is not 218 * compatible with the Java object. 219 */ 220 public void setValue(final Object target, final Object value) 221 throws java.lang.IllegalStateException { 222 Object obj = null; 223 if (value != null) { 224 Object[] args = new String[1]; 225 args[0] = value.toString(); 226 try { 227 obj = _valueOf.invoke(null, args); 228 } catch (java.lang.reflect.InvocationTargetException ite) { 229 Throwable toss = ite.getTargetException(); 230 throw new IllegalStateException(toss.toString()); 231 } catch (java.lang.IllegalAccessException iae) { 232 throw new IllegalStateException(iae.toString()); 233 } 234 } 235 _handler.setValue(target, obj); 236 } //-- setValue 237 238 /** 239 * Sets the value of the field to a default value -- for enum, no action 240 * needed. 241 * 242 * @param target The object. 243 */ 244 public void resetValue(final Object target) { 245 // No action needed 246 } 247 248 /** 249 * Checks the field validity. Returns successfully if the field can be 250 * stored, is valid, etc, throws an exception otherwise. 251 * 252 * @param object The object 253 * @throws ValidityException The field is invalid, is required and null, or 254 * any other validity violation 255 * @throws IllegalStateException The Java object has changed and is no 256 * longer supported by this handler, or the handler is not 257 * compatiable with the Java object 258 */ 259 public void checkValidity(final Object object) throws ValidityException, IllegalStateException { 260 //-- do nothing for now 261 } //-- checkValidity 262 263 /** 264 * Creates a new instance of the object described by this field. 265 * 266 * @param parent The object for which the field is created 267 * @return A new instance of the field's value 268 * @throws IllegalStateException This field is a simple type and cannot be 269 * instantiated 270 */ 271 public Object newInstance(final Object parent) throws IllegalStateException { 272 return ""; 273 } //-- newInstance 274 275 /** 276 * Returns true if the given object is an XMLFieldHandler that is equivalent 277 * to the delegated handler. An equivalent XMLFieldHandler is an 278 * XMLFieldHandler that is an instances of the same class. 279 * 280 * @return true if the given object is an XMLFieldHandler that is equivalent 281 * to this one. 282 */ 283 public boolean equals(final Object obj) { 284 if (obj == null) { 285 return false; 286 } 287 if (obj == this) { 288 return true; 289 } 290 if (!(obj instanceof FieldHandler)) { 291 return false; 292 } 293 return (_handler.getClass().isInstance(obj) || getClass().isInstance(obj)); 294 } //-- equals 295 296 } //-- EnumFieldHandler