    001// Copyright 2006, 2007, 2008, 2010, 2011, 2012 The Apache Software Foundation
    002//
    003// Licensed under the Apache License, Version 2.0 (the "License");
    004// you may not use this file except in compliance with the License.
    005// You may obtain a copy of the License at
    006//
    007// http://www.apache.org/licenses/LICENSE-2.0
    008//
    009// Unless required by applicable law or agreed to in writing, software
    010// distributed under the License is distributed on an "AS IS" BASIS,
    011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012// See the License for the specific language governing permissions and
    013// limitations under the License.
    014
    015package org.apache.tapestry5.ioc.services;
    016
    017import org.apache.tapestry5.plastic.PlasticUtils;
    018
    019/**
    020 * An immutable object that represents a mapping from one type to another. This is also the contribution type when
    021 * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
    022 * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
    023 * describe
    024 * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
    025 * coercions).
    026 *
    027 * @param <S>
    028 *         source (input) type
    029 * @param <T>
    030 *         target (output) type
    031 */
    032public final class CoercionTuple<S, T>
    033{
    034    private final Class<S> sourceType;
    035
    036    private final Class<T> targetType;
    037
    038    private final Coercion<S, T> coercion;
    039
    040    /**
    041     * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
    042     */
    043    private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
    044    {
    045        private final Coercion<WS, WT> coercion;
    046
    047        public CoercionWrapper(Coercion<WS, WT> coercion)
    048        {
    049            this.coercion = coercion;
    050        }
    051
    052        @Override
    053        public WT coerce(WS input)
    054        {
    055            return coercion.coerce(input);
    056        }
    057
    058        @Override
    059        public String toString()
    060        {
    061            return String.format("%s --> %s", convert(sourceType), convert(targetType));
    062        }
    063    }
    064
    065    private String convert(Class type)
    066    {
    067        if (Void.class.equals(type))
    068            return "null";
    069
    070        String name = PlasticUtils.toTypeName(type);
    071
    072        int dotx = name.lastIndexOf('.');
    073
    074        // Strip off a package name of "java.lang"
    075
    076        if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
    077            return name.substring(dotx + 1);
    078
    079        return name;
    080    }
    081
    082    /**
    083     * Standard constructor, which defaults wrap to true.
    084     */
    085    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
    086    {
    087        this(sourceType, targetType, coercion, true);
    088    }
    089
    090    /**
    091     * Convenience constructor to help with generics.
    092     *
    093     * @since 5.2.0
    094     */
    095    public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
    096    {
    097        return new CoercionTuple<S, T>(sourceType, targetType, coercion);
    098    }
    099
    100    /**
    101     * Internal-use constructor.
    102     *
    103     * @param sourceType
    104     *         the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
    105     * @param targetType
    106     *         the target (or output) type of the coercion
    107     * @param coercion
    108     *         the object that performs the coercion
    109     * @param wrap
    110     *         if true, the coercion is wrapped to provide a useful toString()
    111     */
    112    @SuppressWarnings("unchecked")
    113    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
    114    {
    115        assert sourceType != null;
    116        assert targetType != null;
    117        assert coercion != null;
    118
    119        this.sourceType = PlasticUtils.toWrapperType(sourceType);
    120        this.targetType = PlasticUtils.toWrapperType(targetType);
    121        this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
    122    }
    123
    124    @Override
    125    public String toString()
    126    {
    127        return coercion.toString();
    128    }
    129
    130    public Coercion<S, T> getCoercion()
    131    {
    132        return coercion;
    133    }
    134
    135    public Class<S> getSourceType()
    136    {
    137        return sourceType;
    138    }
    139
    140    public Class<T> getTargetType()
    141    {
    142        return targetType;
    143    }
    144
    145}