package com.google.code.joto.reflect;
import java.beans.ConstructorProperties;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
/**
*
*/
public class ConstructorJotoInfo extends MemberJotoInfo {
private static Logger log = LoggerFactory.getLogger(ConstructorJotoInfo.class);
private final Constructor<?> targetConstructor;
private List<ParamToFieldInfo> paramToFieldInfos = new ArrayList<ParamToFieldInfo>();
// -------------------------------------------------------------------------
public ConstructorJotoInfo(ClassJotoInfo parent, Constructor<?> targetConstructor) {
super(parent);
this.targetConstructor = targetConstructor;
Class<?>[] paramTypes = targetConstructor.getParameterTypes();
int paramLength = paramTypes.length;
if (paramLength != 0) {
Field[] paramToFields = new Field[paramLength];
boolean resolve = resolveNonAmbiguousFields(paramToFields);
if (!resolve) {
resolveInfosUsingConstructorPropertiesAnnotation(paramToFields);
}
for(int i = 0; i < paramLength; i++) {
paramToFieldInfos.add(new ParamToFieldInfo(paramTypes[i], paramToFields[i]));
}
}
}
// -------------------------------------------------------------------------
public Constructor<?> getTargetConstructor() {
return targetConstructor;
}
public List<ParamToFieldInfo> getParamToFieldInfos() {
return paramToFieldInfos;
}
public boolean isPublic() {
return // targetConstructor.isAccessible() &&
Modifier.isPublic(targetConstructor.getModifiers());
}
public boolean isParamToFieldInfosComplete() {
int paramLenght = targetConstructor.getParameterTypes().length;
if (paramLenght == 0) {
return true;
}
if (paramToFieldInfos == null || paramToFieldInfos.size() != paramLenght) {
return false;
}
boolean res = true;
for(ParamToFieldInfo paramToFieldInfo : paramToFieldInfos) {
if (paramToFieldInfo == null || paramToFieldInfo.getTargetAssignedField() == null) {
res = false;
break;
}
}
return res;
}
private boolean resolveNonAmbiguousFields(Field[] paramToFields) {
boolean res = true;
Class<?> targetClass = parent.getTargetClass();
Class<?>[] paramTypes = targetConstructor.getParameterTypes();
int len = paramTypes.length;
for(int i = 0; i < len; i++) {
Class<?> paramType = paramTypes[i];
// find if type is assignable to a field, without ambiguity
List<Field> assignableFields = ReflectUtils.findAssignableFieldsForValueType(targetClass, paramType);
if (assignableFields.size() == 1) {
// ok, found a non ambiguous field
paramToFields[i] = assignableFields.get(0);
} else {
res = false; // at least one not found / ambiguous field
}
}
return res;
}
private boolean resolveInfosUsingConstructorPropertiesAnnotation(Field[] paramToFields) {
boolean res = false;
ConstructorProperties ctorPropAnnotation = (ConstructorProperties)
targetConstructor.getAnnotation(ConstructorProperties.class);
if (ctorPropAnnotation != null) {
res = true;
String[] ctorPropValues = ctorPropAnnotation.value();
Class<?> targetClass = parent.getTargetClass();
ReflectionProvider rp = ReflectUtils.getReflectionProvider();
for(int i = 0; i < ctorPropValues.length; i++) {
String ctorPropValue = ctorPropValues[i];
Field f;
try {
f = rp.getField(targetClass, ctorPropValue);
} catch(Exception ex) {
log.warn("Failed to get field for ctor parameter annotation: " + targetClass
+ ", param" + i + " -> field? " + ctorPropValue, ex);
f = null;
}
if (f == null) {
res = false;
}
paramToFields[i] = f;
}
} // else annotation not found!
return res;
}
}