/*******************************************************************************
* Copyright 2013 Ivan Shubin http://mindengine.net
*
* 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 net.mindengine.blogix.db.readers;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import net.mindengine.blogix.db.Entry;
import org.apache.commons.lang3.StringUtils;
public class ObjectReader<T> implements Reader<T> {
private Map<String, Field> objectFields = null;
private EntryReader entryConverter;
private Class<T> objectType;
public ObjectReader(Class<T> objectType, EntryReader entryConverter) {
this.objectType = objectType;
this.entryConverter = entryConverter;
}
@Override
public T convert(String fileName) {
Entry entry = entryConverter.convert(fileName);
return convert(entry);
}
public T convert(Entry entry) {
try {
Constructor<T> constructor = objectType.getConstructor();
T objectInstance = constructor.newInstance();
Set<String> allEntryFields = entry.getAllFieldNames();
for (String entryFieldName : allEntryFields) {
resolveField(entryFieldName, entry, objectInstance);
}
Field field = getObjectFields().get("id");
if (field != null) {
setFieldValue(objectInstance, field, entry.id());
}
setEntryItselfIntoObject(entry, objectInstance);
return objectInstance;
} catch (Exception e) {
throw new RuntimeException("Cannot bind entries to object " + objectType.getClass(), e);
}
}
private void setEntryItselfIntoObject(Entry entry, T objectInstance) throws IllegalArgumentException, IllegalAccessException {
Field entryField = getObjectFields().get("entry");
if (entryField != null) {
if (entryField.getType().equals(Entry.class)) {
entryField.setAccessible(true);
entryField.set(objectInstance, entry);
}
}
}
private void resolveField(String entryFieldName, Entry entry, T objectInstance) {
Field field = getObjectFields().get(entryFieldName);
if (field != null) {
setFieldValue(objectInstance, field, entry.field(entryFieldName));
}
}
private Map<String, Field> getObjectFields() {
if (objectFields == null) {
objectFields = getAllFieldsOfObjectType(objectType);
}
return objectFields;
}
private void setFieldValue(T objectInstance, Field field, String fieldValue) {
Object convertedFieldValue = convertFieldValue(fieldValue, field);
field.setAccessible(true);
try {
field.set(objectInstance, convertedFieldValue);
} catch (Exception e) {
throw new RuntimeException("Cannot set value to field " + field.toString());
}
}
private Object convertFieldValue(String fieldValue, Field field) {
if (fieldValue == null) {
return null;
}
Class<?> type = field.getType();
try {
return convertStringValueToType(fieldValue, type);
}
catch (Exception e) {
throw new IllegalArgumentException("Cannot convert value '" + StringUtils.abbreviate(fieldValue, 20) + "' to field " + field.toString(), e);
}
}
private Object convertStringValueToType(String fieldValue, Class<?> type) {
if (type.equals(String.class)) {
return fieldValue;
}
else if (type.equals(Integer.class) || type.equals(int.class)) {
return Integer.parseInt(fieldValue.trim());
}
else if (type.equals(Long.class) || type.equals(long.class)) {
return Long.parseLong(fieldValue.trim());
}
else if (type.equals(Float.class) || type.equals(float.class)) {
return Float.parseFloat(fieldValue.trim());
}
else if (type.equals(Double.class) || type.equals(double.class)) {
return Double.parseDouble(fieldValue.trim());
}
else if (type.equals(Boolean.class) || type.equals(boolean.class)) {
return Boolean.parseBoolean(fieldValue.trim());
}
else if (type.equals(Date.class)) {
return parseDate(fieldValue);
}
else if (type.equals(String[].class)) {
if (fieldValue.trim().isEmpty()) {
return new String[]{};
}
String[] items = fieldValue.split(",");
String[] array = new String[items.length];
for( int i=0; i<array.length; i++) {
array[i] = (String) convertStringValueToType(items[i].trim(), String.class);
}
return array;
}
throw new IllegalArgumentException("Cannot convert value '" + StringUtils.abbreviate(fieldValue, 20) + "' to type " + type);
}
private Date parseDate(String fieldValue) {
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd hh:mm");
try {
return sdf.parse(fieldValue.trim());
} catch (ParseException e) {
throw new RuntimeException("Error parsing date: " + fieldValue, e);
}
}
private Map<String, Field> getAllFieldsOfObjectType(Class<?> objectType) {
Map<String, Field> fields = convertOnlyNonStaticFieldsToMap(objectType.getDeclaredFields());
Class<?> superClass = objectType.getSuperclass();
if (superClass!=null) {
fields.putAll(getAllFieldsOfObjectType(superClass));
}
return fields;
}
private Map<String, Field> convertOnlyNonStaticFieldsToMap(Field[] declaredFields) {
Map<String, Field> fields = new HashMap<String, Field>();
for (Field field : declaredFields) {
if (!Modifier.isStatic(field.getModifiers())) {
fields.put(field.getName(), field);
}
}
return fields;
}
}