package net.techreadiness.service.object;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.techreadiness.annotation.CoreExtFields;
import net.techreadiness.annotation.CoreField;
import net.techreadiness.persistence.BaseEntity;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public abstract class BaseObject<T extends BaseEntity> implements Serializable {
private static final long serialVersionUID = 1L;
public abstract Class<T> getBaseEntityType();
protected DateFormat fmt;
public BaseObject() {
fmt = new SimpleDateFormat("M/d/yyyy");
}
public Map<String, String> getAsMap() {
Map<String, String> entityMap = Maps.newTreeMap();
try {
for (Class<?> clazz = this.getClass(); clazz != Object.class && clazz != null; clazz = clazz.getSuperclass()) {
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(CoreField.class)) {
field.setAccessible(true);
Object obj = field.get(this);
if (obj != null) {
if (java.util.Date.class.isAssignableFrom(field.getType())) {
entityMap.put(field.getName(), fmt.format((Date) obj));
} else {
entityMap.put(field.getName(), ConvertUtils.convert(obj));
}
}
} else if (field.isAnnotationPresent(CoreExtFields.class)) {
if (field.get(this) != null) {
Map<String, String> map = (Map<String, String>) field.get(this);
entityMap.putAll(map);
}
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return entityMap;
}
public void setFromMap(final Map<String, String> map, boolean update) {
Map<String, String> copy = Maps.newHashMap();
copy.putAll(map);
Iterator<Entry<String, String>> iterator = copy.entrySet().iterator();
try {
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue();
try {
Field field = this.getClass().getDeclaredField(key);
if (field != null) {
if (update || StringUtils.isNotEmpty(value)) {
Object convertedValue = ConvertUtils.convert(value, field.getType());
field.set(this, convertedValue);
}
iterator.remove();
}
} catch (NoSuchFieldException e) {
// nothing to do, field just may not exist. is to be expected sometimes.
} catch (Exception e) {
// probably a conversion error
e.printStackTrace();
}
}
// now put any remaining field in the extended attributes map (if
// appropriate).
if (!copy.isEmpty()) {// if the map is now empty we don't care about copying it into exts, their state remains
// unchanged
if (this instanceof BaseObjectWithExts) {
BaseObjectWithExts<T> thisWithExts = (BaseObjectWithExts<T>) this;
Map<String, String> exts = thisWithExts.getExtendedAttributes();
if (exts == null) {
exts = Maps.newHashMap();
}
exts.putAll(copy);
thisWithExts.setExtendedAttributes(exts);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @return the ID field for. The ID will be used to determine Object equality.
*/
public abstract Long getId();
/**
* Generate hashCode based on ID field. If ID is null, use reflection to build one dynamically.
*/
@Override
public int hashCode() {
if (getId() == null) {
return HashCodeBuilder.reflectionHashCode(this);
}
return getId().hashCode();
}
/**
* Determine object equality based on ID field. If the ID fields of both objects is null, use reflection to compare
* fields dynamically.
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj.getClass() != getClass()) {
return false;
}
BaseObject<?> other = (BaseObject<?>) obj;
if (getId() == null && other.getId() == null) {
return EqualsBuilder.reflectionEquals(this, obj);
}
return Objects.equal(getId(), other.getId());
}
public static List<Long> getIds(List<? extends BaseObject<?>> baseObjects) {
List<Long> ids = Lists.newArrayList();
for (BaseObject<?> object : baseObjects) {
ids.add(object.getId());
}
return ids;
}
}