if (definitionsFactory.hasDefinition(toMap.asBoxed())) {
return definitionsFactory.getDefinition(toMap.asBoxed());
}
final Set<MetaConstructor> constructors = new HashSet<MetaConstructor>();
final SimpleConstructorMapping simpleConstructorMapping = new SimpleConstructorMapping();
final MappingDefinition definition = new MappingDefinition(toMap, false);
for (MetaConstructor c : toMap.getDeclaredConstructors()) {
List<Boolean> hasMapsTos = new ArrayList<Boolean>();
if (c.getParameters().length != 0) {
for (int i = 0; i < c.getParameters().length; i++) {
final Annotation[] annotations = c.getParameters()[i].getAnnotations();
if (annotations.length == 0) {
hasMapsTos.add(false);
}
else {
boolean hasMapsTo = false;
for (Annotation a : annotations) {
if (MapsTo.class.isAssignableFrom(a.annotationType())) {
hasMapsTo = true;
MapsTo mapsTo = (MapsTo) a;
String key = mapsTo.value();
simpleConstructorMapping.mapParmToIndex(key, i, c.getParameters()[i].getType());
}
}
hasMapsTos.add(hasMapsTo);
}
}
if (hasMapsTos.contains(true) && hasMapsTos.contains(false)) {
throw new InvalidMappingException("Not all parameters of constructor " + c.asConstructor()
+ " have a @" + MapsTo.class.getSimpleName() + " annotation");
}
if (hasMapsTos.contains(true)) {
constructors.add(c);
}
}
}
final MetaConstructor constructor;
if (constructors.isEmpty()) {
constructor = toMap.getConstructor(new MetaClass[0]);
}
else if (constructors.size() > 1) {
throw new InvalidMappingException("found more than one matching constructor for mapping: "
+ toMap.getFullyQualifiedName());
}
else {
constructor = constructors.iterator().next();
}
simpleConstructorMapping.setConstructor(constructor);
definition.setInstantiationMapping(simpleConstructorMapping);
if (toMap.isEnum()) {
return definition;
}
if (simpleConstructorMapping.getMappings().length == 0) {
final Set<MetaMethod> factoryMethods = new HashSet<MetaMethod>();
final SimpleFactoryMapping simpleFactoryMapping = new SimpleFactoryMapping();
for (final MetaMethod method : toMap.getDeclaredMethods()) {
if (method.isStatic()) {
List<Boolean> hasMapsTos = new ArrayList<Boolean>();
for (int i = 0; i < method.getParameters().length; i++) {
final Annotation[] annotations = method.getParameters()[i].getAnnotations();
if (annotations.length == 0) {
hasMapsTos.add(false);
}
else {
boolean hasMapsTo = false;
for (Annotation a : annotations) {
if (MapsTo.class.isAssignableFrom(a.annotationType())) {
hasMapsTo = true;
MapsTo mapsTo = (MapsTo) a;
String key = mapsTo.value();
simpleFactoryMapping.mapParmToIndex(key, i, method.getParameters()[i].getType());
}
}
hasMapsTos.add(hasMapsTo);
}
}
if (hasMapsTos.contains(true) && hasMapsTos.contains(false)) {
throw new InvalidMappingException("Not all parameters of method " + method.asMethod()
+ " have a @" + MapsTo.class.getSimpleName() + " annotation");
}
if (hasMapsTos.contains(true)) {
factoryMethods.add(method);
}
}
}
if (factoryMethods.size() > 1) {
throw new InvalidMappingException("found more than one matching factory method for mapping: "
+ toMap.getFullyQualifiedName());
}
else if (factoryMethods.size() == 1) {
final MetaMethod method = factoryMethods.iterator().next();
simpleFactoryMapping.setMethod(method);
definition.setInheritedInstantiationMapping(simpleFactoryMapping);
}
}
if (definition.getInstantiationMapping() instanceof ConstructorMapping
&& definition.getInstantiationMapping().getMappings().length == 0) {
final MetaConstructor defaultConstructor = toMap.getDeclaredConstructor();
if (defaultConstructor == null || !defaultConstructor.isPublic()) {
throw new InvalidMappingException("there is no custom mapping or default no-arg constructor to map: "
+ toMap.getFullyQualifiedName());
}
}
final Set<String> writeKeys = new HashSet<String>();
final Set<String> readKeys = new HashSet<String>();
for (final Mapping m : simpleConstructorMapping.getMappings()) {
writeKeys.add(m.getKey());
}
for (final MetaMethod method : toMap.getDeclaredMethods()) {
if (method.isAnnotationPresent(Key.class)) {