package org.springframework.roo.classpath.scanner; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import org.springframework.roo.classpath.details.AbstractMemberHoldingTypeDetailsBuilder; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder; import org.springframework.roo.classpath.details.ConstructorMetadata; import org.springframework.roo.classpath.details.ConstructorMetadataBuilder; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.FieldMetadataBuilder; import org.springframework.roo.classpath.details.ImportMetadata; import org.springframework.roo.classpath.details.ItdTypeDetails; import org.springframework.roo.classpath.details.ItdTypeDetailsBuilder; import org.springframework.roo.classpath.details.MemberHoldingTypeDetails; import org.springframework.roo.classpath.details.MethodMetadata; import org.springframework.roo.classpath.details.MethodMetadataBuilder; import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType; import org.springframework.roo.model.CustomData; import org.springframework.roo.model.CustomDataBuilder; import org.springframework.roo.model.CustomDataKey; /** * Builder for {@link MemberDetails}. * * @author Alan Stewart * @author Ben Alex * @author James Tyrrell * @since 1.1.3 */ public class MemberDetailsBuilder { static class TypeDetailsBuilder extends AbstractMemberHoldingTypeDetailsBuilder<MemberHoldingTypeDetails> { private final MemberHoldingTypeDetails existing; protected TypeDetailsBuilder(final MemberHoldingTypeDetails existing) { super(existing); this.existing = existing; } public void addDataToConstructor(final ConstructorMetadata replacement, final CustomData customData) { // If the MIDs don't match then the proposed can't be a replacement if (!replacement.getDeclaredByMetadataId().equals(getDeclaredByMetadataId())) { return; } for (final ConstructorMetadataBuilder existingConstructor : getDeclaredConstructors()) { if (AnnotatedJavaType .convertFromAnnotatedJavaTypes(existingConstructor.getParameterTypes()).equals( AnnotatedJavaType.convertFromAnnotatedJavaTypes(replacement.getParameterTypes()))) { for (final Object key : customData.keySet()) { existingConstructor.putCustomData(key, customData.get(key)); } break; } } } public void addDataToField(final FieldMetadata replacement, final CustomData customData) { // If the MIDs don't match then the proposed can't be a replacement if (!replacement.getDeclaredByMetadataId().equals(getDeclaredByMetadataId())) { return; } for (final FieldMetadataBuilder existingField : getDeclaredFields()) { if (existingField.getFieldName().equals(replacement.getFieldName())) { for (final Object key : customData.keySet()) { existingField.putCustomData(key, customData.get(key)); } break; } } } public void addDataToMethod(final MethodMetadata replacement, final CustomData customData) { // If the MIDs don't match then the proposed can't be a replacement if (!replacement.getDeclaredByMetadataId().equals(getDeclaredByMetadataId())) { return; } for (final MethodMetadataBuilder existingMethod : getDeclaredMethods()) { if (existingMethod.getMethodName().equals(replacement.getMethodName())) { if (AnnotatedJavaType.convertFromAnnotatedJavaTypes(existingMethod.getParameterTypes()) .equals( AnnotatedJavaType.convertFromAnnotatedJavaTypes(replacement.getParameterTypes()))) { for (final Object key : customData.keySet()) { existingMethod.putCustomData(key, customData.get(key)); } break; } } } } @Override public void addImports(final Collection<ImportMetadata> imports) { throw new UnsupportedOperationException(); // No known use case } public MemberHoldingTypeDetails build() { if (existing instanceof ItdTypeDetails) { final ItdTypeDetailsBuilder itdBuilder = new ItdTypeDetailsBuilder((ItdTypeDetails) existing); // Push in all members that may have been modified itdBuilder.setDeclaredFields(getDeclaredFields()); itdBuilder.setDeclaredMethods(getDeclaredMethods()); itdBuilder.setAnnotations(getAnnotations()); itdBuilder.setCustomData(getCustomData()); itdBuilder.setDeclaredConstructors(getDeclaredConstructors()); itdBuilder.setDeclaredInitializers(getDeclaredInitializers()); itdBuilder.setDeclaredInnerTypes(getDeclaredInnerTypes()); itdBuilder.setExtendsTypes(getExtendsTypes()); itdBuilder.setImplementsTypes(getImplementsTypes()); itdBuilder.setModifier(getModifier()); return itdBuilder.build(); } else if (existing instanceof ClassOrInterfaceTypeDetails) { final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder((ClassOrInterfaceTypeDetails) existing); // Push in all members that may cidBuilder.setDeclaredFields(getDeclaredFields()); cidBuilder.setDeclaredMethods(getDeclaredMethods()); cidBuilder.setAnnotations(getAnnotations()); cidBuilder.setCustomData(getCustomData()); cidBuilder.setDeclaredConstructors(getDeclaredConstructors()); cidBuilder.setDeclaredInitializers(getDeclaredInitializers()); cidBuilder.setDeclaredInnerTypes(getDeclaredInnerTypes()); cidBuilder.setExtendsTypes(getExtendsTypes()); cidBuilder.setImplementsTypes(getImplementsTypes()); cidBuilder.setModifier(getModifier()); return cidBuilder.build(); } else { throw new IllegalStateException("Unknown instance of MemberHoldingTypeDetails"); } } } private boolean changed = false; private final Map<String, MemberHoldingTypeDetails> memberHoldingTypeDetailsMap = new LinkedHashMap<String, MemberHoldingTypeDetails>(); private final MemberDetails originalMemberDetails; private final Map<String, TypeDetailsBuilder> typeDetailsBuilderMap = new LinkedHashMap<String, TypeDetailsBuilder>(); public MemberDetailsBuilder( final Collection<? extends MemberHoldingTypeDetails> memberHoldingTypeDetailsList) { originalMemberDetails = new MemberDetailsImpl(memberHoldingTypeDetailsList); for (final MemberHoldingTypeDetails memberHoldingTypeDetails : originalMemberDetails .getDetails()) { memberHoldingTypeDetailsMap.put(memberHoldingTypeDetails.getDeclaredByMetadataId(), memberHoldingTypeDetails); } } public MemberDetailsBuilder(final MemberDetails memberDetails) { originalMemberDetails = memberDetails; for (final MemberHoldingTypeDetails memberHoldingTypeDetails : memberDetails.getDetails()) { memberHoldingTypeDetailsMap.put(memberHoldingTypeDetails.getDeclaredByMetadataId(), memberHoldingTypeDetails); } } public MemberDetails build() { if (changed) { for (final TypeDetailsBuilder typeDetailsBuilder : typeDetailsBuilderMap.values()) { memberHoldingTypeDetailsMap.put(typeDetailsBuilder.getDeclaredByMetadataId(), typeDetailsBuilder.build()); } return new MemberDetailsImpl(new ArrayList<MemberHoldingTypeDetails>( memberHoldingTypeDetailsMap.values())); } return originalMemberDetails; } private void doModification(final ConstructorMetadata constructor, final CustomData customData) { final MemberHoldingTypeDetails memberHoldingTypeDetails = memberHoldingTypeDetailsMap.get(constructor.getDeclaredByMetadataId()); if (memberHoldingTypeDetails != null) { final ConstructorMetadata matchedConstructor = memberHoldingTypeDetails.getDeclaredConstructor(AnnotatedJavaType .convertFromAnnotatedJavaTypes(constructor.getParameterTypes())); if (matchedConstructor != null && !matchedConstructor.getCustomData().keySet().containsAll(customData.keySet())) { final TypeDetailsBuilder typeDetailsBuilder = getTypeDetailsBuilder(memberHoldingTypeDetails); typeDetailsBuilder.addDataToConstructor(constructor, customData); changed = true; } } } private void doModification(final FieldMetadata field, final CustomData customData) { final MemberHoldingTypeDetails memberHoldingTypeDetails = memberHoldingTypeDetailsMap.get(field.getDeclaredByMetadataId()); if (memberHoldingTypeDetails != null) { final FieldMetadata matchedField = memberHoldingTypeDetails.getField(field.getFieldName()); if (matchedField != null && !matchedField.getCustomData().keySet().containsAll(customData.keySet())) { final TypeDetailsBuilder typeDetailsBuilder = getTypeDetailsBuilder(memberHoldingTypeDetails); typeDetailsBuilder.addDataToField(field, customData); changed = true; } } } private void doModification(final MemberHoldingTypeDetails type, final CustomData customData) { final MemberHoldingTypeDetails memberHoldingTypeDetails = memberHoldingTypeDetailsMap.get(type.getDeclaredByMetadataId()); if (memberHoldingTypeDetails != null) { if (memberHoldingTypeDetails.getName().equals(type.getName()) && !memberHoldingTypeDetails.getCustomData().keySet().containsAll(customData.keySet())) { final TypeDetailsBuilder typeDetailsBuilder = getTypeDetailsBuilder(memberHoldingTypeDetails); typeDetailsBuilder.getCustomData().append(customData); changed = true; } } } private void doModification(final MethodMetadata method, final CustomData customData) { final MemberHoldingTypeDetails memberHoldingTypeDetails = memberHoldingTypeDetailsMap.get(method.getDeclaredByMetadataId()); if (memberHoldingTypeDetails != null) { final MethodMetadata matchedMethod = memberHoldingTypeDetails.getMethod(method.getMethodName(), AnnotatedJavaType.convertFromAnnotatedJavaTypes(method.getParameterTypes())); if (matchedMethod != null && !matchedMethod.getCustomData().keySet().containsAll(customData.keySet())) { final TypeDetailsBuilder typeDetailsBuilder = getTypeDetailsBuilder(memberHoldingTypeDetails); typeDetailsBuilder.addDataToMethod(method, customData); changed = true; } } } private TypeDetailsBuilder getTypeDetailsBuilder( final MemberHoldingTypeDetails memberHoldingTypeDetails) { if (typeDetailsBuilderMap.containsKey(memberHoldingTypeDetails.getDeclaredByMetadataId())) { return typeDetailsBuilderMap.get(memberHoldingTypeDetails.getDeclaredByMetadataId()); } final TypeDetailsBuilder typeDetailsBuilder = new TypeDetailsBuilder(memberHoldingTypeDetails); typeDetailsBuilderMap.put(memberHoldingTypeDetails.getDeclaredByMetadataId(), typeDetailsBuilder); return typeDetailsBuilder; } public <T> void tag(final T toModify, final CustomDataKey<T> key, final Object value) { if (toModify instanceof FieldMetadata) { final CustomDataBuilder customDataBuilder = new CustomDataBuilder(); customDataBuilder.put(key, value); doModification((FieldMetadata) toModify, customDataBuilder.build()); } else if (toModify instanceof MethodMetadata) { final CustomDataBuilder customDataBuilder = new CustomDataBuilder(); customDataBuilder.put(key, value); doModification((MethodMetadata) toModify, customDataBuilder.build()); } else if (toModify instanceof ConstructorMetadata) { final CustomDataBuilder customDataBuilder = new CustomDataBuilder(); customDataBuilder.put(key, value); doModification((ConstructorMetadata) toModify, customDataBuilder.build()); } else if (toModify instanceof MemberHoldingTypeDetails) { final CustomDataBuilder customDataBuilder = new CustomDataBuilder(); customDataBuilder.put(key, value); doModification((MemberHoldingTypeDetails) toModify, customDataBuilder.build()); } } }