package org.springframework.roo.classpath.scanner; import static org.springframework.roo.classpath.customdata.CustomDataKeys.EMBEDDED_FIELD; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang3.Validate; import org.springframework.roo.classpath.customdata.CustomDataKeys; import org.springframework.roo.classpath.details.BeanInfoUtils; import org.springframework.roo.classpath.details.ConstructorMetadata; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.MemberFindingUtils; import org.springframework.roo.classpath.details.MemberHoldingTypeDetails; import org.springframework.roo.classpath.details.MethodMetadata; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.classpath.persistence.PersistenceMemberLocator; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.support.util.CollectionUtils; /** * Default implementation of {@link MemberDetails}. * * @author Ben Alex * @since 1.1 */ public class MemberDetailsImpl implements MemberDetails { private final List<MemberHoldingTypeDetails> details = new ArrayList<MemberHoldingTypeDetails>(); /** * Constructs a new instance. * * @param details the member holders that should be stored in this instance * (can be <code>null</code>) */ public MemberDetailsImpl(final Collection<? extends MemberHoldingTypeDetails> details) { Validate.notEmpty(details, "Member holding details required"); CollectionUtils.populate(this.details, details); } public AnnotationMetadata getAnnotation(final JavaType type) { Validate.notNull(type, "Annotation type to locate required"); for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { final AnnotationMetadata md = memberHoldingTypeDetails.getAnnotation(type); if (md != null) { return md; } } return null; } public List<ConstructorMetadata> getConstructors() { final List<ConstructorMetadata> result = new ArrayList<ConstructorMetadata>(); for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { result.addAll(memberHoldingTypeDetails.getDeclaredConstructors()); } return result; } public List<MemberHoldingTypeDetails> getDetails() { return Collections.unmodifiableList(details); } public List<String> getDynamicFinderNames() { final List<String> dynamicFinderNames = new ArrayList<String>(); for (final MemberHoldingTypeDetails mhtd : details) { dynamicFinderNames.addAll(mhtd.getDynamicFinderNames()); } return dynamicFinderNames; } public List<FieldMetadata> getFields() { final List<FieldMetadata> result = new ArrayList<FieldMetadata>(); for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { result.addAll(memberHoldingTypeDetails.getDeclaredFields()); } return result; } public MethodMetadata getMethod(final JavaSymbolName methodName) { for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { final MethodMetadata md = MemberFindingUtils.getDeclaredMethod(memberHoldingTypeDetails, methodName); if (md != null) { return md; } } return null; } public List<MethodMetadata> getMethods(final JavaSymbolName methodName) { for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { final List<MethodMetadata> md = MemberFindingUtils.getDeclaredMethods(memberHoldingTypeDetails, methodName); if (md != null && !md.isEmpty()) { return md; } } return null; } public MethodMetadata getMethod(final JavaSymbolName methodName, final List<JavaType> parameters) { for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { final MethodMetadata md = MemberFindingUtils.getDeclaredMethod(memberHoldingTypeDetails, methodName, parameters); if (md != null) { return md; } } return null; } public MethodMetadata getMethod(final JavaSymbolName methodName, final List<JavaType> parameters, final String excludingMid) { for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { final MethodMetadata method = MemberFindingUtils.getDeclaredMethod(memberHoldingTypeDetails, methodName, parameters); if (method != null && !method.getDeclaredByMetadataId().equals(excludingMid)) { return method; } } return null; } public List<MethodMetadata> getMethods() { final List<MethodMetadata> result = new ArrayList<MethodMetadata>(); for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { result.addAll(memberHoldingTypeDetails.getDeclaredMethods()); } return result; } public List<MethodMetadata> getMethodsWithTag(final Object tagKey) { Validate.notNull(tagKey, "Custom data key required"); final List<MethodMetadata> result = new ArrayList<MethodMetadata>(); for (final MethodMetadata method : getMethods()) { if (method.getCustomData().keySet().contains(tagKey)) { result.add(method); } } return result; } public MethodMetadata getMostConcreteMethodWithTag(final Object tagKey) { return CollectionUtils.firstElementOf(getMethodsWithTag(tagKey)); } public Set<JavaType> getPersistentFieldTypes(final JavaType thisType, final PersistenceMemberLocator persistenceMemberLocator) { final MethodMetadata identifierAccessor = persistenceMemberLocator.getIdentifierAccessor(thisType); final MethodMetadata versionAccessor = persistenceMemberLocator.getVersionAccessor(thisType); final Set<JavaType> fieldTypes = new LinkedHashSet<JavaType>(); for (final MethodMetadata method : getMethods()) { // Not interested in non-accessor methods or persistence identifiers // and version fields if (!BeanInfoUtils.isAccessorMethod(method) || method.hasSameName(identifierAccessor, versionAccessor)) { continue; } // Not interested in fields that are JPA transient fields or // immutable fields final FieldMetadata field = BeanInfoUtils.getFieldForJavaBeanMethod(this, method); if (field == null || field.getCustomData().keySet().contains(CustomDataKeys.TRANSIENT_FIELD) || !BeanInfoUtils.hasAccessorAndMutator(field, this)) { continue; } final JavaType returnType = method.getReturnType(); if (returnType.isCommonCollectionType()) { for (final JavaType genericType : returnType.getParameters()) { fieldTypes.add(genericType); } } else { if (!field.getCustomData().keySet().contains(EMBEDDED_FIELD)) { fieldTypes.add(returnType); } } } return fieldTypes; } public boolean isMethodDeclaredByAnother(final JavaSymbolName methodName, final List<JavaType> parameterTypes, final String declaredByMetadataId) { final MethodMetadata method = getMethod(methodName, parameterTypes); return method != null && !method.getDeclaredByMetadataId().equals(declaredByMetadataId); } public boolean isRequestingAnnotatedWith(final AnnotationMetadata annotationMetadata, final String requestingMid) { for (final MemberHoldingTypeDetails memberHoldingTypeDetails : details) { if (MemberFindingUtils.getAnnotationOfType(memberHoldingTypeDetails.getAnnotations(), annotationMetadata.getAnnotationType()) != null) { if (memberHoldingTypeDetails.getDeclaredByMetadataId().equals(requestingMid)) { return true; } } } return false; } }