* @param blueprint {@link Blueprint}
* @throws RegisterBlueprintException
*/
public void registerBlueprint(Object blueprint) throws RegisterBlueprintException {
Blueprint blueprintAnnotation = blueprint.getClass().getAnnotation(Blueprint.class);
if (blueprintAnnotation == null) {
throw new RegisterBlueprintException("Blueprint class not annotated by @Blueprint: " + blueprint);
}
Class target = blueprintAnnotation.value();
List<ModelField> modelFields = new ArrayList<ModelField>();
logger.debug("Registering {} blueprint for {}", blueprint.getClass(), target);
Constructable newInstance = null;
List<Callback> afterCreateCallbacks = new ArrayList<Callback>();
// Get all fields for the blueprint target class
Collection<Field> fields = getAllFields(blueprint.getClass()).values();
for (Field field : fields) {
field.setAccessible(true);
// Register ConstructorCallback field
if ( field.getType().equals(ConstructorCallback.class) || field.getType().equals(com.tobedevoured.modelcitizen.callback.ConstructorCallback.class)) {
Object fieldVal = null;
try {
fieldVal = field.get(blueprint);
} catch (IllegalArgumentException e) {
throw new RegisterBlueprintException(e);
} catch (IllegalAccessException e) {
throw new RegisterBlueprintException(e);
}
if (fieldVal instanceof Constructable) {
logger.debug("Registering ConstructorCallback for {}", blueprint.getClass());
newInstance = (Constructable) fieldVal;
} else {
throw new RegisterBlueprintException("Blueprint " + blueprint.getClass().getSimpleName() + " Field class for " + field.getName() + " is invalid ConstructorCallback");
}
// ConstructorCallback is only used to create new instance.
continue;
}
// Register AfterCreateCallback field
if ( field.getType().equals(AfterCreateCallback.class) ) {
Object fieldVal = null;
try {
fieldVal = field.get(blueprint);
} catch (IllegalArgumentException e) {
throw new RegisterBlueprintException(e);
} catch (IllegalAccessException e) {
throw new RegisterBlueprintException(e);
}
if (fieldVal instanceof AfterCreateCallback) {
logger.debug("Registering AfterCreateCallback for {}", blueprint.getClass());
afterCreateCallbacks.add((AfterCreateCallback)fieldVal);
} else {
throw new RegisterBlueprintException("Blueprint " + blueprint.getClass().getSimpleName() + " Field class for " + field.getName() + " is invalid AfterCreateCallback");
}
// AfterCreateCallback is only used in callbacks
continue;
}
// Process @Default
Default defaultAnnotation = field.getAnnotation(Default.class);
if (defaultAnnotation != null) {
DefaultField defaultField = new DefaultField();
defaultField.setName(field.getName());
defaultField.setForce(defaultAnnotation.force());
try {
defaultField.setValue(field.get(blueprint));
} catch (IllegalArgumentException e) {
throw new RegisterBlueprintException(e);
} catch (IllegalAccessException e) {
throw new RegisterBlueprintException(e);
}
defaultField.setTarget(field.getType());
defaultField.setFieldClass(field.getType());
modelFields.add(defaultField);
logger.trace(" Setting default for {} to {} and forced {}", new Object[]{defaultField.getName(), defaultField.getValue(), defaultField.isForce()});
}
// Process @Mapped
Mapped mapped = field.getAnnotation(Mapped.class);
if (mapped != null) {
MappedField mappedField = new MappedField();
mappedField.setName(field.getName());
if (field.getAnnotation(Nullable.class) != null) {
mappedField.setNullable(true);
}
// If @Mapped(target) not set, use Field's class
if (NotSet.class.equals(mapped.target())) {
mappedField.setTarget(field.getType());
// Use @Mapped(target) for MappedField#target
} else {
mappedField.setTarget(mapped.target());
}
mappedField.setFieldClass(field.getType());
modelFields.add(mappedField);
logger.trace(" Setting mapped for {} to {}", mappedField.getName(), mappedField.getTarget());
}
// Process @MappedList
MappedList mappedCollection = field.getAnnotation(MappedList.class);
if (mappedCollection != null) {
MappedListField listField = new MappedListField();
listField.setName(field.getName());
listField.setFieldClass(field.getType());
listField.setSize(mappedCollection.size());
listField.setIgnoreEmpty(mappedCollection.ignoreEmpty());
listField.setForce(mappedCollection.force());
// If @MappedList(target) not set, use Field's class
if (NotSet.class.equals(mappedCollection.target())) {
listField.setTarget(field.getType());
// Use @MappedList(target) for MappedListField#target
} else {
listField.setTarget(mappedCollection.target());
}
// If @MappedList(targetList) not set, use ArrayList
if (NotSet.class.equals(mappedCollection.targetList())) {
listField.setTargetList(ArrayList.class);
} else {
// Ensure that the targetList implements List
boolean implementsList = false;
for (Class interf : mappedCollection.targetList().getInterfaces()) {
if (List.class.equals(interf)) {
implementsList = true;
break;
}
}
if (!implementsList) {
throw new RegisterBlueprintException("@MappedList targetList must implement List for field " + field.getName());
}
listField.setTargetList(mappedCollection.targetList());
}
modelFields.add(listField);
logger.trace(" Setting mapped list for {} to {} as <{}> and forced {}", new Object[]{listField.getName(), listField.getFieldClass(), listField.getTarget(), listField.isForce()});
}
// Process @MappedSet
MappedSet mappedSet = field.getAnnotation(MappedSet.class);
if (mappedSet != null) {
MappedSetField setField = new MappedSetField();
setField.setName(field.getName());
setField.setFieldClass(field.getType());
setField.setSize(mappedSet.size());
setField.setIgnoreEmpty(mappedSet.ignoreEmpty());
setField.setForce(mappedSet.force());
// XXX: @MappedSet( target ) is required
// If @MappedSet(target) not set
if (NotSet.class.equals(mappedSet.target())) {
// XXX: incorrect, should use generic defined by Set, luckily annotation forces target to be set
setField.setTarget(field.getType());
// Use @MappedSet(target) for MappedSet#target
} else {
setField.setTarget(mappedSet.target());
}
// If @MappedSet(targetSet) not set, use HashSet
if (NotSet.class.equals(mappedSet.targetSet())) {
setField.setTargetSet(HashSet.class);
} else {
// Ensure that the targetSet implements Set
boolean implementsSet = false;
for (Class interf : mappedSet.targetSet().getInterfaces()) {
if (Set.class.equals(interf)) {
implementsSet = true;
break;
}
}
if (!implementsSet) {
throw new RegisterBlueprintException("@MappedSet targetSet must implement Set for field " + field.getName());
}
setField.setTargetSet(mappedSet.targetSet());
}
modelFields.add(setField);
logger.trace(" Setting mapped set for {} to {} as <{}> and is forced {}", new Object[]{setField.getName(), setField.getFieldClass(), setField.getTarget(), setField.isForce()});
}
}
blueprints.add(blueprint);
Class templateClass = blueprintAnnotation.template();
BlueprintTemplate template = null;
try {
template = (BlueprintTemplate)ConstructorUtils.invokeConstructor( templateClass, null );
} catch (NoSuchMethodException e) {
throw new RegisterBlueprintException( e );