ResolvedMember[] mm = impl.getDeclaredMethods();
int implModifiers = impl.getModifiers();
boolean defaultVisibilityImpl = !(Modifier.isPrivate(implModifiers)
|| Modifier.isProtected(implModifiers) || Modifier.isPublic(implModifiers));
boolean hasNoCtorOrANoArgOne = true;
ResolvedMember foundOneOfIncorrectVisibility = null;
for (int i = 0; i < mm.length; i++) {
ResolvedMember resolvedMember = mm[i];
if (resolvedMember.getName().equals("<init>")) {
hasNoCtorOrANoArgOne = false;
if (resolvedMember.getParameterTypes().length == 0) {
if (defaultVisibilityImpl) { // default
// visibility
// implementation
if (resolvedMember.isPublic() || resolvedMember.isDefault()) {
hasNoCtorOrANoArgOne = true;
} else {
foundOneOfIncorrectVisibility = resolvedMember;
}
} else if (Modifier.isPublic(implModifiers)) { // public
// implementation
if (resolvedMember.isPublic()) {
hasNoCtorOrANoArgOne = true;
} else {
foundOneOfIncorrectVisibility = resolvedMember;
}
}
}
}
if (hasNoCtorOrANoArgOne) {
break;
}
}
if (!hasNoCtorOrANoArgOne) {
if (foundOneOfIncorrectVisibility != null) {
reportError(
"@DeclareParents: defaultImpl=\""
+ defaultImplClassName
+ "\" has a no argument constructor, but it is of incorrect visibility. It must be at least as visible as the type.",
struct);
} else {
reportError("@DeclareParents: defaultImpl=\"" + defaultImplClassName
+ "\" has no public no-arg constructor", struct);
}
}
if (!fieldType.isAssignableFrom(impl)) {
reportError("@DeclareParents: defaultImpl=\"" + defaultImplClassName
+ "\" does not implement the interface '" + fieldType.toString() + "'", struct);
}
}
}
// then iterate on field interface hierarchy (not object)
boolean hasAtLeastOneMethod = false;
Iterator<ResolvedMember> methodIterator = fieldType.getMethodsIncludingIntertypeDeclarations(false, true);
while (methodIterator.hasNext()) {
ResolvedMember method = methodIterator.next();
// ResolvedMember[] methods = fieldType.getMethodsWithoutIterator(true, false, false).toArray(
// new ResolvedMember[0]);
// for (int i = 0; i < methods.length; i++) {
// ResolvedMember method = methods[i];
if (method.isAbstract()) {
// moved to be detected at weave time if the target
// doesnt implement the methods
// if (defaultImplClassName == null) {
// // non marker interface with no default impl
// provided
// reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided",
// struct);
// return false;
// }
hasAtLeastOneMethod = true;
// What we are saying here:
// We have this method 'method' and we want to put a
// forwarding method into a type that matches
// typePattern that should delegate to the version
// of the method in 'defaultImplClassName'
// Now the method may be from a supertype but the
// declaring type of the method we pass into the
// type
// munger is what is used to determine the type of
// the field that hosts the delegate instance.
// So here we create a modified method with an
// alternative declaring type so that we lookup
// the right field. See pr164016.
MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType,
defaultImplClassName, typePattern);
mdtm.setFieldType(fieldType);
mdtm.setSourceLocation(struct.enclosingType.getSourceLocation());
struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm));
}
}
// successfull so far, we thus need a bcel type munger to
// have
// a field hosting the mixin in the target type
if (hasAtLeastOneMethod && defaultImplClassName != null) {
ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, fieldType, struct.enclosingType);
struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger(
fieldHost, struct.enclosingType, typePattern)));
}
return true;