package org.springframework.roo.classpath.details.annotations;
import static org.springframework.roo.model.JpaJavaType.COLUMN;
import static org.springframework.roo.model.JpaJavaType.EMBEDDED;
import static org.springframework.roo.model.JpaJavaType.EMBEDDED_ID;
import static org.springframework.roo.model.JpaJavaType.ENUMERATED;
import static org.springframework.roo.model.JpaJavaType.ID;
import static org.springframework.roo.model.JpaJavaType.LOB;
import static org.springframework.roo.model.JpaJavaType.MANY_TO_MANY;
import static org.springframework.roo.model.JpaJavaType.MANY_TO_ONE;
import static org.springframework.roo.model.JpaJavaType.ONE_TO_MANY;
import static org.springframework.roo.model.JpaJavaType.ONE_TO_ONE;
import static org.springframework.roo.model.JpaJavaType.TRANSIENT;
import static org.springframework.roo.model.JpaJavaType.VERSION;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import org.springframework.roo.classpath.details.comments.CommentStructure;
import org.springframework.roo.model.Builder;
import org.springframework.roo.model.EnumDetails;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
/**
* Builder for {@link AnnotationMetadata}.
* <p>
* The "add" method will replace any existing annotation attribute with the same
* name, taking care to preserve its location.
*
* @author Ben Alex
* @author Andrew Swan
* @since 1.1
*/
public class AnnotationMetadataBuilder implements Builder<AnnotationMetadata> {
public static final AnnotationMetadata JPA_COLUMN_ANNOTATION = getInstance(COLUMN);
public static final AnnotationMetadata JPA_EMBEDDED_ANNOTATION = getInstance(EMBEDDED);
public static final AnnotationMetadata JPA_EMBEDDED_ID_ANNOTATION = getInstance(EMBEDDED_ID);
public static final AnnotationMetadata JPA_ENUMERATED_ANNOTATION = getInstance(ENUMERATED);
public static final AnnotationMetadata JPA_ID_ANNOTATION = getInstance(ID);
public static final AnnotationMetadata JPA_LOB_ANNOTATION = getInstance(LOB);
public static final AnnotationMetadata JPA_MANY_TO_MANY_ANNOTATION = getInstance(MANY_TO_MANY);
public static final AnnotationMetadata JPA_MANY_TO_ONE_ANNOTATION = getInstance(MANY_TO_ONE);
public static final AnnotationMetadata JPA_ONE_TO_MANY_ANNOTATION = getInstance(ONE_TO_MANY);
public static final AnnotationMetadata JPA_ONE_TO_ONE_ANNOTATION = getInstance(ONE_TO_ONE);
public static final AnnotationMetadata JPA_TRANSIENT_ANNOTATION = getInstance(TRANSIENT);
public static final AnnotationMetadata JPA_VERSION_ANNOTATION = getInstance(VERSION);
/**
* Returns the metadata for the existing annotation, with no attribute
* values
*
* @param annotationType the annotation type (required)
* @return a non-<code>null</code> instance
* @since 1.2.0
*/
public static AnnotationMetadata getInstance(final Class<?> annotationType) {
return new AnnotationMetadataBuilder(annotationType).build();
}
public static AnnotationMetadata getInstance(final JavaType annotationType) {
return new AnnotationMetadataBuilder(annotationType).build();
}
public static AnnotationMetadataBuilder getInstance(final JavaType annotationType,
final Collection<AnnotationAttributeValue<?>> attributeValues) {
return new AnnotationMetadataBuilder(annotationType, attributeValues);
}
/**
* Returns the metadata for the existing annotation, with no attribute
* values
*
* @param annotationType the fully-qualified name of the annotation type
* (required)
* @return a non-<code>null</code> instance
* @since 1.2.0
*/
public static AnnotationMetadata getInstance(final String annotationType) {
return new AnnotationMetadataBuilder(annotationType).build();
}
private JavaType annotationType;
private final Map<String, AnnotationAttributeValue<?>> attributeValues =
new LinkedHashMap<String, AnnotationAttributeValue<?>>();
private CommentStructure commentStructure;
/**
* Constructor. The caller must set the annotation type via
* {@link #setAnnotationType(JavaType)} before calling {@link #build()}
*/
public AnnotationMetadataBuilder() {}
/**
* Constructor for using an existing {@link AnnotationMetadata} as a
* baseline for building a new instance.
*
* @param existing required
*/
public AnnotationMetadataBuilder(final AnnotationMetadata existing) {
Validate.notNull(existing);
annotationType = existing.getAnnotationType();
for (final JavaSymbolName attributeName : existing.getAttributeNames()) {
attributeValues.put(attributeName.getSymbolName(), existing.getAttribute(attributeName));
}
this.setCommentStructure(existing.getCommentStructure());
}
/**
* Constructor for no initial attribute values
*
* @param annotationType the annotation class (required)
* @since 1.2.0
*/
public AnnotationMetadataBuilder(final Class<?> annotationType) {
this(new JavaType(annotationType));
}
/**
* Constructor for no initial attribute values
*
* @param annotationType
*/
public AnnotationMetadataBuilder(final JavaType annotationType) {
this.annotationType = annotationType;
}
/**
* Constructor that accepts an optional list of values
*
* @param annotationType
* @param attributeValues can be <code>null</code>
*/
public AnnotationMetadataBuilder(final JavaType annotationType,
final Collection<AnnotationAttributeValue<?>> attributeValues) {
this.annotationType = annotationType;
setAttributes(attributeValues);
}
/**
* Constructor for no initial attribute values
*
* @param annotationType the fully-qualified name of the annotation type
* (required)
*/
public AnnotationMetadataBuilder(final String annotationType) {
this(new JavaType(annotationType));
}
public void addAttribute(final AnnotationAttributeValue<?> value) {
// Locate existing attribute with this key and replace it
attributeValues.put(value.getName().getSymbolName(), value);
}
public void addBooleanAttribute(final String key, final boolean value) {
addAttribute(new BooleanAttributeValue(new JavaSymbolName(key), value));
}
public void addCharAttribute(final String key, final char value) {
addAttribute(new CharAttributeValue(new JavaSymbolName(key), value));
}
/**
* Adds an attribute with the given {@link JavaType} as its value
*
* @param key the attribute name (required)
* @param javaType the value (required)
*/
public void addClassAttribute(final String key, final JavaType javaType) {
addAttribute(new ClassAttributeValue(new JavaSymbolName(key), javaType));
}
public void addClassAttribute(final String key, final String fullyQualifiedTypeName) {
addAttribute(new ClassAttributeValue(new JavaSymbolName(key), new JavaType(
fullyQualifiedTypeName)));
}
public void addDoubleAttribute(final String key, final double value,
final boolean floatingPrecisionOnly) {
addAttribute(new DoubleAttributeValue(new JavaSymbolName(key), value, floatingPrecisionOnly));
}
public void addEnumAttribute(final String key, final EnumDetails details) {
addAttribute(new EnumAttributeValue(new JavaSymbolName(key), details));
}
public void addEnumAttribute(final String key, final JavaType javaType,
final JavaSymbolName enumConstant) {
final EnumDetails details = new EnumDetails(javaType, enumConstant);
addAttribute(new EnumAttributeValue(new JavaSymbolName(key), details));
}
public void addEnumAttribute(final String key, final JavaType javaType, final String enumConstant) {
final EnumDetails details = new EnumDetails(javaType, new JavaSymbolName(enumConstant));
addAttribute(new EnumAttributeValue(new JavaSymbolName(key), details));
}
public void addEnumAttribute(final String key, final String fullyQualifiedTypeName,
final String enumConstant) {
final EnumDetails details =
new EnumDetails(new JavaType(fullyQualifiedTypeName), new JavaSymbolName(enumConstant));
addAttribute(new EnumAttributeValue(new JavaSymbolName(key), details));
}
public void addIntegerAttribute(final String key, final int value) {
addAttribute(new IntegerAttributeValue(new JavaSymbolName(key), value));
}
public void addLongAttribute(final String key, final long value) {
addAttribute(new LongAttributeValue(new JavaSymbolName(key), value));
}
public void addStringAttribute(final String key, final String value) {
addAttribute(new StringAttributeValue(new JavaSymbolName(key), value));
}
public AnnotationMetadata build() {
DefaultAnnotationMetadata annotationMetadata =
new DefaultAnnotationMetadata(getAnnotationType(),
new ArrayList<AnnotationAttributeValue<?>>(getAttributes().values()));
annotationMetadata.setCommentStructure(commentStructure);
return annotationMetadata;
}
public JavaType getAnnotationType() {
return annotationType;
}
public Map<String, AnnotationAttributeValue<?>> getAttributes() {
return attributeValues;
}
public void removeAttribute(final String key) {
// Locate existing attribute with this key and replace it
attributeValues.remove(key);
}
public void setAnnotationType(final JavaType annotationType) {
this.annotationType = annotationType;
}
/**
* Sets the attribute values
*
* @param attributeValues the values to set; can be <code>null</code> for
* none
*/
public void setAttributes(final Collection<AnnotationAttributeValue<?>> attributeValues) {
this.attributeValues.clear();
if (attributeValues != null) {
for (final AnnotationAttributeValue<?> attributeValue : attributeValues) {
addAttribute(attributeValue);
}
}
}
public CommentStructure getCommentStructure() {
return commentStructure;
}
public void setCommentStructure(CommentStructure commentStructure) {
this.commentStructure = commentStructure;
}
}