package org.springframework.roo.classpath.details;
import static org.springframework.roo.classpath.PhysicalTypeCategory.CLASS;
import static org.springframework.roo.classpath.PhysicalTypeCategory.ENUMERATION;
import static org.springframework.roo.classpath.PhysicalTypeCategory.INTERFACE;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.roo.classpath.PhysicalTypeCategory;
import org.springframework.roo.classpath.customdata.CustomDataKeys;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
import org.springframework.roo.model.CustomData;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
/**
* Default representation of a {@link ClassOrInterfaceTypeDetails}.
*
* @author Ben Alex
* @author Juan Carlos GarcĂa
* @since 1.0
*/
public class DefaultClassOrInterfaceTypeDetails extends AbstractMemberHoldingTypeDetails implements
ClassOrInterfaceTypeDetails {
private List<ConstructorMetadata> declaredConstructors = new ArrayList<ConstructorMetadata>();
private List<FieldMetadata> declaredFields = new ArrayList<FieldMetadata>();
private List<InitializerMetadata> declaredInitializers = new ArrayList<InitializerMetadata>();
private List<ClassOrInterfaceTypeDetails> declaredInnerTypes =
new ArrayList<ClassOrInterfaceTypeDetails>();
private List<MethodMetadata> declaredMethods = new ArrayList<MethodMetadata>();
private List<JavaSymbolName> enumConstants = new ArrayList<JavaSymbolName>();
private List<JavaType> extendsTypes = new ArrayList<JavaType>();
private List<JavaType> implementsTypes = new ArrayList<JavaType>();
private final JavaType name;
private final PhysicalTypeCategory physicalTypeCategory;
private Set<ImportMetadata> registeredImports = new HashSet<ImportMetadata>();
private final ClassOrInterfaceTypeDetails superclass;
/**
* Constructor is package protected to mandate the use of
* {@link ClassOrInterfaceTypeDetailsBuilder}
*
* @param customData
* @param declaredByMetadataId
* @param modifier
* @param annotations
* @param name
* @param physicalTypeCategory
* @param declaredConstructors
* @param declaredFields
* @param declaredMethods
* @param declaredInnerTypes
* @param declaredInitializers
* @param superclass
* @param extendsTypes
* @param implementsTypes
* @param enumConstants
* @param registeredImports
*/
public DefaultClassOrInterfaceTypeDetails(final CustomData customData,
final String declaredByMetadataId, final int modifier,
final List<AnnotationMetadata> annotations, final JavaType name,
final PhysicalTypeCategory physicalTypeCategory,
final List<ConstructorMetadata> declaredConstructors,
final List<FieldMetadata> declaredFields, final List<MethodMetadata> declaredMethods,
final List<ClassOrInterfaceTypeDetails> declaredInnerTypes,
final List<InitializerMetadata> declaredInitializers,
final ClassOrInterfaceTypeDetails superclass, final List<JavaType> extendsTypes,
final List<JavaType> implementsTypes, final List<JavaSymbolName> enumConstants,
final Collection<ImportMetadata> registeredImports) {
super(customData, declaredByMetadataId, modifier, annotations);
Validate.notNull(name, "Name required");
Validate.notNull(physicalTypeCategory, "Physical type category required");
this.name = name;
this.physicalTypeCategory = physicalTypeCategory;
this.superclass = superclass;
if (declaredConstructors != null) {
this.declaredConstructors = declaredConstructors;
}
if (declaredFields != null) {
this.declaredFields = declaredFields;
}
if (declaredMethods != null) {
this.declaredMethods = declaredMethods;
}
if (declaredInnerTypes != null) {
this.declaredInnerTypes = declaredInnerTypes;
}
if (declaredInitializers != null) {
this.declaredInitializers = declaredInitializers;
}
if (extendsTypes != null) {
this.extendsTypes = extendsTypes;
}
if (implementsTypes != null) {
this.implementsTypes = implementsTypes;
}
if (enumConstants != null && physicalTypeCategory == ENUMERATION) {
this.enumConstants = enumConstants;
}
this.registeredImports = new HashSet<ImportMetadata>();
if (registeredImports != null) {
this.registeredImports.addAll(registeredImports);
}
}
public boolean declaresField(final JavaSymbolName fieldName) {
return getDeclaredField(fieldName) != null;
}
public boolean extendsType(final JavaType type) {
return extendsTypes.contains(type);
}
public List<? extends ConstructorMetadata> getDeclaredConstructors() {
return Collections.unmodifiableList(declaredConstructors);
}
public List<? extends FieldMetadata> getDeclaredFields() {
return Collections.unmodifiableList(declaredFields);
}
public List<InitializerMetadata> getDeclaredInitializers() {
return Collections.unmodifiableList(declaredInitializers);
}
public List<ClassOrInterfaceTypeDetails> getDeclaredInnerTypes() {
return Collections.unmodifiableList(declaredInnerTypes);
}
public List<? extends MethodMetadata> getDeclaredMethods() {
return Collections.unmodifiableList(declaredMethods);
}
@SuppressWarnings("unchecked")
public List<String> getDynamicFinderNames() {
final List<String> dynamicFinders = new ArrayList<String>();
final Object finders = getCustomData().get(CustomDataKeys.DYNAMIC_FINDER_NAMES);
if (finders instanceof Collection) {
dynamicFinders.addAll((Collection<String>) finders);
}
return dynamicFinders;
}
public List<JavaSymbolName> getEnumConstants() {
return Collections.unmodifiableList(enumConstants);
}
public List<JavaType> getExtendsTypes() {
return Collections.unmodifiableList(extendsTypes);
}
public List<JavaType> getImplementsTypes() {
return Collections.unmodifiableList(implementsTypes);
}
@Override
public Set<ImportMetadata> getImports() {
return registeredImports;
}
public JavaType getName() {
return getType();
}
public PhysicalTypeCategory getPhysicalTypeCategory() {
return physicalTypeCategory;
}
public Set<ImportMetadata> getRegisteredImports() {
return Collections.unmodifiableSet(registeredImports);
}
public ClassOrInterfaceTypeDetails getSuperclass() {
return superclass;
}
public JavaType getType() {
return name;
}
public boolean implementsAny(final JavaType... types) {
for (final JavaType type : types) {
if (implementsTypes.contains(type)) {
return true;
}
}
return false;
}
public boolean isAbstract() {
return physicalTypeCategory == INTERFACE || physicalTypeCategory == CLASS
&& Modifier.isAbstract(getModifier());
}
public boolean isInterface() {
return physicalTypeCategory.equals(INTERFACE);
}
@Override
public String toString() {
final ToStringBuilder builder = new ToStringBuilder(this);
builder.append("name", name);
builder.append("modifier", Modifier.toString(getModifier()));
builder.append("physicalTypeCategory", physicalTypeCategory);
builder.append("declaredByMetadataId", getDeclaredByMetadataId());
builder.append("declaredConstructors", declaredConstructors);
builder.append("declaredFields", declaredFields);
builder.append("declaredMethods", declaredMethods);
builder.append("enumConstants", enumConstants);
builder.append("superclass", superclass);
builder.append("extendsTypes", extendsTypes);
builder.append("implementsTypes", implementsTypes);
builder.append("annotations", getAnnotations());
builder.append("customData", getCustomData());
return builder.toString();
}
}