Upscale and Team Self-Selection
4 weeks ago
Reflections on programming and technology
private Refactoring mkRefactoring( RefactoringStatus status, IMethod methodToRename, String newName ) throws CoreException {
RenameJavaElementDescriptor desc = loadDescriptor();
desc.setJavaElement( methodToRename );
desc.setNewName( newName );
return desc.createRefactoring( status );
}
private RenameJavaElementDescriptor loadDescriptor() {
String id = IJavaRefactorings.RENAME_METHOD;
RefactoringContribution contrib = RefactoringCore.getRefactoringContribution( id );
return (RenameJavaElementDescriptor)contrib.createDescriptor();
}
RefactoringStatus status = new RefactoringStatus();
Refactoring refactoring = mkRefactoring( status, methodToRename, newName );
if( status.isOK() ) {
if( refactoring.checkAllConditions( nullMonitor() ).isOK() ) {
Change change = refactoring.createChange( nullMonitor() );
change.perform( nullMonitor() );
}
}
// ...
private IProgressMonitor nullMonitor() {
return new NullProgressMonitor();
}
Now, having about a dozen or so column description enums like this, it became a little unwieldy to add more column information (such as the alignment, i.e. LEFT, RIGHT or CENTER). Each of the enums needed another field that kept the alignment, a getter and another constructor if a sensible default value was to apply. In other words, in order to add alignment information, we still had to write a bunch of code lines into each of the enums (that is, a bunch of code lines that was practically identical for each of them). That looked unelegant to me. The elegant solution was to use a custom annotation type.enum CockpitColumnDesc implements IColumnDesc{
INDICATOR( "Indicator", LEFT, 56, true ) {
public String getLabel( CodeProportion element ) {
return element.getMetric().getLabel();
}
},
SQI( "SQI", 10, false ) {
public String getLabel( CodeProportion element ) {
// ...
}
},
// ... more enum fields
private final String headLabel;
private final int weight;
private final boolean hasImage;
CockpitColumnDesc( String headLabel, ColumnAlignment align, int weight, boolean hasImage ) {
this.headLabel = headLabel;
this.align = align;
this.weight = weight;
this.hasImage = hasImage;
}
CockpitColumnDesc( String headLabel, int weight, boolean hasImage ) {
this( headLabel, RIGHT, weight, hasImage );
}
public int getWeight() {
return weight;
}
public String getHeadLabel() {
return headLabel;
}
// ...
}
The bit about the RetentionPolicy tells the compiler to include the annotation information in the compiled code, so that it can be loaded at runtime. If someone uses your annotation like so:@Target( value = { ElementType.FIELD } )
@Retention( RetentionPolicy.RUNTIME )
public @interface UsusTreeColumn {
String header() default "";
// column weight (percentage of overall width in the table that this column takes)
int weight() default 5;
ColumnAlignment align() default ColumnAlignment.LEFT;
}
you can reach the info in the annotation this way:@UsusTreeColumn( header = "SQI", align = RIGHT, weight = 10 )
SQI( false ) {
public String getLabel( CodeProportion element ) {
// ...
}
}
try {
Field field = loadField( "SQI" );
for( Annotation annotation : field.getAnnotations() ) {
if( annotation instanceof UsusTreeColumn ) {
UsusTreeColumn column = (UsusTreeColumn)annotation;
String header = column.header();
// ...
}
}
} catch( NoSuchFieldException nosufex ) {
// ...
}
// ...
private Field loadField() throws NoSuchFieldException {
Class enumClass = columnDescEnumValue.getClass();
if( enumClass.isAnonymousClass() ) {
enumClass = enumClass.getEnclosingClass();
}
return enumClass.getDeclaredField( columnDescEnumValue.toString() );
}
enum CockpitColumnDesc implements IColumnDesc{
@UsusTreeColumn( header = "Indicator", weight = 56 )
INDICATOR( true ) {
public String getLabel( CodeProportion element ) {
return element.getMetric().getLabel();
}
},
@UsusTreeColumn( header = "SQI", align = RIGHT, weight = 10 )
SQI( false ) {
public String getLabel( CodeProportion element ) {
// ...
}
}
// ...
private final boolean hasImage;
CockpitColumnDesc( boolean hasImage ) {
this.hasImage = hasImage;
}
public boolean hasImage() {
return hasImage;
}
}