package org.springframework.roo.addon.tostring;
import static org.springframework.roo.model.JavaType.STRING;
import java.lang.reflect.Modifier;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.itd.AbstractItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.metadata.MetadataIdentificationUtils;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.project.LogicalPath;
/**
* Metadata for {@link RooToString}.
*
* @author Ben Alex
* @since 1.0
*/
public class ToStringMetadata extends
AbstractItdTypeDetailsProvidingMetadataItem {
private static final String PROVIDES_TYPE_STRING = ToStringMetadata.class
.getName();
private static final String PROVIDES_TYPE = MetadataIdentificationUtils
.create(PROVIDES_TYPE_STRING);
private static final String STYLE = "SHORT_PREFIX_STYLE";
private static final JavaType TO_STRING_BUILDER = new JavaType(
"org.apache.commons.lang3.builder.ReflectionToStringBuilder");
private static final JavaType TO_STRING_STYLE = new JavaType(
"org.apache.commons.lang3.builder.ToStringStyle");
public static String createIdentifier(final JavaType javaType,
final LogicalPath path) {
return PhysicalTypeIdentifierNamingUtils.createIdentifier(
PROVIDES_TYPE_STRING, javaType, path);
}
public static JavaType getJavaType(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.getJavaType(
PROVIDES_TYPE_STRING, metadataIdentificationString);
}
public static String getMetadataIdentiferType() {
return PROVIDES_TYPE;
}
public static LogicalPath getPath(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.getPath(PROVIDES_TYPE_STRING,
metadataIdentificationString);
}
public static boolean isValid(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.isValid(PROVIDES_TYPE_STRING,
metadataIdentificationString);
}
private final ToStringAnnotationValues annotationValues;
/**
* Constructor
*
* @param identifier
* @param aspectName
* @param governorPhysicalTypeMetadata
* @param annotationValues
*/
public ToStringMetadata(final String identifier, final JavaType aspectName,
final PhysicalTypeMetadata governorPhysicalTypeMetadata,
final ToStringAnnotationValues annotationValues) {
super(identifier, aspectName, governorPhysicalTypeMetadata);
Validate.isTrue(
isValid(identifier),
"Metadata identification string '%s' does not appear to be a valid",
identifier);
Validate.notNull(annotationValues, "Annotation values required");
this.annotationValues = annotationValues;
// Generate the toString() method
builder.addMethod(getToStringMethod());
// Create a representation of the desired output ITD
itdTypeDetails = builder.build();
}
/**
* Obtains the "toString" method for this type, if available.
* <p>
* If the user provided a non-default name for "toString", that method will
* be returned.
*
* @return the "toString" method declared on this type or that will be
* introduced (or null if undeclared and not introduced)
*/
private MethodMetadataBuilder getToStringMethod() {
final String toStringMethod = annotationValues.getToStringMethod();
if (StringUtils.isBlank(toStringMethod)) {
return null;
}
// Compute the relevant toString method name
final JavaSymbolName methodName = new JavaSymbolName(toStringMethod);
// See if the type itself declared the method
if (governorHasMethod(methodName)) {
return null;
}
builder.getImportRegistrationResolver().addImports(TO_STRING_BUILDER,
TO_STRING_STYLE);
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
final String[] excludeFields = annotationValues.getExcludeFields();
String str;
if (excludeFields != null && excludeFields.length > 0) {
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < excludeFields.length; i++) {
if (i > 0) {
builder.append(", ");
}
builder.append("\"").append(excludeFields[i]).append("\"");
}
str = "new ReflectionToStringBuilder(this, ToStringStyle." + STYLE
+ ").setExcludeFieldNames(" + builder.toString()
+ ").toString();";
}
else {
str = "ReflectionToStringBuilder.toString(this, ToStringStyle."
+ STYLE + ");";
}
bodyBuilder.appendFormalLine("return " + str);
return new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName,
STRING, bodyBuilder);
}
@Override
public String toString() {
final ToStringBuilder builder = new ToStringBuilder(this);
builder.append("identifier", getId());
builder.append("valid", valid);
builder.append("aspectName", aspectName);
builder.append("destinationType", destination);
builder.append("governor", governorPhysicalTypeMetadata.getId());
builder.append("itdTypeDetails", itdTypeDetails);
return builder.toString();
}
}