001// Copyright 2014 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.
014package org.apache.tapestry5.ioc.internal;
015
016import java.io.File;
017import java.lang.reflect.Array;
018import java.math.BigDecimal;
019import java.math.BigInteger;
020import java.util.Arrays;
021import java.util.Collection;
022import java.util.Collections;
023import java.util.List;
024
025import org.apache.tapestry5.func.Flow;
026import org.apache.tapestry5.ioc.Configuration;
027import org.apache.tapestry5.ioc.services.Coercion;
028import org.apache.tapestry5.ioc.services.CoercionTuple;
029import org.apache.tapestry5.ioc.services.TypeCoercer;
030import org.apache.tapestry5.ioc.util.TimeInterval;
031
032/**
033 * Class that provides Tapestry-IoC's basic type coercions.
034 * @see TypeCoercer
035 * @see Coercion
036 */
037public class BasicTypeCoercions
038{
039    /**
040     * Provides the basic type coercions to a {@link Configuration} instance. 
041     */
042    public static void provideBasicTypeCoercions(Configuration<CoercionTuple> configuration)
043    {
044        add(configuration, Object.class, String.class, new Coercion<Object, String>()
045        {
046            @Override
047            public String coerce(Object input)
048            {
049                return input.toString();
050            }
051        });
052
053        add(configuration, Object.class, Boolean.class, new Coercion<Object, Boolean>()
054        {
055            @Override
056            public Boolean coerce(Object input)
057            {
058                return input != null;
059            }
060        });
061
062        add(configuration, String.class, Double.class, new Coercion<String, Double>()
063        {
064            @Override
065            public Double coerce(String input)
066            {
067                return Double.valueOf(input);
068            }
069        });
070
071        // String to BigDecimal is important, as String->Double->BigDecimal would lose
072        // precision.
073
074        add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>()
075        {
076            @Override
077            public BigDecimal coerce(String input)
078            {
079                return new BigDecimal(input);
080            }
081        });
082
083        add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>()
084        {
085            @Override
086            public Double coerce(BigDecimal input)
087            {
088                return input.doubleValue();
089            }
090        });
091
092        add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>()
093        {
094            @Override
095            public BigInteger coerce(String input)
096            {
097                return new BigInteger(input);
098            }
099        });
100
101        add(configuration, String.class, Long.class, new Coercion<String, Long>()
102        {
103            @Override
104            public Long coerce(String input)
105            {
106                return Long.valueOf(input);
107            }
108        });
109
110        add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
111        {
112            @Override
113            public Byte coerce(Long input)
114            {
115                return input.byteValue();
116            }
117        });
118
119        add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
120        {
121            @Override
122            public Short coerce(Long input)
123            {
124                return input.shortValue();
125            }
126        });
127
128        add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>()
129        {
130            @Override
131            public Integer coerce(Long input)
132            {
133                return input.intValue();
134            }
135        });
136
137        add(configuration, Number.class, Long.class, new Coercion<Number, Long>()
138        {
139            @Override
140            public Long coerce(Number input)
141            {
142                return input.longValue();
143            }
144        });
145
146        add(configuration, Double.class, Float.class, new Coercion<Double, Float>()
147        {
148            @Override
149            public Float coerce(Double input)
150            {
151                return input.floatValue();
152            }
153        });
154
155        add(configuration, Long.class, Double.class, new Coercion<Long, Double>()
156        {
157            @Override
158            public Double coerce(Long input)
159            {
160                return input.doubleValue();
161            }
162        });
163
164        add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>()
165        {
166            @Override
167            public Boolean coerce(String input)
168            {
169                String trimmed = input == null ? "" : input.trim();
170
171                if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
172                    return false;
173
174                // Any non-blank string but "false"
175
176                return true;
177            }
178        });
179
180        add(configuration, Number.class, Boolean.class, new Coercion<Number, Boolean>()
181        {
182            @Override
183            public Boolean coerce(Number input)
184            {
185                return input.longValue() != 0;
186            }
187        });
188
189        add(configuration, Void.class, Boolean.class, new Coercion<Void, Boolean>()
190        {
191            @Override
192            public Boolean coerce(Void input)
193            {
194                return false;
195            }
196        });
197
198        add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
199        {
200            @Override
201            public Boolean coerce(Collection input)
202            {
203                return !input.isEmpty();
204            }
205        });
206
207        add(configuration, Object.class, List.class, new Coercion<Object, List>()
208        {
209            @Override
210            public List coerce(Object input)
211            {
212                return Collections.singletonList(input);
213            }
214        });
215
216        add(configuration, Object[].class, List.class, new Coercion<Object[], List>()
217        {
218            @Override
219            public List coerce(Object[] input)
220            {
221                return Arrays.asList(input);
222            }
223        });
224
225        add(configuration, Object[].class, Boolean.class, new Coercion<Object[], Boolean>()
226        {
227            @Override
228            public Boolean coerce(Object[] input)
229            {
230                return input != null && input.length > 0;
231            }
232        });
233
234        add(configuration, Float.class, Double.class, new Coercion<Float, Double>()
235        {
236            @Override
237            public Double coerce(Float input)
238            {
239                return input.doubleValue();
240            }
241        });
242
243        Coercion primitiveArrayCoercion = new Coercion<Object, List>()
244        {
245            @Override
246            public List<Object> coerce(Object input)
247            {
248                int length = Array.getLength(input);
249                Object[] array = new Object[length];
250                for (int i = 0; i < length; i++)
251                {
252                    array[i] = Array.get(input, i);
253                }
254                return Arrays.asList(array);
255            }
256        };
257
258        add(configuration, byte[].class, List.class, primitiveArrayCoercion);
259        add(configuration, short[].class, List.class, primitiveArrayCoercion);
260        add(configuration, int[].class, List.class, primitiveArrayCoercion);
261        add(configuration, long[].class, List.class, primitiveArrayCoercion);
262        add(configuration, float[].class, List.class, primitiveArrayCoercion);
263        add(configuration, double[].class, List.class, primitiveArrayCoercion);
264        add(configuration, char[].class, List.class, primitiveArrayCoercion);
265        add(configuration, boolean[].class, List.class, primitiveArrayCoercion);
266
267        add(configuration, String.class, File.class, new Coercion<String, File>()
268        {
269            @Override
270            public File coerce(String input)
271            {
272                return new File(input);
273            }
274        });
275
276        add(configuration, String.class, TimeInterval.class, new Coercion<String, TimeInterval>()
277        {
278            @Override
279            public TimeInterval coerce(String input)
280            {
281                return new TimeInterval(input);
282            }
283        });
284
285        add(configuration, TimeInterval.class, Long.class, new Coercion<TimeInterval, Long>()
286        {
287            @Override
288            public Long coerce(TimeInterval input)
289            {
290                return input.milliseconds();
291            }
292        });
293
294        add(configuration, Object.class, Object[].class, new Coercion<Object, Object[]>()
295        {
296            @Override
297            public Object[] coerce(Object input)
298            {
299                return new Object[]
300                        {input};
301            }
302        });
303
304        add(configuration, Collection.class, Object[].class, new Coercion<Collection, Object[]>()
305        {
306            @Override
307            public Object[] coerce(Collection input)
308            {
309                return input.toArray();
310            }
311        });
312        
313        configuration.add(CoercionTuple.create(Flow.class, List.class, new Coercion<Flow, List>()
314        {
315            @Override
316            public List coerce(Flow input)
317            {
318                return input.toList();
319            }
320        }));
321
322        configuration.add(CoercionTuple.create(Flow.class, Boolean.class, new Coercion<Flow, Boolean>()
323        {
324            @Override
325            public Boolean coerce(Flow input)
326            {
327                return !input.isEmpty();
328            }
329        }));
330        
331
332    }
333
334    private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
335                                   Class<T> targetType, Coercion<S, T> coercion)
336    {
337        configuration.add(CoercionTuple.create(sourceType, targetType, coercion));
338    }
339    
340    
341
342}