// Copyright 2006, 2007, 2008, 2010, 2011, 2012 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.apache.tapestry5.ioc.services; import org.apache.tapestry5.plastic.PlasticUtils; /** * An immutable object that represents a mapping from one type to another. This is also the contribution type when * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that * describe * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of * coercions). * * @param <S> * source (input) type * @param <T> * target (output) type */ public final class CoercionTuple<S, T> { private final Class<S> sourceType; private final Class<T> targetType; private final Coercion<S, T> coercion; /** * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types. */ private class CoercionWrapper<WS, WT> implements Coercion<WS, WT> { private final Coercion<WS, WT> coercion; public CoercionWrapper(Coercion<WS, WT> coercion) { this.coercion = coercion; } @Override public WT coerce(WS input) { return coercion.coerce(input); } @Override public String toString() { return String.format("%s --> %s", convert(sourceType), convert(targetType)); } } private String convert(Class type) { if (Void.class.equals(type)) return "null"; String name = PlasticUtils.toTypeName(type); int dotx = name.lastIndexOf('.'); // Strip off a package name of "java.lang" if (dotx > 0 && name.substring(0, dotx).equals("java.lang")) return name.substring(dotx + 1); return name; } /** * Standard constructor, which defaults wrap to true. */ public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion) { this(sourceType, targetType, coercion, true); } /** * Convenience constructor to help with generics. * * @since 5.2.0 */ public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion) { return new CoercionTuple<S, T>(sourceType, targetType, coercion); } /** * Internal-use constructor. * * @param sourceType * the source (or input) type of the coercion, may be Void.class to indicate a coercion from null * @param targetType * the target (or output) type of the coercion * @param coercion * the object that performs the coercion * @param wrap * if true, the coercion is wrapped to provide a useful toString() */ @SuppressWarnings("unchecked") public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap) { assert sourceType != null; assert targetType != null; assert coercion != null; this.sourceType = PlasticUtils.toWrapperType(sourceType); this.targetType = PlasticUtils.toWrapperType(targetType); this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion; } @Override public String toString() { return coercion.toString(); } public Coercion<S, T> getCoercion() { return coercion; } public Class<S> getSourceType() { return sourceType; } public Class<T> getTargetType() { return targetType; } }