package org.openflexo.ws.jira.model;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JIRAObject<J extends JIRAObject<J>> extends HashMap<String, Object> {
/**
*
*/
private static final long serialVersionUID = -3961683012433439153L;
private transient J originalObject;
/** The REST reference to this object */
private String self;
/** The id of the object, usually an integer, but this is represented as a string in JSON */
private String id;
/** The key of the object which is a string. */
private String key;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getSelf() {
return self;
}
public void setSelf(String self) {
this.self = self;
}
public Class<J> getTypedClass() {
return (Class<J>) getClass();
}
public J getAsIdentityObject() throws InstantiationException, IllegalAccessException {
J j = getTypedClass().newInstance();
if (id != null) {
j.setId(id);
} else if (key != null) {
j.setKey(key);
} else {
j.setSelf(self);
}
if (originalObject != null) {
j.originalObject = originalObject;
} else {
j.originalObject = (J) this;
}
return j;
}
@Override
public boolean equals(Object o) {
return o == this || o != null && o.getClass() == getClass() && ((JIRAObject<?>) o).id != null && ((JIRAObject<?>) o).id.equals(id);
}
@Override
public int hashCode() {
if (getId() != null) {
return getId().hashCode();
} else if (getKey() != null) {
return getKey().hashCode();
} else if (getSelf() != null) {
return getSelf().hashCode();
} else {
return super.hashCode();
}
}
public J restoreObject() {
return originalObject;
}
public void automaticMutate() {
}
public <O extends JIRAObject> O mutate(Class<O> target) throws InstantiationException, IllegalAccessException, SecurityException,
NoSuchFieldException {
O o = target.newInstance();
Class<?> klass = getClass();
while (klass != null && JIRAObject.class.isAssignableFrom(klass)) {
for (Field f : klass.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers())) {
continue;
}
if (Modifier.isFinal(f.getModifiers())) {
continue;
}
if (Modifier.isTransient(f.getModifiers())) {
continue;
}
Object value = f.get(this);
setMutatedValueForField(o, value, f.getName());
}
klass = klass.getSuperclass();
}
for (Map.Entry<String, Object> e : entrySet()) {
Object value = e.getValue();
setMutatedValueForField(o, value, e.getKey());
}
return o;
}
protected <O extends JIRAObject> void setMutatedValueForField(O o, Object value, String fieldName) throws IllegalAccessException,
InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException {
Field field = null;
Class<?> klass = o.getClass();
while (field == null && klass != null) {
try {
field = klass.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
} catch (SecurityException e) {
}
klass = klass.getSuperclass();
}
if (value != null) {
if (field != null) {
field.setAccessible(true);
if (value instanceof JIRAObject && JIRAObject.class.isAssignableFrom(field.getType())) {
JIRAObject jiraObject = (JIRAObject) value;
field.set(o, jiraObject.mutate(field.getType()));
} else if (value instanceof List
&& List.class.isAssignableFrom(field.getGenericType().getClass())
&& JIRAObject.class.isAssignableFrom(((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]
.getClass())) {
List<? extends JIRAObject> list = (List<? extends JIRAObject>) value;
List<JIRAObject> values = new ArrayList<JIRAObject>();
for (JIRAObject jiraObject : list) {
values.add(jiraObject.mutate((Class<? extends JIRAObject>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0]));
}
field.set(o, values);
} else {
field.set(o, value);
}
} else {
o.put(fieldName, value);
}
}
}
}