Package flexjson

Source Code of flexjson.ObjectBinder

package flexjson;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import flexjson.factories.ArrayObjectFactory;
import flexjson.factories.BeanObjectFactory;
import flexjson.factories.BooleanObjectFactory;
import flexjson.factories.ByteObjectFactory;
import flexjson.factories.CharacterObjectFactory;
import flexjson.factories.ClassLocatorObjectFactory;
import flexjson.factories.ClassObjectFactory;
import flexjson.factories.DoubleObjectFactory;
import flexjson.factories.EnumObjectFactory;
import flexjson.factories.FloatObjectFactory;
import flexjson.factories.IntegerObjectFactory;
import flexjson.factories.ListObjectFactory;
import flexjson.factories.LongObjectFactory;
import flexjson.factories.MapObjectFactory;
import flexjson.factories.SetObjectFactory;
import flexjson.factories.ShortObjectFactory;
import flexjson.factories.StringObjectFactory;

public class ObjectBinder
{

  private Stack<Object> objectStack= new Stack<Object>();
  private Stack<Object> jsonStack= new Stack<Object>();
  private Path currentPath= new Path();
  private Map<Object, ObjectFactory> factories;
  private Map<Path, ObjectFactory> pathFactories= new HashMap<Path, ObjectFactory>();
  public Map<Integer, Object> references= new HashMap<Integer, Object>();

  public Map<Integer, Object> getReferences()
  {
    return references;
  }

  public ObjectBinder()
  {
    factories= new HashMap<Object, ObjectFactory>();
    factories.put(Class.class, new ClassObjectFactory());
    factories.put(Object.class, new BeanObjectFactory());
    factories.put(Collection.class, new ListObjectFactory());
    factories.put(List.class, new ListObjectFactory());
    factories.put(Set.class, new SetObjectFactory());
    //        factories.put( SortedSet.class, new SortedSetObjectFactory() );
    factories.put(Map.class, new MapObjectFactory());
    factories.put(Integer.class, new IntegerObjectFactory());
    factories.put(int.class, new IntegerObjectFactory());
    factories.put(Float.class, new FloatObjectFactory());
    factories.put(float.class, new FloatObjectFactory());
    factories.put(Double.class, new DoubleObjectFactory());
    factories.put(double.class, new DoubleObjectFactory());
    factories.put(Short.class, new ShortObjectFactory());
    factories.put(short.class, new ShortObjectFactory());
    factories.put(Long.class, new LongObjectFactory());
    factories.put(long.class, new LongObjectFactory());
    factories.put(Byte.class, new ByteObjectFactory());
    factories.put(byte.class, new ByteObjectFactory());
    factories.put(Boolean.class, new BooleanObjectFactory());
    factories.put(boolean.class, new BooleanObjectFactory());
    factories.put(Character.class, new CharacterObjectFactory());
    factories.put(char.class, new CharacterObjectFactory());
    factories.put(Enum.class, new EnumObjectFactory());
    //        factories.put( Date.class, new DateObjectFactory() );
    factories.put(String.class, new StringObjectFactory());
    factories.put(Array.class, new ArrayObjectFactory());
    //        factories.put( BigDecimal.class, new BigDecimalFactory() );
    //        factories.put( BigInteger.class, new BigIntegerFactory() );
  }

  public ObjectBinder use(Path path, ObjectFactory factory)
  {
    pathFactories.put(path, factory);
    return this;
  }

  public ObjectBinder use(Object clazz, ObjectFactory factory)
  {
    factories.put(clazz, factory);
    return this;
  }

  public Path getCurrentPath()
  {
    return currentPath;
  }

  public Object bind(Object input)
  {
    return this.bind(input, null);
  }

  public Object bind(Object source, Object target)
  {
    if (target instanceof Map)
    {
      bindIntoMap((Map) source, (Map<Object, Object>) target, null, null);
    }
    else if (target instanceof Collection)
    {
      bindIntoCollection((Collection) source, (Collection<Object>) target, null);
    }
    else
    {
      bindIntoObject((Map) source, target, target.getClass());
    }
    return target;
  }

  public Object bind(Object input, Type targetType)
  {
    jsonStack.add(input);
    try
    {
      if (input == null)
        return null;
      Class targetClass= findClassName(input, getTargetClass(targetType));
      ObjectFactory factory= findFactoryFor(targetClass);
      if (factory == null)
        throw new JSONException(currentPath + ": + Could not find a suitable ObjectFactory for " + targetClass);
      return factory.instantiate(this, input, targetType, targetClass);
    }
    finally
    {
      jsonStack.pop();
    }
  }

  public <T extends Collection<Object>> T bindIntoCollection(Collection value, T target, Type targetType)
  {
    Type valueType= null;
    if (targetType instanceof ParameterizedType)
    {
      valueType= ((ParameterizedType) targetType).getActualTypeArguments()[0];
    }
    jsonStack.add(value);
    objectStack.add(target);
    getCurrentPath().enqueue("values");
    for (Object obj : value)
    {
      target.add(bind(obj, valueType));
    }
    getCurrentPath().pop();
    objectStack.pop();
    jsonStack.pop();
    return target;
  }

  public Object bindIntoMap(Map input, Map<Object, Object> result, Type keyType, Type valueType)
  {
    jsonStack.add(input);
    objectStack.add(result);
    for (Object inputKey : input.keySet())
    {
      currentPath.enqueue("keys");
      Object key= bind(inputKey, keyType);
      currentPath.pop();
      currentPath.enqueue("values");
      Object value= bind(input.get(inputKey), valueType);
      currentPath.pop();
      result.put(key, value);
    }
    objectStack.pop();
    jsonStack.pop();
    return result;
  }

  public Object bindIntoObject(Map jsonOwner, Object target, Type targetType)
  {
    try
    {
      objectStack.add(target);
      BeanAnalyzer analyzer= BeanAnalyzer.analyze(target.getClass());
      for (BeanProperty descriptor : analyzer.getProperties())
      {
        Object value= findFieldInJson(jsonOwner, descriptor);
        if (value != null)
        {
          currentPath.enqueue(descriptor.getName());
          Method setMethod= descriptor.getWriteMethod();
          if (setMethod != null)
          {
            Type[] types= setMethod.getGenericParameterTypes();
            if (types.length == 1)
            {
              Type paramType= types[0];
              setMethod.invoke(objectStack.peek(), bind(value, resolveParameterizedTypes(paramType, targetType)));
            }
            else
            {
              throw new JSONException(currentPath + ":  Expected a single parameter for method " + target.getClass().getName() + "." + setMethod.getName() + " but got " + types.length);
            }
          }
          else
          {
            Field field= descriptor.getProperty();
            if (field != null)
            {
              field.setAccessible(true);
              field.set(target, bind(value, field.getGenericType()));
            }
          }
          currentPath.pop();
        }
      }
      return objectStack.pop();
    }
    catch (IllegalAccessException e)
    {
      throw new JSONException(currentPath + ":  Could not access the no-arg constructor for " + target.getClass().getName(), e);
    }
    catch (InvocationTargetException ex)
    {
      throw new JSONException(currentPath + ":  Exception while trying to invoke setter method.", ex);
    }
  }

  public JSONException cannotConvertValueToTargetType(Object value, Class targetType)
  {
    return new JSONException(String.format("%s:  Can not convert %s into %s", currentPath, value.getClass().getName(), targetType.getName()));
  }

  private Class getTargetClass(Type targetType)
  {
    if (targetType == null)
    {
      return null;
    }
    else if (targetType instanceof Class)
    {
      return (Class) targetType;
    }
    else if (targetType instanceof ParameterizedType)
    {
      return (Class) ((ParameterizedType) targetType).getRawType();
    }
    else if (targetType instanceof GenericArrayType)
    {
      return Array.class;
    }
    else if (targetType instanceof WildcardType)
    {
      return null; // nothing you can do about these.  User will have to specify this with use()
    }
    else if (targetType instanceof TypeVariable)
    {
      return null; // nothing you can do about these.  User will have to specify this with use()
    }
    else
    {
      throw new JSONException(currentPath + ":  Unknown type " + targetType);
    }
  }

  private Type resolveParameterizedTypes(Type genericType, Type targetType)
  {
    if (genericType instanceof Class)
    {
      return genericType;
    }
    else if (genericType instanceof ParameterizedType)
    {
      return genericType;
    }
    else if (genericType instanceof TypeVariable)
    {
      return targetType;
    }
    else if (genericType instanceof WildcardType)
    {
      return targetType;
    }
    else if (genericType instanceof GenericArrayType)
    {
      return ((GenericArrayType) genericType).getGenericComponentType();
    }
    else
    {
      throw new JSONException(currentPath + ":  Unknown generic type " + genericType + ".");
    }
  }

  private Class findClassName(Object map, Class targetType) throws JSONException
  {
    if (!pathFactories.containsKey(currentPath))
    {
      Class mostSpecificType= useMostSpecific(targetType, map instanceof Map ? findClassInMap((Map) map, null) : null);
      if (mostSpecificType == null)
      {
        return map.getClass();
      }
      else
      {
        return mostSpecificType;
      }
    }
    else
    {
      return null;
    }
  }

  protected Class useMostSpecific(Class classFromTarget, Class typeFound)
  {
    if (classFromTarget != null && typeFound != null)
    {
      return typeFound.isAssignableFrom(classFromTarget) ? classFromTarget : typeFound;
    }
    else if (typeFound != null)
    {
      return typeFound;
    }
    else if (classFromTarget != null)
    {
      return classFromTarget;
    }
    else
    {
      return null;
    }
  }

  protected Class findClassInMap(Map map, Class override)
  {
    if (override == null)
    {
      Integer reference= (Integer) map.get("@ref");
      if (reference != null)
        return getReferences().get(reference).getClass();

      String classname= (String) map.remove("class");
      try
      {
        if (classname != null)
        {
          return Class.forName(classname);
        }
        else
        {
          return null;
        }
      }
      catch (ClassNotFoundException e)
      {
        throw new JSONException( /*String.format( "%s:  Could not load %s", currentPath, classname ), */e);
      }
    }
    else
    {
      return override;
    }
  }

  private ObjectFactory findFactoryFor(Class targetType)
  {
    ObjectFactory factory= pathFactories.get(currentPath);
    if (factory == null)
    {
      if (targetType != null && targetType.isArray())
        return factories.get(Array.class);
      return findFactoryByTargetClass(targetType);
    }
    return factory;
  }

  private ObjectFactory findFactoryByTargetClass(Class targetType)
  {
    ObjectFactory factory;
    factory= factories.get(targetType);
    if (factory == null && targetType != null && targetType.getSuperclass() != null)
    {
      for (Class intf : targetType.getInterfaces())
      {
        factory= findFactoryByTargetClass(intf);
        if (factory != null)
          return factory;
      }
      return findFactoryByTargetClass(targetType.getSuperclass());
    }
    else
    {
      return factory;
    }
  }

  protected Object instantiate(Class clazz)
  {
    try
    {
      Constructor constructor= clazz.getDeclaredConstructor();
      constructor.setAccessible(true);
      return constructor.newInstance();
    }
    catch (InstantiationException e)
    {
      throw new JSONException(currentPath + ":There was an exception trying to instantiate an instance of " + clazz.getName(), e);
    }
    catch (IllegalAccessException e)
    {
      throw new JSONException(currentPath + ":There was an exception trying to instantiate an instance of " + clazz.getName(), e);
    }
    catch (InvocationTargetException e)
    {
      throw new JSONException(currentPath + ":There was an exception trying to instantiate an instance of " + clazz.getName(), e);
    }
    catch (NoSuchMethodException e)
    {
      throw new JSONException(currentPath + ": " + clazz.getName() + " lacks a no argument constructor.  Flexjson will instantiate any protected, private, or public no-arg constructor.", e);
    }
  }

  private Object findFieldInJson(Map map, BeanProperty property)
  {
    Object value= map.get(property.getName());
    if (value == null)
    {
      String field= property.getName();
      value= map.get(upperCase(field));
    }

    return value;
  }

  private String upperCase(String field)
  {
    return Character.toUpperCase(field.charAt(0)) + field.substring(1);
  }

  public Object getTarget()
  {
    return objectStack.peek();
  }

  public Object getSource()
  {
    return jsonStack.peek();
  }

  public Object bindPrimitive(Object value, Class clazz)
  {
    if (value.getClass() == clazz)
    {
      return value;
    }
    else if (value instanceof Number && clazz.equals(Double.class))
    {
      return ((Number) value).doubleValue();
    }
    else if (value instanceof Number && clazz.equals(Integer.class))
    {
      return ((Number) value).intValue();
    }
    else if (value instanceof Number && clazz.equals(Long.class))
    {
      return ((Number) value).longValue();
    }
    else if (value instanceof Number && clazz.equals(Short.class))
    {
      return ((Number) value).shortValue();
    }
    else if (value instanceof Number && clazz.equals(Byte.class))
    {
      return ((Number) value).byteValue();
    }
    else if (value instanceof Number && clazz.equals(Float.class))
    {
      return ((Number) value).floatValue();
    }
    else if (value instanceof Boolean && clazz.equals(Boolean.class))
    {
      return value;
    }
    else if (value instanceof Long && clazz == Date.class)
    {
      return new Date((Long) value);
    }
    else
    {
      throw new JSONException(String.format("%s: Don't know how to bind %s into class %s.  You might need to use an ObjectFactory instead of a plain class.", getCurrentPath().toString(), value, clazz.getName()));
    }
  }

  public Class findClassAtPath(Path currentPath) throws ClassNotFoundException
  {
    ObjectFactory factory= pathFactories.get(currentPath);
    if (factory instanceof ClassLocatorObjectFactory)
    {
      return ((ClassLocatorObjectFactory) factory).getLocator().locate(this, currentPath);
    }
    else
    {
      return null;
    }
  }
}
TOP

Related Classes of flexjson.ObjectBinder

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.