Package jfun.yan.xml.nut

Source Code of jfun.yan.xml.nut.NutIntrospector

package jfun.yan.xml.nut;


import java.beans.BeanInfo;
import java.beans.IndexedPropertyDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import jfun.yan.Binder;
import jfun.yan.Component;
import jfun.yan.xml.ConfigurationException;




/**
* Utility class to run introspection on a {@link Nut} class
* to get NutDescriptor.
* <p>
* @author Ben Yu
* Nov 9, 2005 11:34:52 PM
*/
public class NutIntrospector implements java.io.Serializable {
  private final HashMap cache = new HashMap();
  /**
   * Get a NutDescriptor for a Nut class.
   * @param type the class.
   * @return the NutDescriptor object.
   * @throws IntrospectionException when introspection fails.
   */
  public NutDescriptor getNutDescriptor(final Class type)
  throws IntrospectionException{
    NutDescriptor desc = (NutDescriptor)cache.get(type);
    if(desc == null){
      if(!Nut.class.isAssignableFrom(type)){
        throw new IllegalArgumentException("only Nut class is introspectable.");
      }
      /*
      try{
        type.getConstructor(null);
      }
      catch(NoSuchMethodException e){
        throw new IllegalArgumentException("default constructor not present in class "+type);
      }*/
      desc = new NutDescriptor(type);
      cache.put(type, desc);
      final Evaluator evaluator = getEvaluator(type);
      desc.setEvaluator(evaluator);
      desc.setPropertyDescriptors(getProperties(type));
      populateSub(type, desc);
    }
    return desc;
  }
  private Evaluator getEvaluator(final Class type){
    if(ComponentNut.class.isAssignableFrom(type)){
      return new Evaluator(){
        public Object eval(Object obj)
        throws Exception{
          final ComponentNut nut = (ComponentNut)obj;
          return nut.eval();
        }
        public Class getType(){
          return Component.class;
        }
      };
    }
    else if(BinderNut.class.isAssignableFrom(type)){
      return new Evaluator(){
        public Object eval(Object obj) {
          final BinderNut nut = (BinderNut)obj;
          try{
            return nut.eval();
          }
          catch(Exception e){
            throw new ConfigurationException(e, nut.getTagLocation());
          }
        }
        public Class getType(){
          return Binder.class;
        }
      };
    }
    else{
      try{
        final Method mtd = type.getMethod("eval", null);
        final Class rtype = mtd.getReturnType();
        return new Evaluator(){
          public Object eval(Object obj){
            final Nut nut = (Nut)obj;
            try{
              final Object r = mtd.invoke(nut, null);
              if(void.class.equals(rtype)){
                return nut;
              }
              else return r;
            }
            catch(InvocationTargetException e){
              throw new ConfigurationException(e.getTargetException(), nut.getTagLocation());
            }
            catch(Exception e){
              throw new ConfigurationException(e, nut.getTagLocation());
            }
          }
          public Class getType(){
            return (void.class.equals(rtype)?type:rtype);
          }
        };
      }
      catch(NoSuchMethodException e){
        return new Evaluator(){
          public Object eval(Object nut){
            return nut;
          }
          public Class getType(){
            return type;
          }
        };
      }
    }
  }
 
  private Map getProperties(Class type)
  throws IntrospectionException{
    final BeanInfo info = Introspector.getBeanInfo(type);
    final PropertyDescriptor[] pdescs = info.getPropertyDescriptors();
    final HashMap ret = new HashMap();
    for(int i=0; i<pdescs.length; i++){
      final PropertyDescriptor desc = pdescs[i];
      if(desc.getWriteMethod()!=null && !(desc instanceof IndexedPropertyDescriptor)){
        ret.put(desc.getName(), desc);
      }
    }
    return ret;
  }
  //gets the only "set" method with one array parameter.
  //if more than one is found, use the most restrictive one.
  private final void populateSub(Class type, NutDescriptor desc)
  throws IntrospectionException{
    final HashMap subs= new HashMap();
    final Method[] mtds = type.getMethods();
    final ArrayList anonymous_adders = new ArrayList();
    Class etype = null;
    Method r = null;
    for(int i=0; i<mtds.length; i++){
      final Method mtd = mtds[i];
      final String mname = mtd.getName();
      if(mname.equals("set")){
        final Class[] ptypes = mtd.getParameterTypes();
        if(ptypes.length != 1){
          continue;
        }
        final Class ptype = ptypes[0];
        if(!ptype.isArray()){
          continue;
        }
        final Class etype2 = ptype.getComponentType();
        if(etype != null){
          if(etype.isAssignableFrom(etype2)){
            //we find a more restrictive version
            etype = etype2;
            r = mtd;
          }
        }
        else{
          r = mtd;
          etype = etype2;
        }
      }
      else if(mname.startsWith(ADDER)){
        final Class[] ptypes = mtd.getParameterTypes();
        if(ptypes.length!=1){
          continue;
        }
        Class ptype = ptypes[0];
        final String elem_name = mname.substring(3).toLowerCase(Locale.US);
        if(subs.containsKey(elem_name)){
          throw new IllegalArgumentException("duplicate adder: "+mname);
        }
        if(elem_name.length()==0){
          /*
          if(!ptype.isAssignableFrom(String.class)){
            //add() with non-string parameter.
            continue;
          }*/
          anonymous_adders.add(new Method1(mtd, ptype));
        }
        else{
          if(!Nut.class.isAssignableFrom(ptype))
            continue;
          desc.putAdder(elem_name, mtd);
          if(elem_name.length()>0){
            subs.put(elem_name, getNutDescriptor(ptype));
          }
        }
      }
    }
    if(r!=null){
      desc.setCollectionDescriptor(
          new NutDescriptor.CollectionDescriptor(etype, r)
      );
    }
    else{
      desc.setRegularDescriptor(
          new NutDescriptor.RegularDescriptor(subs)
      );
    }
    final Method1[] anonymous = new Method1[anonymous_adders.size()];
    anonymous_adders.toArray(anonymous);
    desc.setAdderSuite(new MethodSuite(ADDER, anonymous));
  }
  private static final String ADDER = "add";
}
TOP

Related Classes of jfun.yan.xml.nut.NutIntrospector

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.