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}