fit.TypeAdapter.java Source code

Java tutorial

Introduction

Here is the source code for fit.TypeAdapter.java

Source

// 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.*;
import java.util.*;
import java.util.regex.Pattern;

import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableSet;
import static org.apache.commons.lang.StringUtils.isEmpty;

public class TypeAdapter {
    public Object target;
    public Fixture fixture;
    public Field field;
    public Method method;
    public Class<?> type;
    public boolean isRegex;
    private static Map<Class<?>, TypeAdapter> PARSE_DELEGATES = new HashMap<Class<?>, TypeAdapter>();
    // 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;
        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;

        if (isRegex)
            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 && isEmpty((String) o))
            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 (RuntimeException e) {
            throw e;
        } 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 (RuntimeException e) {
            throw e;
        } 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 {
        public void set(Object i) throws IllegalAccessException {
            field.setByte(target, (Byte) i);
        }
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    static class ClassBooleanAdapter extends TypeAdapter {
        public Object parse(String s) {
            if ("null".equals(s))
                return null;
            String ls = s.toLowerCase();
            final Set<String> truth = unmodifiableSet(new HashSet<String>(asList("true", "yes", "1", "y", "+")));
            return truth.contains(ls);
        }
    }

    static class ArrayAdapter extends TypeAdapter {
        Class<?> componentType;
        TypeAdapter componentAdapter;

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

        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;
        }

        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();
        }

        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();
        }

        public Object parse(String s) throws Exception {
            return parseMethod.invoke(null, s);
        }

        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 });
        }

        public Object parse(String s) throws Exception {
            return parseMethod.invoke(delegate, s);
        }

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