I am building an active annotation to get rid of some boilerplate from my Xtend source files.
The following is the snippet of the source code of my AbstractFieldProcessor.
package dynamic
import java.lang.annotation.ElementType
import java.lang.annotation.Target
import org.eclipse.xtend.lib.macro.AbstractFieldProcessor
import org.eclipse.xtend.lib.macro.Active
import org.eclipse.xtend.lib.macro.TransformationContext
import org.eclipse.xtend.lib.macro.declaration.MutableFieldDeclaration
@Target(ElementType.FIELD)
@Active(DynamicCarmenFieldProcessor)
annotation DynamicCarmenField
{
String xpath
String prefix;
String suffix;
}
class DynamicCarmenFieldProcessor extends AbstractFieldProcessor {
override doTransform(MutableFieldDeclaration field, extension TransformationContext context)
{
if (!field.type.toString.equals("WebElement"))
field.addError("Only Type WebElement is supported by @Dynamic")
if (field.initializer != null)
field.addError("Initialisers are not supported by @Dynamic ")
var annotations = field.getAnnotations()
var xpath = "";
var suffix = "";
var prefix = "";
for(annotation:annotations)
{
if(annotation.annotationTypeDeclaration.simpleName == "DynamicCarmenField")
{
xpath = annotation.getStringValue("xpath")
suffix = annotation.getStringValue("suffix")
prefix = annotation.getStringValue("prefix")
}
}
val xpa = xpath
val suf = suffix
val pre = prefix
field.declaringType.addMethod('click' + field.simpleName.toFirstUpper)
[
body =
'''
WebElement webElement = driver.findElement(By.xpath("«xpa»"));
String dependentOnId = webElement.getAttribute("id");
String «field.simpleName»Id ="«pre»"+ dependentOnId +"«suf»";
«field.simpleName» = driver.findElement(By.id(«field.simpleName»Id));
«field.simpleName».click();
'''
]
field.declaringType.addMethod('set'+ field.simpleName.toFirstUpper +'Input' )
[
var stringType = context.findTypeGlobally("String")
addParameter("values",context.newTypeReference(stringType))
body=
'''
this.click«field.simpleName.toFirstUpper»();
«field.simpleName»Input.sendKeys(values);
'''
]
}
}
This code is ok. Now I try to use it as follows in the following TestFile I get an error message. I have determined that the problem is because the Generated Java Code does not contain all of the imports.
package dynamic
import org.openqa.selenium.WebDriver
import org.openqa.selenium.WebElement
import org.openqa.selenium.support.FindBy
class DynamicCarmenFieldExample
{
WebDriver driver
@DynamicCarmenField(xpath="//table[@datatable='1' and @summary!='Question Administration']" , prefix="1", suffix="_Sequence")
WebElement answerSequenceField
@FindBy(id="1_Sequence")
WebElement answerSequenceFieldInput
}
Below is the generated Java Code.
import dynamic.DynamicCarmenField;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
@SuppressWarnings("all")
public class DynamicCarmenFieldExample {
private WebDriver driver;
@DynamicCarmenField(xpath = "//table[@datatable=\'1\' and @summary!=\'Question Administration\']", prefix = "1", suffix = "_Sequence")
private WebElement answerSequenceField;
@FindBy(id = "1_Sequence")
private WebElement answerSequenceFieldInput;
public void clickAnswerSequenceField() {
WebElement webElement = driver.findElement(By.xpath("//table[@datatable='1' and @summary!='Question Administration']"));
String dependentOnId = webElement.getAttribute("id");
String answerSequenceFieldId ="1"+ dependentOnId +"_Sequence";
answerSequenceField = driver.findElement(By.id(answerSequenceFieldId));
answerSequenceField.click();
}
public void setAnswerSequenceFieldInput(final String values) {
this.clickAnswerSequenceField();
answerSequenceFieldInput.sendKeys(values);
}
}
The problem is that the code
import org.openqa.selenium.By
is missing from the generated Java. The code is not detecting that it needs to be included in the generated java file. I know I can get around this by importing the package and using it in the Xtend source but I want my active annotation to be able to do the imports correctly. Is this possible?
You can use TypeReferenceProvider.newTypeReference()
in the template expression:
WebElement webElement = driver.findElement(«By.newTypeReference».xpath("«xpa»"));
The other types are imported automatically because they are probably referenced by the processed type (eg. from by field, by method return type or parameter type, etc.).
Example Xtend code:
package test
import org.eclipse.xtend.lib.macro.Active
import org.eclipse.xtend.lib.macro.AbstractClassProcessor
import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration
import org.eclipse.xtend.lib.macro.TransformationContext
import java.util.Date
@Active(MyAnnotationProcessor)
annotation MyAnnotation
{
}
class MyAnnotationProcessor extends AbstractClassProcessor
{
override doTransform(MutableClassDeclaration annotatedClass, extension TransformationContext context)
{
annotatedClass.addMethod("generatedMethod") [
body = '''«Date.newTypeReference» date = new Date();'''
]
}
}
The referenced types will be imported in the generated Java code:
package test;
import java.util.Date;
import test.MyAnnotation;
@MyAnnotation
@SuppressWarnings("all")
public class MyAnnotationTest {
public void generatedMethod() {
Date date = new Date();
}
}