All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fit.TypeAdapter Maven / Gradle / Ivy

There is a newer version: 20241026
Show newest version
// Modified or written by Object Mentor, Inc. for inclusion with FitNesse.
// Copyright (c) 2002 Cunningham & Cunningham, Inc.
// Released under the terms of the GNU General Public License version 2 or later.
package fit;

// Copyright (c) 2002 Cunningham & Cunningham, Inc.
// Released under the terms of the GNU General Public License version 2 or later.

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

public class TypeAdapter {
  public Object target;
  public Fixture fixture;
  public Field field;
  public Method method;
  public Class type;
  public boolean isRegex;
  private static final Map, TypeAdapter> PARSE_DELEGATES = new HashMap<>();
  // Factory //////////////////////////////////

  public static TypeAdapter on(Fixture target, Class type) {
    TypeAdapter a = adapterFor(type);
    a.init(target, type);
    return a;
  }

  public static TypeAdapter on(Fixture fixture, Field field) {
    TypeAdapter a = on(fixture, field.getType());
    a.target = fixture;
    a.field = field;
    a.field.setAccessible(true);
    return a;
  }

  public static TypeAdapter on(Fixture fixture, Method method) {
    return on(fixture, method, false);
  }

  public static TypeAdapter on(Fixture fixture, Method method, boolean isRegex) {
    TypeAdapter a = on(fixture, method.getReturnType());
    a.target = fixture;
    a.method = method;
    a.isRegex = isRegex;
    return a;
  }

  public static TypeAdapter adapterFor(Class type) throws UnsupportedOperationException {
    if (type.isPrimitive()) {
      if (type.equals(byte.class)) return new ByteAdapter();
      if (type.equals(short.class)) return new ShortAdapter();
      if (type.equals(int.class)) return new IntAdapter();
      if (type.equals(long.class)) return new LongAdapter();
      if (type.equals(float.class)) return new FloatAdapter();
      if (type.equals(double.class)) return new DoubleAdapter();
      if (type.equals(char.class)) return new CharAdapter();
      if (type.equals(boolean.class)) return new BooleanAdapter();
      throw new UnsupportedOperationException("can't yet adapt " + type);
    } else {
      Object delegate = PARSE_DELEGATES.get(type);
      if (delegate instanceof DelegateClassAdapter)
        return (TypeAdapter) ((DelegateClassAdapter) delegate).clone();
      if (delegate instanceof DelegateObjectAdapter)
        return (TypeAdapter) ((DelegateObjectAdapter) delegate).clone();
      if (type.equals(Byte.class)) return new ClassByteAdapter();
      if (type.equals(Short.class)) return new ClassShortAdapter();
      if (type.equals(Integer.class)) return new ClassIntegerAdapter();
      if (type.equals(Long.class)) return new ClassLongAdapter();
      if (type.equals(Float.class)) return new ClassFloatAdapter();
      if (type.equals(Double.class)) return new ClassDoubleAdapter();
      if (type.equals(Character.class)) return new ClassCharacterAdapter();
      if (type.equals(Boolean.class)) return new ClassBooleanAdapter();
      if (type.isArray()) return new ArrayAdapter();
      return new TypeAdapter();
    }
  }

  // Accessors ////////////////////////////////

  public void init(Fixture fixture, Class type) {
    this.fixture = fixture;
    this.type = type;
  }

  public Object get() throws IllegalAccessException, InvocationTargetException {
    if (field != null) {
      return field.get(target);
    }
    if (method != null) {
      return invoke();
    }
    return null;
  }

  public void set(Object value) throws Exception {
    field.set(target, value);
  }

  public Object invoke() throws IllegalAccessException, InvocationTargetException {
    Object[] params = {};
    return method.invoke(target, params);
  }

  public Object parse(String s) throws Exception {
    Object obj;
    obj = isRegex ? s : fixture.parse(s, type);
    return obj;
  }

  public boolean equals(Object a, Object b) {
    boolean isEqual = false;

    if (isRegex) {
      if (b != null)
        isEqual = Pattern.matches(a.toString(), b.toString());
    } else {
      if (a == null)
        isEqual = (b == null);
      else
        isEqual = a.equals(b);
    }
    return isEqual;
  }

  public String toString(Object o) {
    if (o == null) {
      return "null";
    } else if (o instanceof String && ((String) o).equals(""))
      return "blank";
    else
      return o.toString();
  }

  /*
   * Registers a delegate, a class that will handle parsing of other types of values.
   */
  public static void registerParseDelegate(Class type, Class parseDelegate) {
    try {
      PARSE_DELEGATES.put(type, new DelegateClassAdapter(parseDelegate));
    } catch (Exception ex) {
      throw new RuntimeException("Parse delegate class " + parseDelegate.getName()
        + " does not have a suitable static parse() method.");
    }
  }

  /*
   * Registers a delegate object that will handle parsing of other types of values.
   */
  public static void registerParseDelegate(Class type, Object parseDelegate) {
    try {
      PARSE_DELEGATES.put(type, new DelegateObjectAdapter(parseDelegate));
    } catch (Exception ex) {
      throw new RuntimeException("Parse delegate object of class " + parseDelegate.getClass().getName()
        + " does not have a suitable parse() method.");
    }
  }

  public static void clearDelegatesForNextTest() {
    PARSE_DELEGATES.clear();
  }

  // Subclasses ///////////////////////////////

  static class ByteAdapter extends ClassByteAdapter {
    @Override
    public void set(Object i) throws IllegalAccessException {
      field.setByte(target, ((Byte) i).byteValue());
    }
  }

  static class ClassByteAdapter extends TypeAdapter {
    @Override
    public Object parse(String s) {
      return ("null".equals(s)) ? null : new Byte(Byte.parseByte(s));
    }
  }

  static class ShortAdapter extends ClassShortAdapter {
    @Override
    public void set(Object i) throws IllegalAccessException {
      field.setShort(target, ((Short) i).shortValue());
    }
  }

  static class ClassShortAdapter extends TypeAdapter {
    @Override
    public Object parse(String s) {
      return ("null".equals(s)) ? null : new Short(Short.parseShort(s));
    }
  }

  static class IntAdapter extends ClassIntegerAdapter {
    @Override
    public void set(Object i) throws IllegalAccessException {
      field.setInt(target, ((Integer) i).intValue());
    }
  }

  static class ClassIntegerAdapter extends TypeAdapter {
    @Override
    public Object parse(String s) {
      return ("null".equals(s)) ? null : new Integer(Integer.parseInt(s));
    }
  }

  static class LongAdapter extends ClassLongAdapter {
    public void set(Long i) throws IllegalAccessException {
      field.setLong(target, i.longValue());
    }
  }

  static class ClassLongAdapter extends TypeAdapter {
    @Override
    public Object parse(String s) {
      return ("null".equals(s)) ? null : new Long(Long.parseLong(s));
    }
  }

  static class FloatAdapter extends ClassFloatAdapter {
    @Override
    public void set(Object i) throws IllegalAccessException {
      field.setFloat(target, ((Number) i).floatValue());
    }

    @Override
    public Object parse(String s) {
      return ("null".equals(s)) ? null : new Float(Float.parseFloat(s));
    }
  }

  static class ClassFloatAdapter extends TypeAdapter {
    @Override
    public Object parse(String s) {
      return ("null".equals(s)) ? null : new Float(Float.parseFloat(s));
    }
  }

  static class DoubleAdapter extends ClassDoubleAdapter {
    @Override
    public void set(Object i) throws IllegalAccessException {
      field.setDouble(target, ((Number) i).doubleValue());
    }

    @Override
    public Object parse(String s) {
      return new Double(Double.parseDouble(s));
    }
  }

  static class ClassDoubleAdapter extends TypeAdapter {
    @Override
    public Object parse(String s) {
      return ("null".equals(s)) ? null : new Double(Double.parseDouble(s));
    }
  }

  static class CharAdapter extends ClassCharacterAdapter {
    @Override
    public void set(Object i) throws IllegalAccessException {
      field.setChar(target, ((Character) i).charValue());
    }
  }

  static class ClassCharacterAdapter extends TypeAdapter {
    @Override
    public Object parse(String s) {
      return ("null".equals(s)) ? null : new Character(s.charAt(0));
    }
  }

  static class BooleanAdapter extends ClassBooleanAdapter {
    @Override
    public void set(Object i) throws IllegalAccessException {
      field.setBoolean(target, ((Boolean) i).booleanValue());
    }
  }

  static class ClassBooleanAdapter extends TypeAdapter {
    @Override
    public Object parse(String s) {
      if ("null".equals(s)) return null;
      String ls = s.toLowerCase();
      if (ls.equals("true"))
        return Boolean.TRUE;
      if (ls.equals("yes"))
        return Boolean.TRUE;
      if (ls.equals("1"))
        return Boolean.TRUE;
      if (ls.equals("y"))
        return Boolean.TRUE;
      if (ls.equals("+"))
        return Boolean.TRUE;
      return Boolean.FALSE;
    }
  }

  static class ArrayAdapter extends TypeAdapter {
    Class componentType;
    TypeAdapter componentAdapter;

    @Override
    public void init(Fixture target, Class type) {
      super.init(target, type);
      componentType = type.getComponentType();
      componentAdapter = on(target, componentType);
    }

    @Override
    public Object parse(String s) throws Exception {
      StringTokenizer t = new StringTokenizer(s, ",");
      Object array = Array.newInstance(componentType, t.countTokens());
      for (int i = 0; t.hasMoreTokens(); i++) {
        Array.set(array, i, componentAdapter.parse(t.nextToken().trim()));
      }
      return array;
    }

    @Override
    public String toString(Object o) {
      if (o == null)
        return "";
      int length = Array.getLength(o);
      StringBuilder b = new StringBuilder(5 * length);
      for (int i = 0; i < length; i++) {
        b.append(componentAdapter.toString(Array.get(o, i)));
        if (i < (length - 1)) {
          b.append(", ");
        }
      }
      return b.toString();
    }

    @Override
    public boolean equals(Object a, Object b) {
      int length = Array.getLength(a);
      if (length != Array.getLength(b))
        return false;
      for (int i = 0; i < length; i++) {
        if (!componentAdapter.equals(Array.get(a, i), Array.get(b, i)))
          return false;
      }
      return true;
    }
  }

  static class DelegateClassAdapter extends TypeAdapter implements Cloneable {
    private Method parseMethod;

    public DelegateClassAdapter(Class parseDelegate) throws SecurityException, NoSuchMethodException {
      this.parseMethod = parseDelegate.getMethod("parse", new Class[]{String.class});
      int modifiers = parseMethod.getModifiers();
      if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)
        || parseMethod.getReturnType() == Void.class)
        throw new NoSuchMethodException();
    }

    @Override
    public Object parse(String s) throws Exception {
      return parseMethod.invoke(null, new Object[]
        {s});
    }

    @Override
    protected Object clone() {
      try {
        return super.clone();
      } catch (CloneNotSupportedException e) {
        return null;
      }
    }
  }

  static class DelegateObjectAdapter extends TypeAdapter implements Cloneable {
    private Object delegate;
    private Method parseMethod;

    public DelegateObjectAdapter(Object delegate) throws SecurityException, NoSuchMethodException {
      this.delegate = delegate;
      this.parseMethod = delegate.getClass().getMethod("parse", new Class[]
        {String.class});
    }

    @Override
    public Object parse(String s) throws Exception {
      return parseMethod.invoke(delegate, new Object[]
        {s});
    }

    @Override
    protected Object clone() {
      try {
        return super.clone();
      } catch (CloneNotSupportedException e) {
        return null;
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy