/**
* == @Spearal ==>
*
* Copyright (C) 2014 Franck WOLFF & William DRAI (http://www.spearal.io)
*
* 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.spearal.impl.converter;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import org.spearal.SpearalContext;
import org.spearal.configuration.ConverterProvider;
import org.spearal.impl.SpearalDateTime;
/**
* @author Franck WOLFF
*/
public class SimpleConvertersProvider implements ConverterProvider {
private final Map<Class<?>, Converter<?>> converters;
public SimpleConvertersProvider() {
this.converters = new HashMap<Class<?>, Converter<?>>();
// Boolean
Converter<?> converter = new Converter<Boolean>() {
@Override
public Boolean convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return (targetType == boolean.class ? Boolean.FALSE : null);
Class<?> cls = value.getClass();
if (cls == Boolean.class)
return (Boolean)value;
if (cls == String.class)
return Boolean.valueOf(Boolean.parseBoolean((String)value));
if (Number.class.isAssignableFrom(cls))
return Boolean.valueOf(((Number)value).intValue() != 0);
if (cls == Character.class)
return Boolean.valueOf(((Character)value).charValue() != '\0');
return Boolean.TRUE;
}
};
converters.put(Boolean.class, converter);
converters.put(boolean.class, converter);
// Number
converter = new Converter<Byte>() {
@Override
public Byte convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return (targetType == byte.class ? Byte.valueOf((byte)0) : null);
Class<?> cls = value.getClass();
if (cls == Byte.class)
return (Byte)value;
if (Number.class.isAssignableFrom(cls))
return Byte.valueOf(((Number)value).byteValue());
if (cls == String.class) {
try {
return Byte.valueOf(Byte.parseByte((String)value));
}
catch (NumberFormatException e) {
return Byte.valueOf((byte)0);
}
}
if (cls == Boolean.class)
return Byte.valueOf((byte)(((Boolean)value).booleanValue() ? 1 : 0));
if (cls == Character.class)
return Byte.valueOf((byte)((Character)value).charValue());
return Byte.valueOf((byte)1);
}
};
converters.put(Byte.class, converter);
converters.put(byte.class, converter);
converter = new Converter<Short>() {
@Override
public Short convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return (targetType == int.class ? Short.valueOf((short)0) : null);
Class<?> cls = value.getClass();
if (cls == Short.class)
return (Short)value;
if (Number.class.isAssignableFrom(cls))
return Short.valueOf(((Number)value).shortValue());
if (cls == String.class) {
try {
return Short.valueOf(Short.parseShort((String)value));
}
catch (NumberFormatException e) {
return Short.valueOf((short)0);
}
}
if (cls == Character.class)
return Short.valueOf((short)((Character)value).charValue());
if (cls == Boolean.class)
return Short.valueOf((short)(((Boolean)value).booleanValue() ? 1 : 0));
return Short.valueOf((short)1);
}
};
converters.put(Short.class, converter);
converters.put(short.class, converter);
converter = new Converter<Integer>() {
@Override
public Integer convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return (targetType == int.class ? Integer.valueOf(0) : null);
Class<?> cls = value.getClass();
if (cls == Integer.class)
return (Integer)value;
if (Number.class.isAssignableFrom(cls))
return Integer.valueOf(((Number)value).intValue());
if (cls == String.class) {
try {
return Integer.valueOf(Integer.parseInt((String)value));
}
catch (NumberFormatException e) {
return Integer.valueOf(0);
}
}
if (cls == Character.class)
return Integer.valueOf(((Character)value).charValue());
if (cls == Boolean.class)
return Integer.valueOf(((Boolean)value).booleanValue() ? 1 : 0);
return Integer.valueOf(1);
}
};
converters.put(Integer.class, converter);
converters.put(int.class, converter);
converter = new Converter<Long>() {
@Override
public Long convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return (targetType == long.class ? Long.valueOf(0L) : null);
Class<?> cls = value.getClass();
if (cls == Long.class)
return (Long)value;
if (Number.class.isAssignableFrom(cls))
return Long.valueOf(((Number)value).longValue());
if (cls == String.class) {
try {
return Long.valueOf(Long.parseLong((String)value));
}
catch (NumberFormatException e) {
return Long.valueOf(0);
}
}
if (cls == Character.class)
return Long.valueOf(((Character)value).charValue());
if (cls == Boolean.class)
return Long.valueOf(((Boolean)value).booleanValue() ? 1L : 0L);
return Long.valueOf(1L);
}
};
converters.put(Long.class, converter);
converters.put(long.class, converter);
converter = new Converter<BigInteger>() {
@Override
public BigInteger convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == BigInteger.class)
return (BigInteger)value;
if (Number.class.isAssignableFrom(cls))
return BigInteger.valueOf(((Number)value).longValue());
if (cls == String.class) {
try {
return new BigInteger((String)value);
}
catch (NumberFormatException e) {
return BigInteger.ZERO;
}
}
if (cls == Character.class)
return BigInteger.valueOf(((Character)value).charValue());
if (cls == Boolean.class)
return (((Boolean)value).booleanValue() ? BigInteger.ONE : BigInteger.ZERO);
return BigInteger.ONE;
}
};
converters.put(BigInteger.class, converter);
final Float FLOAT_ZERO = Float.valueOf(0.0f);
final Float FLOAT_ONE = Float.valueOf(1.0f);
converter = new Converter<Float>() {
@Override
public Float convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return (targetType == float.class ? Float.valueOf(0.0f) : null);
Class<?> cls = value.getClass();
if (cls == Float.class)
return (Float)value;
if (Number.class.isAssignableFrom(cls))
return Float.valueOf(((Number)value).floatValue());
if (cls == String.class) {
try {
return Float.valueOf(Float.parseFloat((String)value));
}
catch (NumberFormatException e) {
return FLOAT_ZERO;
}
}
if (cls == Character.class)
return Float.valueOf(((Character)value).charValue());
if (cls == Boolean.class)
return (((Boolean)value).booleanValue() ? FLOAT_ONE : FLOAT_ZERO);
return FLOAT_ONE;
}
};
converters.put(Float.class, converter);
converters.put(float.class, converter);
final Double DOUBLE_ZERO = Double.valueOf(0.0);
final Double DOUBLE_ONE = Double.valueOf(1.0);
converter = new Converter<Double>() {
@Override
public Double convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return (targetType == double.class ? Double.valueOf(0.0) : null);
Class<?> cls = value.getClass();
if (cls == Double.class)
return (Double)value;
if (Number.class.isAssignableFrom(cls))
return Double.valueOf(((Number)value).doubleValue());
if (cls == String.class) {
try {
return Double.valueOf(Double.parseDouble((String)value));
}
catch (NumberFormatException e) {
return DOUBLE_ZERO;
}
}
if (cls == Character.class)
return Double.valueOf(((Character)value).charValue());
if (cls == Boolean.class)
return (((Boolean)value).booleanValue() ? DOUBLE_ONE : DOUBLE_ZERO);
return DOUBLE_ONE;
}
};
converters.put(Double.class, converter);
converters.put(double.class, converter);
converter = new Converter<BigDecimal>() {
@Override
public BigDecimal convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == BigDecimal.class)
return (BigDecimal)value;
if (Number.class.isAssignableFrom(cls))
return BigDecimal.valueOf(((Number)value).doubleValue());
if (cls == String.class) {
try {
return new BigDecimal((String)value);
}
catch (NumberFormatException e) {
return BigDecimal.ZERO;
}
}
if (cls == Character.class)
return BigDecimal.valueOf(((Character)value).charValue());
if (cls == Boolean.class)
return (((Boolean)value).booleanValue() ? BigDecimal.ONE : BigDecimal.ZERO);
return BigDecimal.ONE;
}
};
converters.put(BigDecimal.class, converter);
// String / Character
converter = new Converter<String>() {
@Override
public String convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == String.class)
return (String)value;
if (cls == char[].class)
return String.valueOf((char[])value);
if (cls == Character[].class) {
Character[] characters = (Character[])value;
StringBuilder sb = new StringBuilder(characters.length);
for (Character c : characters)
sb.append((c != null ? c.charValue() : '\0'));
return sb.toString();
}
return value.toString();
}
};
converters.put(String.class, converter);
converter = new Converter<Character>() {
@Override
public Character convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == Character.class)
return (Character)value;
if (cls == char[].class) {
char[] chars = (char[])value;
return (chars.length > 0 ? Character.valueOf(chars[0]) : null);
}
if (cls == Character[].class) {
Character[] characters = (Character[])value;
return (characters.length > 0 ? characters[0] : null);
}
String string = value.toString();
return (string.length() > 0 ? Character.valueOf(string.charAt(0)) : null);
}
};
converters.put(Character.class, converter);
converter = new Converter<Character>() {
@Override
public Character convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return Character.valueOf('\0');
Class<?> cls = value.getClass();
if (cls == Character.class)
return (Character)value;
if (cls == char[].class) {
char[] chars = (char[])value;
return Character.valueOf(chars.length > 0 ? chars[0] : '\0');
}
if (cls == Character[].class) {
Character[] characters = (Character[])value;
return (characters.length > 0 && characters[0] != null ? characters[0] : Character.valueOf('\0'));
}
String string = value.toString();
return (string.length() > 0 ? Character.valueOf(string.charAt(0)) : Character.valueOf('\0'));
}
};
converters.put(char.class, converter);
converter = new Converter<Character[]>() {
@Override
public Character[] convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == Character[].class)
return (Character[])value;
if (cls != char[].class)
value = value.toString().toCharArray();
char[] chars = (char[])value;
Character[] characters = new Character[chars.length];
for (int i = 0; i < chars.length; i++)
characters[i] = Character.valueOf(chars[i]);
return characters;
}
};
converters.put(Character[].class, converter);
converter = new Converter<char[]>() {
@Override
public char[] convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == char[].class)
return (char[])value;
if (cls == Character[].class) {
Character[] characters = (Character[])value;
char[] chars = new char[characters.length];
for (int i = 0; i < characters.length; i++) {
Character c = characters[i];
chars[i] = (c != null ? c.charValue() : '\0');
}
return chars;
}
return value.toString().toCharArray();
}
};
converters.put(char[].class, converter);
// Byte array
final Charset UTF8 = Charset.forName("UTF-8");
converter = new Converter<byte[]>() {
@Override
public byte[] convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == byte[].class)
return (byte[])value;
return value.toString().getBytes(UTF8);
}
};
converters.put(byte[].class, converter);
// Temporal types.
final TimeZone UTC = TimeZone.getTimeZone("UTC");
converter = new Converter<GregorianCalendar>() {
@Override
public GregorianCalendar convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == SpearalDateTime.class)
return ((SpearalDateTime)value).toGregorianCalendar();
Date date;
if (value instanceof Date)
date = (Date)value;
else if (value instanceof Number)
date = new Date(((Number)value).longValue());
else
date = parseDate(value.toString());
if (date != null) {
GregorianCalendar calendar = new GregorianCalendar(UTC, Locale.US);
calendar.setTime(date);
return calendar;
}
return null;
}
};
converters.put(Calendar.class, converter);
converters.put(GregorianCalendar.class, converter);
converter = new Converter<Date>() {
@Override
public Date convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == SpearalDateTime.class)
return ((SpearalDateTime)value).toDate();
if (cls == Date.class)
return (Date)value;
if (value instanceof Number)
return new Date(((Number)value).longValue());
return parseDate(value.toString());
}
};
converters.put(Date.class, converter);
converter = new Converter<java.sql.Date>() {
@Override
public java.sql.Date convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == SpearalDateTime.class)
return ((SpearalDateTime)value).toSQLDate();
if (cls == java.sql.Date.class)
return (java.sql.Date)value;
if (value instanceof Date)
return new java.sql.Date(((Date)value).getTime());
if (value instanceof Number)
return new java.sql.Date(((Number)value).longValue());
Date date = parseDate(value.toString());
return (date != null ? new java.sql.Date(date.getTime()) : null);
}
};
converters.put(java.sql.Date.class, converter);
converter = new Converter<java.sql.Time>() {
@Override
public java.sql.Time convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == SpearalDateTime.class)
return ((SpearalDateTime)value).toSQLTime();
if (cls == java.sql.Time.class)
return (java.sql.Time)value;
if (value instanceof Date)
return new java.sql.Time(((Date)value).getTime());
if (value instanceof Number)
return new java.sql.Time(((Number)value).longValue());
Date date = parseDate(value.toString());
return (date != null ? new java.sql.Time(date.getTime()) : null);
}
};
converters.put(java.sql.Time.class, converter);
converter = new Converter<java.sql.Timestamp>() {
@Override
public java.sql.Timestamp convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
Class<?> cls = value.getClass();
if (cls == SpearalDateTime.class)
return ((SpearalDateTime)value).toSQLTimestamp();
if (cls == java.sql.Timestamp.class)
return (java.sql.Timestamp)value;
if (value instanceof Date)
return new java.sql.Timestamp(((Date)value).getTime());
if (value instanceof Number)
return new java.sql.Timestamp(((Number)value).longValue());
Date date = parseDate(value.toString());
return (date != null ? new java.sql.Timestamp(date.getTime()) : null);
}
};
converters.put(java.sql.Timestamp.class, converter);
// Class.
converter = new Converter<Class<?>>() {
@Override
public Class<?> convert(SpearalContext context, Object value, Type targetType) {
if (value == null)
return null;
if (value.getClass() == Class.class)
return ((Class<?>)value);
try {
return context.loadClass(value.toString(), targetType);
}
catch (Exception e) {
return null;
}
}
};
converters.put(Class.class, converter);
// SpearalDateTime -> Object.
converter = new Converter<Object>() {
@Override
public Object convert(SpearalContext context, Object value, Type targetType) {
if (value != null && value.getClass() == SpearalDateTime.class)
return ((SpearalDateTime)value).toDate();
return value;
}
};
converters.put(Object.class, converter);
}
@Override
public Converter<?> getConverter(Class<?> valueClass, Type targetType) {
return converters.get(targetType);
}
private static Date parseDate(String s) {
// TODO: support ISO-8601 format.
DateFormat format = SimpleDateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
try {
return format.parse(s);
}
catch (Exception e) {
return null;
}
}
}