com.googlecode.mjorm.annotations.AnnotationsObjectDescriptorParser Maven / Gradle / Ivy
package com.googlecode.mjorm.annotations;
import java.beans.BeanInfo;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bson.types.ObjectId;
import com.googlecode.mjorm.DiscriminatorType;
import com.googlecode.mjorm.MjormException;
import com.googlecode.mjorm.MappingUtil;
import com.googlecode.mjorm.ObjectDescriptor;
import com.googlecode.mjorm.ObjectIdValueGenerator;
import com.googlecode.mjorm.PropertyDescriptor;
import com.googlecode.mjorm.ReflectionUtil;
import com.googlecode.mjorm.ValueGenerator;
import com.googlecode.mjorm.convert.JavaType;
/**
* "Parses" objects with mapping annotations and
* returns {@link ObjectDescriptor}s.
*/
public class AnnotationsObjectDescriptorParser {
/**
* Parses the given {@link Class>}s and returns {@link ObjectDescriptor}s
* for them.
* @param classes the classes to parse
* @return the {@link ObjectDescriptor}s
*/
public List parseClasses(Class>... classes) {
List ret = new ArrayList();
for (Class> clazz : classes) {
ret.add(parseClass(clazz, ret));
}
return ret;
}
/**
* Parses the given {@link Class>}s and returns {@link ObjectDescriptor}s
* for them.
* @param classes the classes to parse
* @return the {@link ObjectDescriptor}s
*/
public List parseClasses(Collection> classes) {
return parseClasses(classes.toArray(new Class>[0]));
}
/**
* Parses the given {@link Class>} and returns an {@link ObjectDescriptor}
* for it.
* @param clazz the class to parse
* @return the {@link ObjectDescriptor}
*/
private ObjectDescriptor parseClass(Class> clazz, List descriptors) {
// get the entity annotation
Entity entity = clazz.getAnnotation(Entity.class);
if (entity==null) {
throw new MjormException(
clazz.getName()+" does not have an "+Entity.class.getName()+" annotation");
}
// parse entity date
String discriminatorName = entity.discriminatorName();
DiscriminatorType discriminatorType = entity.discriminatorType();
SubClass[] subClasses = entity.subClasses();
// create an object descriptor
ObjectDescriptor desc = new ObjectDescriptor();
desc.setType(clazz);
desc.setDiscriminatorName(discriminatorName);
desc.setDiscriminatorType(discriminatorType.toString());
// get BeanInfo
BeanInfo info = ReflectionUtil.getBeanInfo(clazz);
Map methodMap
= new HashMap();
for (java.beans.PropertyDescriptor pd : info.getPropertyDescriptors()) {
methodMap.put(pd.getReadMethod(), pd);
methodMap.put(pd.getWriteMethod(), pd);
}
// get all of the methods
for (Method method : clazz.getMethods()) {
// look for the annotations
Property property = method.getAnnotation(Property.class);
Id id = method.getAnnotation(Id.class);
if (property==null) {
continue;
}
// find pd
java.beans.PropertyDescriptor pd = methodMap.get(method);
if (pd==null) {
throw new MjormException(
method.getName()+" is not not a valid bean method.");
}
// "parse" data
String propField = !property.field().equals("")
? property.field()
: pd.getName();
Type propType = !property.type().equals(void.class)
? property.type()
: pd.getReadMethod().getGenericReturnType();
Type storageType = !property.storageType().equals(void.class)
? property.storageType()
: null;
Class> valueGeneratorClass = !property.valueGeneratorClass().equals(void.class)
? property.valueGeneratorClass()
: null;
Type[] genericParameterTypes = property.genericParameterTypes().length>0
? property.genericParameterTypes()
: new Type[0];
boolean propIsIdentifier = (id!=null);
boolean propIsAutoGen = (id!=null && id.autoGenerated());
// get the hints
Map hints = new HashMap();
if (property.typeConversionHints()!=null) {
for (TypeConversionHint hint : property.typeConversionHints()) {
hints.put(hint.name(), hint.stringValue());
}
}
// create the PropertyDescriptor
PropertyDescriptor prop = new PropertyDescriptor();
prop.setName(pd.getName());
prop.setFieldName(propField);
prop.setGetter(pd.getReadMethod());
prop.setSetter(pd.getWriteMethod());
prop.setIdentifier(propIsIdentifier);
prop.setType(JavaType.fromType(propType));
prop.setAutoGenerated(propIsAutoGen);
prop.setConversionHints(hints);
prop.setGenericParameterTypes(genericParameterTypes);
if (propIsAutoGen) {
ValueGenerator> valueGenerator = null;
if (valueGeneratorClass==null) {
valueGenerator = ObjectIdValueGenerator.INSTANCE;
storageType = ObjectId.class;
} else {
try {
valueGenerator = ValueGenerator.class.cast(valueGeneratorClass.newInstance());
} catch(Exception e) {
throw new IllegalArgumentException(
"Unable to create ValueGenerator for "+valueGeneratorClass.getName(), e);
}
}
prop.setValueGenerator(valueGenerator);
}
// set the storage type
if (storageType!=null) {
prop.setStorageType(JavaType.fromType(storageType));
}
// add to descriptor
desc.addPropertyDescriptor(prop);
}
// parse subclasses
for (SubClass subClassAnot : subClasses) {
// get discriminator value
Object discriminatorValue = MappingUtil.parseDiscriminator(
subClassAnot.discriminiatorValue(), discriminatorType);
// parse sub class
ObjectDescriptor subClass = parseClass(subClassAnot.entityClass(), descriptors);
// add subclass
desc.addSubClassObjectDescriptor(discriminatorValue, subClass);
descriptors.add(subClass);
}
// return it
return desc;
}
}