From 7c279747beb43c7e88633a6228a155a30e6834f7 Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Mon, 27 May 2024 11:38:33 -0400 Subject: Initial import --- .../net/israfil/foundation/dynamic/Dynamic.java | 62 +++++ .../israfil/foundation/dynamic/DynamicObject.java | 69 +++++ .../israfil/foundation/dynamic/DynamicUtil.java | 297 +++++++++++++++++++++ .../foundation/dynamic/DynamicallyAccessible.java | 50 ++++ .../dynamic/DynamicallyAccessibleObject.java | 144 ++++++++++ .../foundation/dynamic/DynamicallyMutable.java | 54 ++++ .../dynamic/DynamicallyMutableObject.java | 197 ++++++++++++++ .../foundation/dynamic/DynamicObjectTest.java | 120 +++++++++ .../foundation/dynamic/DynamicUtilTest.java | 160 +++++++++++ .../dynamic/DynamicallyAccessibleTest.java | 174 ++++++++++++ .../foundation/dynamic/DynamicallyMutableTest.java | 210 +++++++++++++++ 11 files changed, 1537 insertions(+) create mode 100644 israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/Dynamic.java create mode 100644 israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicObject.java create mode 100644 israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicUtil.java create mode 100644 israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyAccessible.java create mode 100644 israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyAccessibleObject.java create mode 100644 israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutable.java create mode 100644 israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutableObject.java create mode 100644 israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicObjectTest.java create mode 100644 israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicUtilTest.java create mode 100644 israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicallyAccessibleTest.java create mode 100644 israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicallyMutableTest.java (limited to 'israfil-foundation-dynamic/src') diff --git a/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/Dynamic.java b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/Dynamic.java new file mode 100644 index 0000000..e1bdb8b --- /dev/null +++ b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/Dynamic.java @@ -0,0 +1,62 @@ +/* + * 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: Dynamic.java 14 2006-01-27 23:50:37Z cgruber $ + */ +package net.israfil.foundation.dynamic; + + +/** + * A simple interface that defines the ability to perform and detect + * arbitrary methods, by use of a "selector" string. The selector + * is a string constructed of a method name and an arbitrary number of + * classes representing parameter types. These are then concatenated + * with a ":" separator. The resulting string represents a full + * method signature, without reference to the implementing class. This + * allows arbitrary classes to be interrogated as to the validity of a + * given method call (i.e. do they or their parents implement it). It + * also then allows the method with the given signature to be invoked. + * + * For example: + * + * if (a.respondsTo("doThing:java.lang.String")) + * a.perform("doThing:java.lang.String",aString); + * + * + * @author Christian Edward Gruber + */ +public interface Dynamic { + + public Object perform(String selector, Object ... parameters); + + public boolean respondsTo(String selector); + +} diff --git a/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicObject.java b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicObject.java new file mode 100644 index 0000000..3beda20 --- /dev/null +++ b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicObject.java @@ -0,0 +1,69 @@ +/* + * 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: DynamicObject.java 92 2006-08-04 12:39:25Z cgruber $ + */ +package net.israfil.foundation.dynamic; + +import java.lang.reflect.Method; + + +/** + * An abstract superclass that implements the Dynamic interface, with + * all the necessary lookup logic. It also implements static equivalents of + * the Dynamic methods. + * + * @author Christian Edward Gruber + */ +public abstract class DynamicObject implements Dynamic { + //private static Logger logger = Logger.getLogger(DynamicObject.class.getName()); + + + /** + * @see org.israfil.maveric.Dynamic#perform(java.lang.String, java.lang.Object[]) + */ + public Object perform(String selector, Object ... parameters) { + return DynamicUtil.performOn(this,selector,parameters); + } + + /** + * @see org.israfil.maveric.Dynamic#respondsTo(java.lang.String) + */ + public boolean respondsTo(String selector) { + return DynamicUtil.respondsTo(this,selector); + } + + protected Method getMethodForSelector(String selector) { + return DynamicUtil.getMethodForSelector(this,selector); + } + + +} diff --git a/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicUtil.java b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicUtil.java new file mode 100644 index 0000000..9c165bc --- /dev/null +++ b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicUtil.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2003-2009 Israfil Consulting Services Corporation + * Copyright (c) 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: DynamicUtil.java 91 2006-08-03 21:38:24Z cgruber $ + */ +package net.israfil.foundation.dynamic; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.israfil.foundation.collections.ArrayUtils; + +/** + * Utilities used for the implementation of Dynamic and + * related interfaces. + * + * @author Christian Edward Gruber + */ +public final class DynamicUtil { + private static Logger logger = Logger.getLogger(DynamicUtil.class.getName()); + + private DynamicUtil() {} + + static Map> _primitiveTypes = new HashMap>(); + static Map, Class> _primitiveTypeEquivalents = new HashMap, Class>(); + static Map, Class> _boxedTypeEquivalents = new HashMap, Class>(); + static { + _primitiveTypes.put("boolean",boolean.class); + _primitiveTypeEquivalents.put(Boolean.class,boolean.class); + _boxedTypeEquivalents.put(boolean.class,Boolean.class); + _primitiveTypes.put("int",int.class); + _primitiveTypeEquivalents.put(Integer.class,int.class); + _boxedTypeEquivalents.put(int.class,Integer.class); + _primitiveTypes.put("long",long.class); + _primitiveTypeEquivalents.put(Long.class,long.class); + _boxedTypeEquivalents.put(long.class,Long.class); + _primitiveTypes.put("short",short.class); + _primitiveTypeEquivalents.put(Short.class,short.class); + _boxedTypeEquivalents.put(short.class,Short.class); + _primitiveTypes.put("byte",byte.class); + _primitiveTypeEquivalents.put(Byte.class,byte.class); + _boxedTypeEquivalents.put(byte.class,Byte.class); + _primitiveTypes.put("char",char.class); + _primitiveTypeEquivalents.put(Character.class,char.class); + _boxedTypeEquivalents.put(char.class,Character.class); + _primitiveTypes.put("double",double.class); + _primitiveTypeEquivalents.put(Double.class,double.class); + _boxedTypeEquivalents.put(double.class,Double.class); + _primitiveTypes.put("float",float.class); + _primitiveTypeEquivalents.put(Float.class,float.class); + _boxedTypeEquivalents.put(float.class,Float.class); + } + public static boolean hasPrimitiveTypeEquivalent(Class c) { + return _primitiveTypeEquivalents.containsKey(c); + } + + public static Class getPrimitiveTypeEquivalent(Class c) { + return _primitiveTypeEquivalents.get(c); + } + + public static boolean hasBoxedTypeEquivalent(Class c) { + return _boxedTypeEquivalents.containsKey(c); + } + + public static Class getBoxedTypeEquivalent(Class c) { + return _boxedTypeEquivalents.get(c); + } + + protected static final Map, Set>> classes = new HashMap, Set>>(); + + public static Set> getAllParentTypes(Class c) { + if (!classes.containsKey(c)) { + Set> parents = new HashSet>(); + for (Class cType = c; cType != Object.class && cType != null; cType = cType + .getSuperclass()) { + parents.add(cType); + addSuperInterfaces(parents,cType); + } + parents.add(Object.class); + parents.remove(c); + classes.put(c,parents); + } + return classes.get(c); + } + + public static void addSuperInterfaces(Set> set, Class c) { + if (c == null || c.getInterfaces() == null) return; + for (Class i : c.getInterfaces()) { + set.add(i); + addSuperInterfaces(set,i); + } + } + + /** + * Conveniently get a field from an object, automatically trapping + * exceptions and returning the Field or null if no such field exists. + */ + public static Field getField(Object receiver, String attributeName) { + Field f = null; + try { + f = receiver.getClass().getField(attributeName); + } catch (NoSuchFieldException e) { + return null; + } + return f; + } + + + + /** + * @see org.israfil.maveric.Dynamic#respondsTo(java.lang.String) + */ + public static boolean respondsTo(Object receiver, String selector) { + return (getMethodForSelector(receiver,selector) != null); + } + + public static Method getMethodForSelector(Object receiver, String selector) { + if (receiver instanceof Class) + return getMethodForSelector((Class) receiver, selector); + return getMethodForSelector(receiver.getClass(),selector); + } + + public static Method getMethodForSelector(Class receiverClass, + String selector) { + try { + return _getMethodForSelector(receiverClass,selector); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + return null; + } + } + + protected static Method _getMethodForSelector(Class receiverClass, + String selector) throws ClassNotFoundException, + NoSuchMethodException { + StringTokenizer st = new StringTokenizer(selector,":"); + Class[] paramTypes = new Class[st.countTokens() - 1]; + String methodName = st.nextToken(); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + for (int i = 0; st.hasMoreTokens(); i++) { + String className = st.nextToken(); + if (DynamicUtil._primitiveTypes.containsKey(className)) + paramTypes[i] = (Class) DynamicUtil._primitiveTypes + .get(className); + else paramTypes[i] = loader.loadClass(className); + } + return receiverClass.getMethod(methodName,paramTypes); + } + + /** + * @see org.israfil.maveric.Dynamic#perform(java.lang.String, java.lang.Object[]) + */ + public static Object performOn(Object receiver, String selector, Object ... parameters) { + if (parameters == null) parameters = new Object[]{}; + Method m = getMethodForSelector(receiver,selector); + try { + if (m != null) return m.invoke(receiver,parameters); + //else return null; + else throw new NoSuchMethodError("No public method defined with selector \""+selector+"\""); + } catch (InvocationTargetException ite) { + logger.log(Level.FINE,ite.getClass().getName()+" thrown attempting to invoke selector: " + selector + " on "+receiver,ite); + if (ite.getCause() != null) throw new RuntimeException(ite.getCause()); + else throw new RuntimeException(ite); + } catch (IllegalAccessException iae) { + logger.log(Level.FINE,iae.getClass().getName()+" thrown attempting to invoke selector: " + selector + " on "+receiver,iae); + throw new RuntimeException(iae); + } + } + + /** + * Construct an object of the given named class with the provided + * constructor parameters. If there is no such class or no + * constructor is found that is appropriate to these parameters, + * the method will return null; + * + * @param className The fully qualified name of a Class object to be instantiated. + * @param parameters Optional parameters for the discovered constructor + * @return an instance of the named class, or null if no such class or constructor is found. + */ + public static Object construct(String className, Object ... parameters) { + try { + Class clazz = Thread.currentThread().getContextClassLoader() + .loadClass(className); + return construct(clazz,parameters); + } catch (ClassNotFoundException e) { + logger.log(Level.FINE,e.getClass().getName()+" thrown attempting to construct a " + className + ".", e); + return null; + } + } + /** + * Construct an object of the given class with the provided + * constructor parameters. If there is no such class or no + * constructor is found that is appropriate to these parameters, + * the method will return null; + * + * @param c A Class object to be instantiated. + * @param parameters Optional parameters for the discovered constructor + * @return an instance of the named class, or null if no such class or constructor is found. + */ + public static T construct(Class c, Object ... parameters) { + Class [] parmTypes = new Class[parameters.length]; + for (int i = 0; i < parmTypes.length; i++) { + parmTypes[i] = parameters[i].getClass(); + } + return construct(c,parmTypes,parameters); + } + + /** + * Construct an object of the given named class with the provided + * constructor parameter types and values. If there is no such class + * or no constructor is found that is appropriate to these parameters, + * the method will return null; + * + * @param className The fully qualified name of a Class object to be instantiated. + * @param parameterTypes The types that form the desired constructor's method signature + * @param parameters Optional parameters for the discovered constructor + * @return an instance of the named class, or null if no such class or constructor is found. + */ + public static Object construct(String className, Class[] parameterTypes, + Object... parameters) { + try { + Class clazz = Thread.currentThread().getContextClassLoader() + .loadClass(className); + return construct(clazz, parameterTypes,parameters); + } catch (ClassNotFoundException e) { + logger.log(Level.FINE,e.getClass().getName()+" thrown attempting to construct a " + className + ".", e); + return null; + } + } + + /** + * Construct an object of the given class with the provided + * constructor parameter types and values. If there is no such class + * or no constructor is found that is appropriate to these parameters, + * the method will return null; + * + * @param c A Class object to be instantiated. + * @param parameterTypes The types that form the desired constructor's method signature + * @param parameters Optional parameters for the discovered constructor + * @return an instance of the named class, or null if no such class or constructor is found. + */ + @SuppressWarnings("unchecked") + public static T construct(Class c, Class[] parameterTypes, + Object... parameters) { + try { + Constructor[] constructors = (Constructor[]) c.getDeclaredConstructors(); + for (Constructor constructor : constructors) { + if (ArrayUtils.equivalent(parameterTypes,constructor.getParameterTypes())) { + return (T)constructor.newInstance(parameters); + } + } + return null; + } catch (Exception e) { + logger.log(Level.FINE,e.getClass().getName()+" thrown attempting to construct a " + c.getName() + ".", e); + return null; + } + } + +} diff --git a/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyAccessible.java b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyAccessible.java new file mode 100644 index 0000000..202bd11 --- /dev/null +++ b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyAccessible.java @@ -0,0 +1,50 @@ +/* + * 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: DynamicallyAccessible.java 23 2006-02-01 17:17:31Z cgruber $ + */ +package net.israfil.foundation.dynamic; + + +/** + * A generic accessor interface. By this means any attribute should be + * retrievable by using the provided methods, as well as the existence of + * an accessor method can be detected. + * + * @author Christian Edward Gruber + */ +public interface DynamicallyAccessible extends Dynamic{ + + public boolean hasAttribute(String attributeName); + public Object get(String attributeName); + public abstract boolean hasAccessor(String attributeName); + +} \ No newline at end of file diff --git a/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyAccessibleObject.java b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyAccessibleObject.java new file mode 100644 index 0000000..fd376a7 --- /dev/null +++ b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyAccessibleObject.java @@ -0,0 +1,144 @@ +/* + * 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: DynamicallyAccessibleObject.java 76 2006-08-03 15:37:05Z cgruber $ + */ +package net.israfil.foundation.dynamic; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.israfil.foundation.core.Strings; + +/** + * An implementation of the DynamicallyAccessible interface with the + * appropriate infrastructure for retrieving field data, via accessors if + * such are implemented, or directly from the field where not. + * + * @author Christian Edward Gruber + * @author Latest: $Author: cgruber $ + * @version $Revision: 76 $ + */ +public abstract class DynamicallyAccessibleObject extends DynamicObject implements DynamicallyAccessible { + private static Logger logger = Logger.getLogger(DynamicallyAccessibleObject.class.getName()); + + public Object get(String attributeName) { + return get(this,attributeName); + } + + public static Object get(Object receiver, String attributeName) { + try { + return _get(receiver, attributeName); + } catch (NoSuchFieldException e) { + logger.log(Level.FINE,"Object attempted to dynamically access a non-existant or unreadable field.",e); + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + logger.log(Level.FINE,"Object attempted to dynamically access a inaccessible field.",e); + throw new RuntimeException(e); + } + } + + /** @deprecated This method is deprecated in favour of the static _get(receiver, attributeName) */ + Object _get(String attributeName) throws NoSuchFieldException, IllegalAccessException { + return _get(this,attributeName); + } + + /** + * Internal _get method that throws all the exceptions, to be wrapped by public methods + * so that the various exceptions can be given meaning in different contexts (such + * as fetching data, vs. testing for the existance of something. + * + * @param attributeName + * @return + * @throws NoSuchFieldException + * @throws IllegalAccessException + */ + static Object _get(Object receiver, String attributeName) throws NoSuchFieldException, IllegalAccessException { + if (hasAccessor(receiver,attributeName)) return DynamicUtil.performOn(receiver,_getAccessorSelector(receiver,attributeName), new Object[]{}); + return receiver.getClass().getField(attributeName).get(receiver); + } + + /** + * Determines whether an attribute of the given name exists on this object's + * definition, or if not, if there is a javabeans-style accessor named + * appropriately for that attribute. Put another way, determines whether + * a get() call would work against this attribute name. + * + * The existing implementation is inefficient, but simple to maintain. + */ + public boolean hasAttribute(String attributeName) { + return hasAttribute(this,attributeName); + } + + public static boolean hasAttribute(Object receiver, String attributeName) { + try { + _get(receiver,attributeName); + return true; + } catch (NoSuchFieldException e) { + logger.log(Level.FINEST,"Object attempted to dynamically access a non-existant or unreadable field.",e); + return false; + } catch (IllegalAccessException e) { + logger.log(Level.FINEST,"Object attempted to dynamically access a inaccessible field.",e); + return false; + } + } + + protected static final String[] accessPrefixes = new String[] { "get","is" }; + + /** @deprecated This method is deprecated in favour of the static _getAccessorSelector(receiver,attribute) */ + protected String getAccessorSelector(String attributeName) { return _getAccessorSelector(this,attributeName); } + + protected static String _getAccessorSelector(Object receiver, String attributeName) { + if (attributeName == null || attributeName.equals("")) return null; + String camelAttr = camel(attributeName); + for (String prefix : accessPrefixes) { + String selector = prefix+camelAttr; + if (DynamicUtil.respondsTo(receiver,selector)) return selector; + } + // No accessor, try a NeXTSTEP-style accessor, named the same as the property. + if (DynamicUtil.respondsTo(receiver,attributeName)) return attributeName; + return null; + } + + public boolean hasAccessor(String attributeName) { + return hasAccessor(this,attributeName); + } + + public static boolean hasAccessor(Object receiver, String attributeName) { + return _getAccessorSelector(receiver,attributeName) != null; + } + + /** @deprecated This method has been moved to net.israfil.foundation.core.Strings.camel(String) */ + public static String camel(String string) { + return Strings.camel(string); + } + +} diff --git a/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutable.java b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutable.java new file mode 100644 index 0000000..49b2a5d --- /dev/null +++ b/israfil-foundation-dynamic/src/main/java/net/israfil/foundation/dynamic/DynamicallyMutable.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2003-2009 Israfil Consulting Services Corporation + * Copyright (c) 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: DynamicallyMutable.java 39 2006-02-23 00:01:17Z cgruber $ + */ +package net.israfil.foundation.dynamic; + + +/** + * A generic mutator interface. By this means any attribute should be + * mutable by using the provided methods. Additionally, the existence of + * a mutator method can be detected. + * + * @author Christian Edward Gruber + */ +public interface DynamicallyMutable extends DynamicallyAccessible{ + + public void set(String attributeName, Object attributeValue); + + public void set(String attributeName, Object attributeValue, Class type); + + public void setNull(String attributeName, Class type); + + public abstract boolean hasMutator(String attributeName, Class type); + +} \ No newline at end of file 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 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; + } +} diff --git a/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicObjectTest.java b/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicObjectTest.java new file mode 100644 index 0000000..a5b7a90 --- /dev/null +++ b/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicObjectTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2003-2009 Israfil Consulting Services Corporation + * Copyright (c) 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: DynamicObjectTest.java 130 2006-12-31 23:22:17Z cgruber $ + */ + +package net.israfil.foundation.dynamic; + +import java.lang.reflect.Method; +import java.util.Date; + +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + + +@Test +public class DynamicObjectTest { + + private static final String TEST_STRING1 = "String1"; + private static final String TEST_STRING2 = "String2"; + + DynamicTestObject testDO; + + @BeforeMethod + protected void setUp() throws Exception { + testDO = new DynamicTestObject(); + } + + @AfterMethod + protected void tearDown() throws Exception { + testDO = null; + } + + public void testPerformMethods() { + Assert.assertTrue((Boolean)testDO.perform("action")); + Assert.assertEquals(TEST_STRING1,testDO.perform("action:java.lang.String",TEST_STRING1)); + Assert.assertEquals(TEST_STRING2,testDO.perform("action:java.lang.String:boolean", + new Object[] {TEST_STRING2,Boolean.TRUE})); + Assert.assertEquals(TEST_STRING2+TEST_STRING2,testDO.perform("action:java.lang.String:boolean",new Object[] {TEST_STRING2,Boolean.FALSE})); + Assert.assertNull(testDO.perform("action:java.util.Date",new Object[] {new Date()})); + } + + @Test(expectedExceptions={NoSuchMethodError.class}) + public void testPerformAgainstProtectedMethod() { + testDO.perform("action:boolean",new Object[] {Boolean.TRUE}); + } + + @Test(expectedExceptions={NoSuchMethodError.class}) + public void testPerformAgainstPackageFriendlyMethod() { + testDO.perform("action:java.lang.Float",new Object[] {1.5f}); + } + + @Test(expectedExceptions={NoSuchMethodError.class}) + public void testPerformAgainstPrivateMethod() { + testDO.perform("privateAction"); + } + + public void testRespondsTo() { + Assert.assertTrue(testDO.respondsTo("action")); + Assert.assertFalse(testDO.respondsTo("noAction")); + Assert.assertTrue(testDO.respondsTo("action:java.lang.String")); + Assert.assertFalse(testDO.respondsTo("action:java.lang.Integer")); + Assert.assertTrue(testDO.respondsTo("action:java.lang.String:"+boolean.class.getName())); + Assert.assertFalse(testDO.respondsTo("action:java.lang.Integer:java.lang.String")); + Assert.assertFalse(testDO.respondsTo("action:boolean")); + Assert.assertFalse(testDO.respondsTo("action:java.lang.Float")); + Assert.assertTrue(testDO.respondsTo("action:int")); + } + + public void testGetMethodForSelector() { + Method m = testDO.getMethodForSelector("action:java.lang.String"); + Assert.assertNotNull(m); + Assert.assertEquals("action",m.getName()); + Assert.assertEquals(String.class,m.getParameterTypes()[0]); + } + + public class DynamicTestObject extends DynamicObject { + public boolean action() { return !privateAction(); /* false */ } + public String action(String foo) { return foo; } + public String action(String foo, boolean bool) { + if (bool) return foo; + else return foo+foo; + } + public void action(Date foo) { if (foo==null);return; } + protected boolean action(boolean b) { return b; } + Float action(Float f) { return f; } + public int action(int i) { return i; } + private boolean privateAction() { return false; } + } +} diff --git a/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicUtilTest.java b/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicUtilTest.java new file mode 100644 index 0000000..31d11a7 --- /dev/null +++ b/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicUtilTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2003-2009 Israfil Consulting Services Corporation + * Copyright (c) 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: DynamicUtilTest.java 130 2006-12-31 23:22:17Z cgruber $ + */ +package net.israfil.foundation.dynamic; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * + * @author Christian Edward Gruber + * @author Latest: $Author: cgruber $ + * @version $Revision: 130 $ + */ +@Test +public class DynamicUtilTest { + + public void testAddSuperinterfaces1() { + Class clz = IA.class; + Set> cSet = new HashSet>(); + DynamicUtil.addSuperInterfaces(cSet,clz); + Assert.assertEquals(0,cSet.size()); + } + public void testAddSuperinterfaces2() { + Class clz = IC.class; + Set> cSet = new HashSet>(); + DynamicUtil.addSuperInterfaces(cSet,clz); + Assert.assertTrue(cSet.contains(IA.class),"Should have type IA"); + Assert.assertEquals(1,cSet.size()); + } + public void testClassLookupForA() { + Class clz = A.class; + Set> cSet = DynamicUtil.getAllParentTypes(clz); + Assert.assertTrue(cSet.contains(IA.class),"Should have type IA"); + Assert.assertTrue(cSet.contains(Object.class),"Should have type Object"); + Assert.assertEquals(2,cSet.size()); + } + public void testClassLookupForB() { + Class clz = B.class; + Set> cSet = DynamicUtil.getAllParentTypes(clz); + Assert.assertTrue(cSet.contains(IA.class),"Should have type IA"); + Assert.assertTrue(cSet.contains(A.class),"Should have type A"); + Assert.assertTrue(cSet.contains(IB.class),"Should have type IB"); + Assert.assertTrue(cSet.contains(Object.class),"Should have type Object"); + Assert.assertEquals(4,cSet.size()); + } + public void testClassLookupForC() { + Class clz = C.class; + Set> cSet = DynamicUtil.getAllParentTypes(clz); + Assert.assertTrue(cSet.contains(IA.class),"Should have type IA"); + Assert.assertTrue(cSet.contains(IC.class),"Should have type IC"); + Assert.assertTrue(cSet.contains(Object.class),"Should have type Object"); + Assert.assertFalse(cSet.contains(A.class),"Should not have type A"); + Assert.assertEquals(3,cSet.size()); + } + + public void testRespondsTo() { + Object obj = new TestObject(); + Assert.assertTrue(DynamicUtil.respondsTo(obj,"action:java.lang.String")); + Assert.assertFalse(DynamicUtil.respondsTo(obj,"action")); + Assert.assertFalse(DynamicUtil.respondsTo(obj,"action:boolean")); + Assert.assertTrue(DynamicUtil.respondsTo(obj,"equals:java.lang.Object")); + } + + public void testHasPrimitiveTypeEquivalent() { + Assert.assertTrue(DynamicUtil.hasPrimitiveTypeEquivalent(Boolean.class)); + Assert.assertTrue(DynamicUtil.hasPrimitiveTypeEquivalent(Integer.class)); + Assert.assertTrue(DynamicUtil.hasPrimitiveTypeEquivalent(Long.class)); + Assert.assertTrue(DynamicUtil.hasPrimitiveTypeEquivalent(Short.class)); + Assert.assertTrue(DynamicUtil.hasPrimitiveTypeEquivalent(Byte.class)); + Assert.assertTrue(DynamicUtil.hasPrimitiveTypeEquivalent(Double.class)); + Assert.assertTrue(DynamicUtil.hasPrimitiveTypeEquivalent(Character.class)); + Assert.assertFalse(DynamicUtil.hasPrimitiveTypeEquivalent(String.class)); + } + + public void testGetMethodForSelectorObjectString() { + Method m = null; + Object obj = new TestObject(); + + m = DynamicUtil.getMethodForSelector(obj,"action:java.lang.String"); + Assert.assertNotNull(m); + + m = DynamicUtil.getMethodForSelector(obj,"action:boolean"); + Assert.assertNull(m); + + // force a test of getMethodForSelector(Object,String) with a class + m = DynamicUtil.getMethodForSelector((Object)obj.getClass(),"action:java.lang.String"); + // force a test of getMethodForSelector(Class,String) + m = DynamicUtil.getMethodForSelector((Class) obj.getClass(), + "action:java.lang.String"); + Assert.assertNotNull(m); + + } + + @SuppressWarnings("unchecked") + public void testConstructWithClass() { + ArrayList al = DynamicUtil.construct(ArrayList.class); + Assert.assertNotNull(al); + Assert.assertEquals(ArrayList.class,al.getClass()); + } + @SuppressWarnings("unchecked") + public void testConstructWithString() { + ArrayList al = (ArrayList)DynamicUtil.construct("java.util.ArrayList"); + Assert.assertNotNull(al); + Assert.assertEquals(ArrayList.class,al.getClass()); + } + + public void testGetMethodForSelectorClassString() { + Object obj = new TestObject(); + Assert.assertNotNull(DynamicUtil.getMethodForSelector(obj.getClass(),"action:java.lang.String")); + } + + public interface IA {} + public interface IB {} + public interface IC extends IA {} + + public class A implements IA {} + public class B extends A implements IB {} + public class C implements IC {} + + public class TestObject { + public void action(String s) {} + } + +} diff --git a/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicallyAccessibleTest.java b/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicallyAccessibleTest.java new file mode 100644 index 0000000..94c9edb --- /dev/null +++ b/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicallyAccessibleTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2003-2009 Israfil Consulting Services Corporation + * Copyright (c) 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: DynamicallyAccessibleTest.java 130 2006-12-31 23:22:17Z cgruber $ + */ +package net.israfil.foundation.dynamic; + +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + + + +/** + * + * @author Christian Edward Gruber + * @author Latest: $Author: cgruber $ + * @version $Revision: 130 $ + */ +@Test +public class DynamicallyAccessibleTest { + + TestAccessibleObject testDBO; + String var1 = "value1"; + String var1Name = "publicVariable"; + String var2 = "value2"; + String var2Name = "publicVariableWithAccessor"; + String var3 = "value3"; + String var3Name = "privateVariable"; + boolean var4 = false; + String var4Name = "booleanVariable"; + int var5 = 5; + String var5Name = "intVariable"; + boolean var6 = true; + String var6Name = "isTrue"; + + @BeforeMethod + protected void setUp() { + testDBO = new TestAccessibleObject(var1,var2,var3,var4,var5,var6); + } + + @AfterMethod + protected void tearDown() throws Exception { + testDBO = null; + } + + public void testHasAccessor() { + Assert.assertFalse(testDBO.hasAccessor(var1Name)); + Assert.assertTrue(testDBO.hasAccessor(var2Name)); + Assert.assertTrue(testDBO.hasAccessor(var3Name)); + Assert.assertTrue(testDBO.hasAccessor(var4Name)); + Assert.assertTrue(testDBO.hasAccessor(var5Name)); + } + + public void testHasAttribute() { + Assert.assertTrue(testDBO.hasAttribute("publicVariable")); + Assert.assertTrue(testDBO.hasAttribute("publicVariableWithAccessor")); + Assert.assertTrue(testDBO.hasAttribute("privateVariable")); + Assert.assertTrue(testDBO.hasAttribute("booleanVariable")); + Assert.assertFalse(testDBO.hasAttribute("oddlyNamedIntVariable")); + Assert.assertTrue(testDBO.hasAttribute("aFinalStaticString")); + } + + public void testGet() { + Assert.assertEquals(var1,testDBO.get(var1Name)); + Assert.assertEquals(var2,testDBO.get(var2Name)); + Assert.assertEquals(var3,testDBO.get(var3Name)); + Assert.assertEquals(var4,testDBO.get(var4Name)); + Assert.assertEquals(var5,testDBO.get(var5Name)); + Assert.assertEquals(var6,testDBO.get(var6Name)); + } + + public void testHasAccessorStatic() { + Assert.assertFalse(DynamicallyAccessibleObject.hasAccessor(testDBO,var1Name)); + Assert.assertTrue(DynamicallyAccessibleObject.hasAccessor(testDBO,var2Name)); + Assert.assertTrue(DynamicallyAccessibleObject.hasAccessor(testDBO,var3Name)); + Assert.assertTrue(DynamicallyAccessibleObject.hasAccessor(testDBO,var4Name)); + Assert.assertTrue(DynamicallyAccessibleObject.hasAccessor(testDBO,var5Name)); + } + + public void testHasAttributeStatic() { + Assert.assertTrue(DynamicallyAccessibleObject.hasAttribute(testDBO,"publicVariable")); + Assert.assertTrue(DynamicallyAccessibleObject.hasAttribute(testDBO,"publicVariableWithAccessor")); + Assert.assertTrue(DynamicallyAccessibleObject.hasAttribute(testDBO,"privateVariable")); + Assert.assertTrue(DynamicallyAccessibleObject.hasAttribute(testDBO,"booleanVariable")); + Assert.assertFalse(DynamicallyAccessibleObject.hasAttribute(testDBO,"oddlyNamedIntVariable")); + Assert.assertTrue(DynamicallyAccessibleObject.hasAttribute(testDBO,"aFinalStaticString")); + } + + public void testGetStatic() { + Assert.assertEquals(var1,DynamicallyAccessibleObject.get(testDBO,var1Name)); + Assert.assertEquals(var2,DynamicallyAccessibleObject.get(testDBO,var2Name)); + Assert.assertEquals(var3,DynamicallyAccessibleObject.get(testDBO,var3Name)); + Assert.assertEquals(new Boolean(var4),DynamicallyAccessibleObject.get(testDBO,var4Name)); + Assert.assertEquals(new Integer(var5),DynamicallyAccessibleObject.get(testDBO,var5Name)); + } + + @Test(expectedExceptions={RuntimeException.class}) + public void testGetWithNoFieldOrAccessor() { + testDBO.get("nonExistantVariable"); + } + + + public static class TestAccessibleObject extends DynamicallyAccessibleObject { + + public String publicVariable; + public String publicVariableWithAccessor; + private String privateVariable; + private boolean booleanVariable; + private int oddlyNamedIntVariable; + public static final String aFinalStaticString = "foo"; + private boolean isTrue; + + public TestAccessibleObject() {} + + public TestAccessibleObject(String publicVar, + String publicVarWithAcc, + String privateVar, + boolean booleanVar, + int intVar, + boolean isTrue) { + this.publicVariable = publicVar; + this.publicVariableWithAccessor = publicVarWithAcc; + this.privateVariable = privateVar; + this.booleanVariable = booleanVar; + this.oddlyNamedIntVariable = intVar; + this.isTrue = isTrue; + } + + @Override + public void finalize() throws Throwable { + publicVariable = null; + publicVariableWithAccessor = null; + privateVariable = null; + super.finalize(); + } + public String getPublicVariableWithAccessor() + { return publicVariableWithAccessor;} + + public String getPrivateVariable() { return privateVariable; } + public boolean getBooleanVariable() { return booleanVariable; } + public int getIntVariable() { return oddlyNamedIntVariable; } + public boolean isTrue() { return isTrue; } + } +} diff --git a/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicallyMutableTest.java b/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicallyMutableTest.java new file mode 100644 index 0000000..9bc9103 --- /dev/null +++ b/israfil-foundation-dynamic/src/test/java/net/israfil/foundation/dynamic/DynamicallyMutableTest.java @@ -0,0 +1,210 @@ +/* + * 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: DynamicallyMutableTest.java 130 2006-12-31 23:22:17Z cgruber $ + */ +package net.israfil.foundation.dynamic; + +import net.israfil.foundation.core.Strings; + +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + + + +/** + * + * @author Christian Edward Gruber + * @author Latest: $Author: cgruber $ + * @version $Revision: 130 $ + */ +@Test +public class DynamicallyMutableTest { + + MutableTestObject testMO; + String var1 = "value1"; + String var1Name = "publicVariable"; + String var2 = "value2"; + String var2Name = "publicVariableWithAccessor"; + String var3 = "value3"; + String var3Name = "privateVariable"; + Boolean var4 = false; + String var4Name = "booleanVariable"; + Integer var5 = 5; + String var5Name = "intVariable"; + boolean var6 = true; + String var6Name = "primitiveBoolean"; + int var7 = 9; + String var7Name = "primitiveInt"; + + MutableTestObject2 mto2; + + + @BeforeMethod + protected void setUp() throws Exception { + testMO = new MutableTestObject(); + mto2 = new MutableTestObject2(); + } + + @AfterMethod + protected void tearDown() throws Exception { + testMO = null; + mto2 = null; + } + + public void testHasMutator() { + Assert.assertFalse(testMO.hasMutator(var1Name,var1.getClass())); + Assert.assertTrue(testMO.hasMutator(var2Name,var2.getClass())); + Assert.assertTrue(testMO.hasMutator(var3Name,var3.getClass())); + Assert.assertTrue(testMO.hasMutator(var4Name,var4.getClass())); + Assert.assertTrue(testMO.hasMutator(var5Name,var5.getClass())); + Assert.assertTrue(testMO.hasMutator(var6Name,boolean.class)); + Assert.assertTrue(testMO.hasMutator(var7Name,int.class)); + + } + + public void testSet() { + testMO.set(var1Name,var1); + testMO.set(var2Name,var2); + testMO.set(var3Name,var3); + testMO.set(var4Name,var4); + testMO.set(var5Name,var5); + testMO.set(var6Name,var6); + testMO.set(var7Name,var7); + Assert.assertEquals(var1,testMO.get(var1Name)); + Assert.assertEquals(var2,testMO.get(var2Name)); + Assert.assertEquals(var3,testMO.get(var3Name)); + Assert.assertEquals(var4,testMO.get(var4Name)); + Assert.assertEquals(var5,testMO.get(var5Name)); + } + + @Test(expectedExceptions={RuntimeException.class}) + public void testSetWithNoFieldOrAccessor() { + testMO.set("nonExistantVariable","aString"); + } + + public void testCamel() { + Assert.assertEquals("BlahFoo",Strings.camel("blahFoo")); + Assert.assertEquals("FooBar",Strings.camel("FooBar")); + } + + @Test(expectedExceptions={IllegalArgumentException.class}) + public void testSetWithNullAndNoParameterSetMethod() { + mto2.set("a",null); + } + + @Test(expectedExceptions={IllegalArgumentException.class}) + public void testSetWithNullWithTooManySetMethods() { + mto2.set("b",null); + } + + @Test(expectedExceptions={IllegalArgumentException.class}) + public void testSetWithNullAndSolitarySinglePrimitiveParameter() { + mto2.set("c",null); + } + + public void testSetWithNullAndSolitarySingleNonPrimitiveParameter() { + mto2.set("d",null); + Assert.assertTrue(mto2.d_String_WasTouched); + } + + public void testSetNullWithTypeAndSolitarySingleNonPrimitiveParameter() { + mto2.setNull("b",Integer.class); + Assert.assertTrue(mto2.b_Integer_WasTouched); + mto2.setNull("b",String.class); + Assert.assertTrue(mto2.b_String_WasTouched); + } + + @Test(expectedExceptions={IllegalArgumentException.class}) + public void testSetNullWithTypeAndSolitarySinglePrimitiveParameter() { + mto2.setNull("b",boolean.class); + } + + public class MutableTestObject2 extends DynamicallyMutableObject { + + public boolean a_WasTouched = false; + public boolean b_Integer_WasTouched = false; + public boolean b_String_WasTouched = false; + public boolean b_boolean_WasTouched = false; + public boolean c_boolean_WasTouched = false; + public boolean d_String_WasTouched = false; + + public boolean c; + + public void setA() {a_WasTouched = true;} + + public void setB(String s) {b_String_WasTouched = true;} + public void setB(Integer i) {b_Integer_WasTouched = true;} + public void setB(boolean b) {b_boolean_WasTouched = true;} + + public void setC(boolean b) {c_boolean_WasTouched = true;} + + public void setD(String s) {d_String_WasTouched = true;} + + } + + public class MutableTestObject extends DynamicallyMutableObject { + + public String publicVariable; + public String publicVariableWithAccessor; + private String privateVariable; + private boolean booleanVariable; + private int oddlyNamedIntVariable; + + public MutableTestObject() { + } + + @Override + public void finalize() throws Throwable { + publicVariable = null; + publicVariableWithAccessor = null; + privateVariable = null; + super.finalize(); + } + + public void setPublicVariableWithAccessor(String s) + { publicVariableWithAccessor = s; } + + public void setPrivateVariable(String s) { privateVariable = s; } + public String getPrivateVariable() { return privateVariable; } + + public void setBooleanVariable(Boolean b) { booleanVariable = b; } + public boolean getBooleanVariable() { return booleanVariable; } + + public void setIntVariable(Integer i) { oddlyNamedIntVariable = i; } + public Integer getIntVariable() { return oddlyNamedIntVariable; } + + public void setPrimitiveInt(int i) {} + public void setPrimitiveBoolean(boolean b) {} + } +} -- cgit v1.2.3