package org.springframework.roo.classpath.details; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang3.Validate; import org.springframework.roo.classpath.PhysicalTypeCategory; import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; /** * Builder for {@link ClassOrInterfaceTypeDetails}. * * @author Ben Alex * @since 1.1 */ public class ClassOrInterfaceTypeDetailsBuilder extends AbstractMemberHoldingTypeDetailsBuilder<ClassOrInterfaceTypeDetails> { private final List<JavaSymbolName> enumConstants = new ArrayList<JavaSymbolName>(); private JavaType name; private PhysicalTypeCategory physicalTypeCategory; private final Set<ImportMetadata> registeredImports = new HashSet<ImportMetadata>(); private ClassOrInterfaceTypeDetailsBuilder superclass; /** * Constructor * * @param existing */ public ClassOrInterfaceTypeDetailsBuilder(final ClassOrInterfaceTypeDetails existing) { super(existing); init(existing); } /** * Constructor * * @param declaredbyMetadataId */ public ClassOrInterfaceTypeDetailsBuilder(final String declaredbyMetadataId) { super(declaredbyMetadataId); } /** * Constructor * * @param declaredbyMetadataId * @param existing */ public ClassOrInterfaceTypeDetailsBuilder(final String declaredbyMetadataId, final ClassOrInterfaceTypeDetails existing) { super(declaredbyMetadataId, existing); init(existing); } /** * Constructor * * @param declaredbyMetadataId * @param modifier * @param name * @param physicalTypeCategory */ public ClassOrInterfaceTypeDetailsBuilder(final String declaredbyMetadataId, final int modifier, final JavaType name, final PhysicalTypeCategory physicalTypeCategory) { this(declaredbyMetadataId); setModifier(modifier); this.name = name; this.physicalTypeCategory = physicalTypeCategory; } /** * Adds the given imports to this builder, if not already present * * @param imports the imports to add; can be <code>null</code> for none * @return <code>true</code> if the state of this builder changed */ public boolean add(final Collection<ImportMetadata> imports) { if (imports == null) { return false; } return registeredImports.addAll(imports); } /** * Adds the given import to this builder * * @param importMetadata the import to add; can be <code>null</code> not to * add anything * @return <code>true</code> if the state of this builder changed */ public boolean add(final ImportMetadata importMetadata) { if (importMetadata == null) { return false; } return registeredImports.add(importMetadata); } public boolean addEnumConstant(final JavaSymbolName javaSymbolName) { return enumConstants.add(javaSymbolName); } @Override public void addImports(final Collection<ImportMetadata> imports) { if (imports != null) { registeredImports.addAll(imports); } } public ClassOrInterfaceTypeDetails build() { ClassOrInterfaceTypeDetails superclass = null; if (this.superclass != null) { superclass = this.superclass.build(); } return new DefaultClassOrInterfaceTypeDetails(getCustomData().build(), getDeclaredByMetadataId(), getModifier(), buildAnnotations(), getName(), getPhysicalTypeCategory(), buildConstructors(), buildFields(), buildMethods(), buildInnerTypes(), buildInitializers(), superclass, getExtendsTypes(), getImplementsTypes(), getEnumConstants(), getRegisteredImports()); } /** * Copies this builder's modifications into the given ITD builder * * @param targetBuilder the ITD builder to receive the additions (required) * @param governorTypeDetails the {@link ClassOrInterfaceTypeDetails} of the * governor (required) */ public void copyTo(final AbstractMemberHoldingTypeDetailsBuilder<?> targetBuilder, final ClassOrInterfaceTypeDetails governorTypeDetails) { Validate.notNull(targetBuilder, "Target builder required"); Validate.notNull(governorTypeDetails, "Governor member holding types required"); // Copy fields fieldAdditions: for (final FieldMetadataBuilder field : getDeclaredFields()) { for (final FieldMetadataBuilder targetField : targetBuilder.getDeclaredFields()) { if (targetField.getFieldType().equals(field.getFieldType()) && targetField.getFieldName().equals(field.getFieldName())) { // The field already exists, so move on continue fieldAdditions; } } if (!governorTypeDetails.declaresField(field.getFieldName())) { targetBuilder.addField(field); } } // Copy methods methodAdditions: for (final MethodMetadataBuilder method : getDeclaredMethods()) { for (final MethodMetadataBuilder targetMethod : targetBuilder.getDeclaredMethods()) { if (targetMethod.getMethodName().equals(method.getMethodName()) && targetMethod.getParameterTypes().equals(method.getParameterTypes())) { continue methodAdditions; } } targetBuilder.addMethod(method); } // Copy annotations annotationAdditions: for (final AnnotationMetadataBuilder annotation : getAnnotations()) { for (final AnnotationMetadataBuilder targetAnnotation : targetBuilder.getAnnotations()) { if (targetAnnotation.getAnnotationType().equals(annotation.getAnnotationType())) { continue annotationAdditions; } } targetBuilder.addAnnotation(annotation); } // Copy custom data if (getCustomData() != null) { targetBuilder.append(getCustomData().build()); } // Copy constructors constructorAdditions: for (final ConstructorMetadataBuilder constructor : getDeclaredConstructors()) { for (final ConstructorMetadataBuilder targetConstructor : targetBuilder .getDeclaredConstructors()) { if (targetConstructor.getParameterTypes().equals(constructor.getParameterTypes())) { continue constructorAdditions; } } targetBuilder.addConstructor(constructor); } // Copy initializers for (final InitializerMetadataBuilder initializer : getDeclaredInitializers()) { targetBuilder.addInitializer(initializer); } // Copy inner types innerTypeAdditions: for (final ClassOrInterfaceTypeDetailsBuilder innerType : getDeclaredInnerTypes()) { for (final ClassOrInterfaceTypeDetailsBuilder targetInnerType : targetBuilder .getDeclaredInnerTypes()) { if (targetInnerType.getName().equals(innerType.getName())) { continue innerTypeAdditions; } } targetBuilder.addInnerType(innerType); } // Copy extends types for (final JavaType type : getExtendsTypes()) { if (!targetBuilder.getExtendsTypes().contains(type)) { targetBuilder.addExtendsTypes(type); } } // Copy implements types for (final JavaType type : getImplementsTypes()) { if (!targetBuilder.getImplementsTypes().contains(type)) { targetBuilder.addImplementsType(type); } } // Copy imports targetBuilder.addImports(getRegisteredImports()); } public List<JavaSymbolName> getEnumConstants() { return enumConstants; } public JavaType getName() { return name; } public PhysicalTypeCategory getPhysicalTypeCategory() { return physicalTypeCategory; } /** * Returns this builder's imports * * @return a non-<code>null</code> copy */ public Set<ImportMetadata> getRegisteredImports() { return new HashSet<ImportMetadata>(registeredImports); } public ClassOrInterfaceTypeDetailsBuilder getSuperclass() { return superclass; } private void init(final ClassOrInterfaceTypeDetails existing) { name = existing.getName(); physicalTypeCategory = existing.getPhysicalTypeCategory(); if (existing.getSuperclass() != null) { superclass = new ClassOrInterfaceTypeDetailsBuilder(existing.getSuperclass()); } enumConstants.addAll(existing.getEnumConstants()); registeredImports.clear(); registeredImports.addAll(existing.getRegisteredImports()); } /** * Sets this builder's enum constants to the given collection * * @param enumConstants can be <code>null</code> for none, otherwise is * defensively copied */ public void setEnumConstants(final Collection<? extends JavaSymbolName> enumConstants) { this.enumConstants.clear(); if (enumConstants != null) { this.enumConstants.addAll(enumConstants); } } public void setName(final JavaType name) { this.name = name; } public void setPhysicalTypeCategory(final PhysicalTypeCategory physicalTypeCategory) { this.physicalTypeCategory = physicalTypeCategory; } /** * Sets this builder's imports * * @param registeredImports can be <code>null</code> for none; defensively * copied */ public void setRegisteredImports(final Collection<ImportMetadata> registeredImports) { this.registeredImports.clear(); if (registeredImports != null) { this.registeredImports.addAll(registeredImports); } } public void setSuperclass(final ClassOrInterfaceTypeDetails superclass) { setSuperclass(new ClassOrInterfaceTypeDetailsBuilder(superclass)); } public void setSuperclass(final ClassOrInterfaceTypeDetailsBuilder superclass) { this.superclass = superclass; } }