package org.springframework.roo.classpath.customdata.taggers; import static org.springframework.roo.model.RooJavaType.ROO_PLURAL; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.MemberHoldingTypeDetails; import org.springframework.roo.classpath.details.MethodMetadata; import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.model.CustomDataKey; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; /** * {@link MethodMetadata} specific implementation of {@link Matcher}. Matches * are based on field name which is dynamically determined based on: the * {@link FieldMatcher}s presented; the type of method (accessor/mutator); the * default method name; the user specified method name obtained from a * particular Roo annotation; a plural/singular suffix of the referenced entity; * and, an additional suffix. * * @author James Tyrrell * @since 1.1.3 */ public class MethodMatcher implements Matcher<MethodMetadata> { private String additionalSuffix = ""; private JavaType catalystAnnotationType; private final CustomDataKey<MethodMetadata> customDataKey; private String defaultName; private final List<FieldMatcher> fieldTaggers = new ArrayList<FieldMatcher>(); private boolean isAccessor; private boolean suffixPlural; private boolean suffixSingular; private JavaSymbolName userDefinedNameAttribute; /** * Constructor * * @param fieldTaggers can be <code>null</code> for none * @param customDataKey * @param isAccessor */ public MethodMatcher(final Collection<? extends FieldMatcher> fieldTaggers, final CustomDataKey<MethodMetadata> customDataKey, final boolean isAccessor) { this.customDataKey = customDataKey; this.isAccessor = isAccessor; if (fieldTaggers != null) { this.fieldTaggers.addAll(fieldTaggers); } } /** * Constructor * * @param customDataKey * @param catalystAnnotationType * @param userDefinedNameAttribute * @param defaultName */ public MethodMatcher(final CustomDataKey<MethodMetadata> customDataKey, final JavaType catalystAnnotationType, final JavaSymbolName userDefinedNameAttribute, final String defaultName) { this.catalystAnnotationType = catalystAnnotationType; this.customDataKey = customDataKey; this.userDefinedNameAttribute = userDefinedNameAttribute; this.defaultName = defaultName; } /** * Constructor * * @param customDataKey * @param catalystAnnotationType * @param userDefinedNameAttribute * @param defaultName * @param suffixPlural * @param suffixSingular */ public MethodMatcher(final CustomDataKey<MethodMetadata> customDataKey, final JavaType catalystAnnotationType, final JavaSymbolName userDefinedNameAttribute, final String defaultName, final boolean suffixPlural, final boolean suffixSingular) { this(customDataKey, catalystAnnotationType, userDefinedNameAttribute, defaultName); this.suffixPlural = suffixPlural; this.suffixSingular = suffixSingular; } /** * Constructor * * @param customDataKey * @param catalystAnnotationType * @param userDefinedNameAttribute * @param defaultName * @param suffixPlural * @param suffixSingular * @param additionalSuffix */ public MethodMatcher(final CustomDataKey<MethodMetadata> customDataKey, final JavaType catalystAnnotationType, final JavaSymbolName userDefinedNameAttribute, final String defaultName, final boolean suffixPlural, final boolean suffixSingular, final String additionalSuffix) { this(customDataKey, catalystAnnotationType, userDefinedNameAttribute, defaultName, suffixPlural, suffixSingular); this.additionalSuffix = additionalSuffix; } public CustomDataKey<MethodMetadata> getCustomDataKey() { return customDataKey; } private List<FieldMetadata> getFieldsInterestedIn( final List<MemberHoldingTypeDetails> memberHoldingTypeDetailsList) { final List<FieldMetadata> fields = new ArrayList<FieldMetadata>(); for (final FieldMatcher fieldTagger : fieldTaggers) { fields.addAll(fieldTagger.matches(memberHoldingTypeDetailsList)); } return fields; } private ClassOrInterfaceTypeDetails getMostConcreteClassOrInterfaceTypeDetails( final List<MemberHoldingTypeDetails> memberHoldingTypeDetailsList) { ClassOrInterfaceTypeDetails cid = null; // The last ClassOrInterfaceTypeDetails is the most concrete as dictated // by the logic in MemberDetailsScannerImpl for (final MemberHoldingTypeDetails memberHoldingTypeDetails : memberHoldingTypeDetailsList) { if (memberHoldingTypeDetails instanceof ClassOrInterfaceTypeDetails) { cid = (ClassOrInterfaceTypeDetails) memberHoldingTypeDetails; } } Validate.notNull(cid, "No concrete type found; cannot continue"); return cid; } private String getPrefix() { return isAccessor ? "get" : "set"; } private String getSuffix(final List<MemberHoldingTypeDetails> memberHoldingTypeDetailsList, final boolean singular, final Map<String, String> pluralMap) { final ClassOrInterfaceTypeDetails cid = getMostConcreteClassOrInterfaceTypeDetails(memberHoldingTypeDetailsList); if (singular) { return cid.getName().getSimpleTypeName(); } String plural = pluralMap.get(cid.getDeclaredByMetadataId()); for (final AnnotationMetadata annotationMetadata : cid.getAnnotations()) { if (annotationMetadata.getAnnotationType().getFullyQualifiedTypeName() .equals(ROO_PLURAL.getFullyQualifiedTypeName())) { final AnnotationAttributeValue<?> annotationAttributeValue = annotationMetadata.getAttribute(new JavaSymbolName("value")); if (annotationAttributeValue != null) { plural = annotationAttributeValue.getValue().toString(); } break; } } if (StringUtils.isNotBlank(plural)) { plural = StringUtils.capitalize(plural); } return plural; } public Object getTagValue(final MethodMetadata key) { return null; } private JavaSymbolName getUserDefinedMethod( final List<MemberHoldingTypeDetails> memberHoldingTypeDetailsList, final Map<String, String> pluralMap) { if (catalystAnnotationType == null || userDefinedNameAttribute == null) { return null; } final String suffix = suffixPlural || suffixSingular ? getSuffix(memberHoldingTypeDetailsList, suffixSingular, pluralMap) : ""; final ClassOrInterfaceTypeDetails cid = getMostConcreteClassOrInterfaceTypeDetails(memberHoldingTypeDetailsList); for (final AnnotationMetadata annotationMetadata : cid.getAnnotations()) { if (annotationMetadata.getAnnotationType().getFullyQualifiedTypeName() .equals(catalystAnnotationType.getFullyQualifiedTypeName())) { final AnnotationAttributeValue<?> annotationAttributeValue = annotationMetadata.getAttribute(userDefinedNameAttribute); if (annotationAttributeValue != null && StringUtils.isNotBlank(annotationAttributeValue.getValue().toString())) { return new JavaSymbolName(annotationAttributeValue.getValue().toString() + suffix); } break; } } return defaultName == null ? null : new JavaSymbolName(defaultName + suffix); } public List<MethodMetadata> matches( final List<MemberHoldingTypeDetails> memberHoldingTypeDetailsList) { return null; // TODO: This needs to be dealt with -JT } public List<MethodMetadata> matches( final List<MemberHoldingTypeDetails> memberHoldingTypeDetailsList, final Map<String, String> pluralMap) { final List<FieldMetadata> fields = getFieldsInterestedIn(memberHoldingTypeDetailsList); final List<MethodMetadata> methods = new ArrayList<MethodMetadata>(); final Set<JavaSymbolName> methodNames = new HashSet<JavaSymbolName>(); final JavaSymbolName userDefinedMethodName = getUserDefinedMethod(memberHoldingTypeDetailsList, pluralMap); if (userDefinedMethodName == null) { for (final FieldMetadata field : fields) { methodNames.add(new JavaSymbolName(getPrefix() + StringUtils.capitalize(field.getFieldName().getSymbolName()))); } } else { methodNames.add(new JavaSymbolName(userDefinedMethodName.getSymbolName() + additionalSuffix)); } for (final MemberHoldingTypeDetails memberHoldingTypeDetails : memberHoldingTypeDetailsList) { for (final MethodMetadata method : memberHoldingTypeDetails.getDeclaredMethods()) { if (methodNames.contains(method.getMethodName())) { methods.add(method); } } } return methods; } }