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
015 package org.apache.tapestry5.ioc.services;
016
017 import 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 */
032 public 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 public WT coerce(WS input)
053 {
054 return coercion.coerce(input);
055 }
056
057 @Override
058 public String toString()
059 {
060 return String.format("%s --> %s", convert(sourceType), convert(targetType));
061 }
062 }
063
064 private String convert(Class type)
065 {
066 if (Void.class.equals(type))
067 return "null";
068
069 String name = PlasticUtils.toTypeName(type);
070
071 int dotx = name.lastIndexOf('.');
072
073 // Strip off a package name of "java.lang"
074
075 if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
076 return name.substring(dotx + 1);
077
078 return name;
079 }
080
081 /**
082 * Standard constructor, which defaults wrap to true.
083 */
084 public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
085 {
086 this(sourceType, targetType, coercion, true);
087 }
088
089 /**
090 * Convenience constructor to help with generics.
091 *
092 * @since 5.2.0
093 */
094 public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
095 {
096 return new CoercionTuple<S, T>(sourceType, targetType, coercion);
097 }
098
099 /**
100 * Internal-use constructor.
101 *
102 * @param sourceType
103 * the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
104 * @param targetType
105 * the target (or output) type of the coercion
106 * @param coercion
107 * the object that performs the coercion
108 * @param wrap
109 * if true, the coercion is wrapped to provide a useful toString()
110 */
111 @SuppressWarnings("unchecked")
112 public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
113 {
114 assert sourceType != null;
115 assert targetType != null;
116 assert coercion != null;
117
118 this.sourceType = PlasticUtils.toWrapperType(sourceType);
119 this.targetType = PlasticUtils.toWrapperType(targetType);
120 this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
121 }
122
123 @Override
124 public String toString()
125 {
126 return coercion.toString();
127 }
128
129 public Coercion<S, T> getCoercion()
130 {
131 return coercion;
132 }
133
134 public Class<S> getSourceType()
135 {
136 return sourceType;
137 }
138
139 public Class<T> getTargetType()
140 {
141 return targetType;
142 }
143
144 }