/*
* Copyright 2008-2011 the original author or authors.
*
* 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.kaleidofoundry.core.util;
import static org.kaleidofoundry.core.i18n.InternalBundleHelper.UtilMessageBundle;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import org.kaleidofoundry.core.lang.annotation.Task;
import org.kaleidofoundry.core.lang.annotation.TaskLabel;
import org.kaleidofoundry.core.lang.annotation.ThreadSafe;
/**
* Primitives types (java.lang type) toString serializer
*
* @author jraduget
*/
@ThreadSafe
public class PrimitiveTypeToStringSerializer implements ToStringSerializer {
/** The multi-value separator by default is | */
public static final String DefaultMultiValuesSeparator = "|";
/** The date format pattern by default */
public static final String DefaultDateFormat = "yyyy-MM-dd'T'HH:mm:ss"; // yyyy-MM-ddTHH:mm:ss
/** The number format pattern by default */
public static final String DefaultNumberFormat = "##0.0####";
/** The multi-value separator to use */
protected final String MultiValuesSeparator;
/** The date format pattern to use */
protected final String DateFormat;
/** The number format pattern to use */
protected final String NumberFormat;
/**
*
*/
public PrimitiveTypeToStringSerializer() {
this(DefaultMultiValuesSeparator, DefaultDateFormat, DefaultNumberFormat);
}
/**
* @param multiValuesSeparator
* @param dateFormat
* @param numberFormat
*/
public PrimitiveTypeToStringSerializer(final String multiValuesSeparator, final String dateFormat, final String numberFormat) {
MultiValuesSeparator = (multiValuesSeparator != null ? multiValuesSeparator : DefaultMultiValuesSeparator);
DateFormat = dateFormat != null ? dateFormat : DefaultDateFormat;
NumberFormat = numberFormat != null ? numberFormat : DefaultNumberFormat;
}
/*
* (non-Javadoc)
* @see org.kaleidofoundry.core.util.ToStringSerializer#serialize(T, java.lang.Class)
*/
@Override
@Task(comment = "use SimpleDateFormat has a thread local", labels = TaskLabel.Enhancement)
public <T extends Serializable> String serialize(final T value, final Class<T> type) {
if (value == null) { return null; }
if (Boolean.class.isAssignableFrom(type)) { return value.toString(); }
if (Number.class.isAssignableFrom(type)) { return value.toString(); }
if (Date.class.isAssignableFrom(type) || (value instanceof Date && String.class.isAssignableFrom(type))) { return new SimpleDateFormat(DateFormat)
.format((Date) value); }
if (String.class.isAssignableFrom(type)) { return String.valueOf(value); }
if (Character.class.isAssignableFrom(type)) {
String valueStr = String.valueOf(value);
return StringHelper.isEmpty(valueStr) ? null : String.valueOf(valueStr.charAt(0));
}
throw new IllegalStateException(UtilMessageBundle.getMessage("serializer.illegal.class", type.getName()));
}
/*
* (non-Javadoc)
* @see org.kaleidofoundry.core.util.ToStringSerializer#deserialize(java.lang.String, java.lang.Class)
*/
@Override
@SuppressWarnings("unchecked")
@Task(comment = "use SimpleDateFormat has a thread local", labels = TaskLabel.Enhancement)
public <T extends Serializable> T deserialize(final String value, final Class<T> type) throws IllegalStateException {
if (value == null) { return null; }
if (Boolean.class.isAssignableFrom(type)) { return (T) Boolean.valueOf(value); }
if (Number.class.isAssignableFrom(type)) {
try {
if (Byte.class == type) { return (T) Byte.valueOf(value); }
if (Short.class == type) { return (T) Short.valueOf(value); }
if (Integer.class == type) { return (T) Integer.valueOf(value); }
if (Long.class == type) { return (T) Long.valueOf(value); }
if (Float.class == type) { return (T) Float.valueOf(value); }
if (Double.class == type) { return (T) Double.valueOf(value); }
if (BigInteger.class == type) { return (T) new BigInteger(value); }
if (BigDecimal.class == type) { return (T) new BigDecimal(value); }
} catch (final NumberFormatException nfe) {
throw new IllegalStateException(UtilMessageBundle.getMessage("serializer.number.format.error", value), nfe);
}
}
if (Date.class.isAssignableFrom(type)) {
try {
return (T) new SimpleDateFormat(DateFormat).parse(value);
} catch (final ParseException pe) {
throw new IllegalStateException(UtilMessageBundle.getMessage("serializer.date.format.error", value, DateFormat), pe);
}
}
if (String.class.isAssignableFrom(type)) { return (T) (StringHelper.isEmpty(value) ? "" : value); }
if (Character.class.isAssignableFrom(type)) { return (T) (StringHelper.isEmpty(value) ? null : Character.valueOf(value.charAt(0))); }
throw new IllegalStateException(UtilMessageBundle.getMessage("serializer.illegal.class", type.getName()));
}
/*
* (non-Javadoc)
* @see org.kaleidofoundry.core.util.ToStringSerializer#serialize(java.util.Collection, java.lang.Class)
*/
@Override
public <T extends Serializable> String serialize(final Collection<T> values, final Class<T> type) {
if (values == null) {
return null;
} else {
List<String> valuesList = new LinkedList<String>();
for (T v : values) {
valuesList.add(serialize(v, type));
}
return StringHelper.unsplit(MultiValuesSeparator, valuesList.toArray());
}
}
/*
* (non-Javadoc)
* @see org.kaleidofoundry.core.util.ToStringSerializer#deserializeToList(java.lang.String, java.lang.Class)
*/
@Override
public <T extends Serializable> List<T> deserializeToList(final String values, final Class<T> type) {
if (values == null) { return null; }
List<T> result = null;
if (!StringHelper.isEmpty(values)) {
result = new LinkedList<T>();
final StringTokenizer strToken = new StringTokenizer(values, MultiValuesSeparator);
while (strToken.hasMoreTokens()) {
result.add(deserialize(strToken.nextToken(), type));
}
}
return result;
}
/**
* convert a value to another type
*
* @param <T>
* @param value
* @param type
* @return
* @throws IllegalArgumentException
*/
@SuppressWarnings("unchecked")
protected <T extends Serializable> T convert(final Serializable value, final Class<T> type) {
if (value == null) { return null; }
if (type.isAssignableFrom(value.getClass())) {
return (T) value;
} else if (value instanceof String) {
return deserialize((String) value, type);
} else if (BigDecimal.class.isAssignableFrom(type)) {
return (T) new BigDecimal(value.toString());
} else if (BigInteger.class.isAssignableFrom(type)) {
return (T) new BigInteger(value.toString());
} else if (Long.class.isAssignableFrom(type)) {
return (T) new Long(value.toString());
} else if (Integer.class.isAssignableFrom(type)) {
return (T) new Integer(value.toString());
} else if (Double.class.isAssignableFrom(type)) {
return (T) new Double(value.toString());
} else if (Float.class.isAssignableFrom(type)) {
return (T) new Float(value.toString());
} else if (Short.class.isAssignableFrom(type)) {
return (T) new Short(value.toString());
} else if (type.isAssignableFrom(String.class)) {
return (T) serialize((T) value, type);
} else {
throw new IllegalArgumentException(UtilMessageBundle.getMessage("serializer.illegal.argument", value.getClass().getName(), type.getName()));
}
}
/**
* convert a list value to another list type
*
* @param <T>
* @param values
* @param type
* @return
* @throws IllegalArgumentException
*/
@SuppressWarnings("unchecked")
protected <T extends Serializable> List<T> convertToList(final Serializable values, final Class<T> type) {
if (values == null) { return null; }
if (values instanceof String) {
return deserializeToList((String) values, type);
} else if (values instanceof Collection) {
Collection<? extends Serializable> current = (Collection<? extends Serializable>) values;
List<T> result = new ArrayList<T>();
for (Serializable item : current) {
result.add(convert(item, type));
}
return result;
} else {
return Arrays.asList(convert(values, type));
}
}
}