summaryrefslogtreecommitdiff
path: root/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutableObject.java
diff options
context:
space:
mode:
authorBenjamin Culkin <scorpress@gmail.com>2024-05-27 11:38:33 -0400
committerBenjamin Culkin <scorpress@gmail.com>2024-05-27 11:38:33 -0400
commit7c279747beb43c7e88633a6228a155a30e6834f7 (patch)
tree511176048944fa7332dc1a163a6148c46e7c61b3 /israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutableObject.java
Initial import
Diffstat (limited to 'israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutableObject.java')
-rw-r--r--israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutableObject.java197
1 files changed, 197 insertions, 0 deletions
diff --git a/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutableObject.java b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutableObject.java
new file mode 100644
index 0000000..63b301d
--- /dev/null
+++ b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutableObject.java
@@ -0,0 +1,197 @@
+/*
+ * 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 <a href="mailto:cgruber@israfil.net">Christian Edward Gruber </a>
+ *
+ */
+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;
+ }
+}