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