    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}