/* * Copyright © 2003-2009 Israfil Consulting Services Corporation * Copyright © 2003-2009 Christian Edward Gruber * All Rights Reserved * * This software is licensed under the Berkeley Standard Distribution license, * (BSD license), as defined below: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of Israfil Consulting Services nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * $Id: DynamicallyMutableObject.java 127 2006-11-09 18:04:43Z cgruber $ */ package net.israfil.foundation.dynamic; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.logging.Level; import java.util.logging.Logger; import net.israfil.foundation.core.Strings; import net.israfil.foundation.core.Types; /** * An abstract class which implements the DynamicallyMutableObject * infrastructure. It sets a field's value, by mutator method if such * exists, or directly if none such exists. * * @author Christian Edward Gruber * */ public abstract class DynamicallyMutableObject extends DynamicallyAccessibleObject implements DynamicallyMutable { private static Logger logger = Logger.getLogger(DynamicallyMutableObject.class.getName()); public void setNull(String attributeName, Class valueType) { setNull(this,attributeName,valueType); } public void setNull(Object target, String attributeName, Class valueType) { if (valueType == null) throw new IllegalArgumentException("Cannot give a valueType of null for setNull(String,Class) method."); set(target,attributeName, null, valueType); } public void set(String attributeName,Object value) { set(this,attributeName,value); } public static void set(Object target, String attributeName,Object value) { if (value == null) set(target,attributeName, value, null); else set(target,attributeName, value, value.getClass()); } public void set(String attributeName, Object value, Class valueType) { set(this,attributeName,value,valueType); } public static void set(Object target, String attributeName, Object value, Class valueType) { if (value == null) { if (valueType != null && valueType.isPrimitive()) throw new IllegalArgumentException("Attempted to set null on a variable or accessor for attribute '"+attributeName+"' of primitive type: " + valueType); String selector = getMutatorSelector(target,attributeName,valueType); if (selector != null) { Method m = DynamicUtil.getMethodForSelector(target,selector); Class[] parmTypes = m.getParameterTypes(); if (parmTypes[0].isPrimitive()) throw new IllegalArgumentException("Attempted to set null using an accessor for attribute '"+attributeName+"' of primitive type: " + parmTypes[0]); DynamicUtil.performOn(target,selector,new Object[]{value}); } else { Field f = DynamicUtil.getField(target,attributeName); if (f == null || f.getType().isPrimitive()) throw new IllegalArgumentException("Attempted to set null but could not find a set"+Strings.camel(attributeName)+" method with a single non-primitive type."); else _setField(target,attributeName,valueType); } } else /* value != null */ { if (valueType == null) valueType = value.getClass(); if (hasMutator(target,attributeName,valueType)) { DynamicUtil.performOn(target,getMutatorSelector(target,attributeName,valueType),new Object[]{value}); return; } else if(hasMutator(target,attributeName,DynamicUtil.getPrimitiveTypeEquivalent(valueType))) { DynamicUtil.performOn(target,getMutatorSelector(target,attributeName,DynamicUtil.getPrimitiveTypeEquivalent(valueType)),new Object[]{value}); return; } else { _setField(target,attributeName,value); } } } protected void _setField(String attributeName,Object value) { _setField(this,attributeName,value); } protected static void _setField(Object target, String attributeName,Object value) { Field f = DynamicUtil.getField(target,attributeName); try { if (f == null) { RuntimeException rte = new RuntimeException("Could not find field named " + attributeName, new NoSuchFieldException(target + " has no property " + attributeName)); logger.log(Level.FINEST,"Failed to set field.",rte); throw rte; } f.set(target,Types.convert(value,f.getType())); } catch (IllegalAccessException e) { logger.log(Level.FINEST,"Object attempted to dynamically access a inaccessible field.",e); throw new RuntimeException(e); } } protected static final String mutatePrefix = "set"; protected String getMutatorSelector(String attributeName, Class type) { return getMutatorSelector(this,attributeName,type); } protected static String getMutatorSelector(Object target, String attributeName, Class type) { if (attributeName == null || attributeName.equals("")) return null; String camelAttr = Strings.camel(attributeName); String selector = null; if (type == null) { Method method = _tryToFindMutator(target,attributeName); if (method == null) { return null; } else /* method != null */ { if (method.getParameterTypes().length != 1) return null; else return "set"+Strings.camel(attributeName)+":"+method.getParameterTypes()[0].getName(); } } else /* type != null */ { String tmp = mutatePrefix+camelAttr+":"+type.getName(); if (DynamicUtil.respondsTo(target,tmp)) selector = tmp; for (Class c : DynamicUtil.getAllParentTypes(type)) { tmp = mutatePrefix + camelAttr + ":" + c.getName(); if (DynamicUtil.respondsTo(target, tmp)) selector = tmp; } } return selector; } protected static Method _tryToFindMutator(Object target, String attributeName) { Method method = null; Method[] methods = target.getClass().getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals("set"+Strings.camel(attributeName))) { if (method == null) method = methods[i]; else throw new IllegalArgumentException("Attempted to find "+mutatePrefix+Strings.camel(attributeName) + " without a given type, but more than one such method exists. Should use set(String,Object,Class)"); } } return method; } protected static Method _tryToFindMutator(Object target, String attributeName, Class type) { if (type == null) throw new IllegalArgumentException("Must set a type, or use _tryToFindMutator(Object,String)."); String methodName = mutatePrefix+Strings.camel(attributeName); Method m = DynamicUtil.getMethodForSelector(target,methodName+":"+type.getName()); for (Class c : DynamicUtil.getAllParentTypes(type)) { m = DynamicUtil.getMethodForSelector(target,methodName+":"+c.getName()); } return m; } public static Method getMutator(Object target, String attributeName, Class type) { if (type == null) { return _tryToFindMutator(target,attributeName); } else { return _tryToFindMutator(target,attributeName,type); } } public boolean hasMutator(String attributeName, Class type) { return hasMutator(this,attributeName,type); } public static boolean hasMutator(Object target, String attributeName, Class type) { return getMutatorSelector(target,attributeName,type) != null; } }