Package net.sourceforge.javautil.common.reflection

Source Code of net.sourceforge.javautil.common.reflection.ObjectManager

package net.sourceforge.javautil.common.reflection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassDescriptor;
import net.sourceforge.javautil.common.reflection.cache.ClassMethod;
import net.sourceforge.javautil.common.reflection.cache.ClassProperty;
import net.sourceforge.javautil.common.visitor.IVisitable;

/**
* A helper/utility for {@link ClassDescriptor}'s to hold onto a single instance
* and manipulate it via reflection.
*
* @author elponderador
* @author $Author: ponderator $
* @version $Id: ObjectManager.java 2624 2010-11-24 13:56:23Z ponderator $
*/
public class ObjectManager<T> implements IVisitable<ObjectVisitorBase> {
 
  /**
   * @param <T> The type/class of object
   * @param cache The cache to use
   * @param object The non-null object instance
   * @return A manager for manipulating the object
   */
  public static <T> ObjectManager<T> getManager (T object) {
    if (object == null) throw new IllegalArgumentException("Null objects not allowed for management");
   
    return new ObjectManager<T>(ClassCache.getFor((Class<T>)object.getClass()), object);
  }
 
  /**
   * The parent of this manager, or null if it does not have one
   */
  protected final ObjectManager parent;

  /**
   * The descriptor for the class of the inestnace
   */
  protected final ClassDescriptor<T> descriptor;
 
  /**
   * The instance to be managed, or null if it has not been instantiated
   */
  protected T instance;
 
  /**
   * This assumes null instance and no parent.
   *
   * @see #ObjectManager(ClassDescriptor, ObjectManager, Object)
   */
  public ObjectManager(ClassDescriptor<T> descriptor) {
    this(descriptor, null, null);
  }
 
  /**
   * This assumes no parent.
   *
   * @see #ObjectManager(ClassDescriptor, ObjectManager, Object)
   */
  public ObjectManager(ClassDescriptor<T> descriptor, T instance) {
    this(descriptor, null, instance);
  }
 
  /**
   * This assumes null instance.
   *
   * @see #ObjectManager(ClassDescriptor, ObjectManager, Object)
   */
  public ObjectManager(ClassDescriptor<T> descriptor, ObjectManager parent) {
    this(descriptor, parent, null);
  }
  
  /**
   * @param descriptor The {@link #descriptor}
   * @param instance The {@link #instance}
   */
  public ObjectManager(ClassDescriptor<T> descriptor, ObjectManager parent, T instance) {
    this.descriptor = descriptor;
    this.instance = instance;
    this.parent = parent;
  }
 
  /**
   * @param visitor The visitor that is interested in visiting this object and its properties
   * @return The visitor for chaining
   */
  public <V extends ObjectVisitorBase> V accept (V visitor) { this.accept(visitor, new ObjectVisitorContext(this, instance)); return visitor; }
 
  /**
   * The recursive method for visiting the object and its properties. Null values will NOT be visited.
   * This will respect {@link Collection}'s, arrays and {@link Map}'s and iterate over their values
   * and call the visitor for each one.
   *
   * @param visitor The visitor to call
   * @param instance The instance in question, or null if the property was null
   * @param property The property related to the instance, or null if the root
   * @return The response
   */
  protected void accept (ObjectVisitorBase visitor, ObjectVisitorContext ctx) {
    visitor.visit(ctx);
    if (ctx.isContinue()) {
      ClassDescriptor descriptor = ClassCache.getFor(instance.getClass());
      Map<String, ClassProperty> properties = descriptor.getProperties();
      for (String name : properties.keySet()) {
        ClassProperty op = properties.get(name);
        Object value = op.getValue(instance);
       
        if (value == null) continue;
       
        if (op.getType().isArray()) {
          for (int i=0; i<Array.getLength(value); i++) {
            Object avalue = Array.get(value, i);
            if (avalue != null) accept(visitor, ctx.setVisited(avalue, op));
            if (ctx.isAborted()) break;
          }
        } else if (value instanceof Collection) {
          Iterator it = ((Collection)value).iterator();
          while (it.hasNext()) {
            Object ivalue = it.next();
            if (ivalue != null) accept(visitor, ctx.setVisited(ivalue, op));
            if (ctx.isAborted()) break;
          }
        } else if (value instanceof Map) {
          Iterator keys = ((Map)value).keySet().iterator();
          while (keys.hasNext()) {
            Object mvalue = ((Map)value).get(keys.next());
            if (mvalue != null) accept(visitor, ctx.setVisited(mvalue, op));
            if (ctx.isAborted()) break;
          }
        } else accept(visitor, ctx.setVisited(value, op));
       
        if (ctx.isAborted()) break;
      }
    }
  }
 
  /**
   * @return The {@link #instance}
   */
  public T getInstance() { return instance; }
  public void setInstance(T instance) { this.instance = instance; }

  /**
   * @return The {@link #parent}
   */
  public ObjectManager getParent() { return parent; }
 
  /**
   * @return The {@link #descriptor}
   */
  public ClassDescriptor<T> getDescriptor() { return descriptor; }
 
  /**
   * @param name The name of a property
   * @return True if the property exists, otherwise false
   */
  public boolean hasProperty (String name) { return descriptor.hasProperty(name); }
 
  /**
   * @param name The name of a method
   * @return True if the method exists, otherwise false
   */
  public boolean hasMethod (String name) { return descriptor.hasMethod(name); }

  /**
   * @param name The name of the property
   * @param value The value to set/assign to the property
   */
  public void setProperty (String name, Object value) {
    descriptor.setPropertyValue(instance, name, value);
  }

  /**
   * @param name The name of the property
   * @return The current value of the property
   */
  public Object getProperty (String name) {
    return descriptor.getPropertyValue(instance, name);
  }
 
  /**
   * @param name The name of the property
   * @return A descriptor for the class/type of the property
   */
  public ClassDescriptor getPropertyDescriptor (String name) {
    return descriptor.getProperty(name).getTypeDescriptor();
  }
 
  /**
   * @param name The name of the property
   * @return An instance of the object manager for the current value of the property, if null a manager for the descriptor
   */
  public ObjectManager getPropertyManager (String name) {
    Object value = this.getProperty(name);
    return value == null ?
        new ObjectManager(this.getPropertyDescriptor(name), this) :
        new ObjectManager(descriptor.getCache().getDescriptor( value.getClass() ), this, value);
  }
 
  /**
   * This will match the arguments passed and see they are valid values for the method being invoked. Otherwise
   * the method must have no arguments, in any other case an exception will be thrown.
   *
   * @param <V> The type of value expected
   * @param annotationType The annotation type for locating the method
   * @param defaultValue The default value to return if the method is not found
   * @param optionalArguments The optional arguments to pass to the method
   * @return The value from the invocation of the method if found, otherwise the defaultValue
   */
  public <V> V invokeAnnotated (Class<? extends Annotation> annotationType, V defaultValue, Object... optionalArguments) {
    ClassMethod method = this.descriptor.getMethod(annotationType);
    if (method != null) {
      switch (method.compareArguments(optionalArguments)) {
        case EXACT: case FUNCTIONAL:
          return (V) method.invoke(instance, optionalArguments);
         
        default:
          if (method.getParameterTypes().length == 0) {
            return (V) method.invoke(instance);
          } else {
            throw new ReflectionException("Parameters required for method: " + method.getJavaMember());
          }
      }
    } else {
      return defaultValue;
    }
  }
 
  /**
   * @param name The name of the method to invoke
   * @param arguments The arguments to pass to the invocation
   * @return The value returned by the method invocation
   */
  public Object invoke (String name, Object... arguments) {
    return this.descriptor.invoke(name, instance, arguments);
  }
 
}
TOP

Related Classes of net.sourceforge.javautil.common.reflection.ObjectManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.