/*
* Copyright (c) 2013 Simon Templer
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Simon Templer - initial version
*/
package eu.esdihumboldt.util.blueprints.entities;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ConstructorNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.GenericsType;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.BinaryExpression;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.FieldExpression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.NotExpression;
import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.BlockStatement;
import org.codehaus.groovy.ast.stmt.EmptyStatement;
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.ast.stmt.IfStatement;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.syntax.Token;
import org.codehaus.groovy.syntax.Types;
import org.codehaus.groovy.transform.ASTTransformation;
import org.codehaus.groovy.transform.AbstractASTTransformUtil;
import org.codehaus.groovy.transform.GroovyASTTransformation;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
/**
* Groovy AST transformation that converts POGOs to vertex entities.
*
* @author Simon Templer
*/
@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
@SuppressWarnings("deprecation")
public class VertexEntityTransformation implements ASTTransformation {
private static final ClassNode VERTEX_CLASS = ClassHelper.make(Vertex.class);
private static final ClassNode GRAPH_CLASS = ClassHelper.make(Graph.class);
private static final ClassNode ORIENT_GRAPH_CLASS = ClassHelper.make(OrientGraph.class);
private static final ClassNode VERTEX_ENTITY_CLASS = ClassHelper.make(VertexEntity.class);
private static final ClassNode ITERABLE_CLASS = ClassHelper.make(Iterable.class);
private static final ClassNode VE_DELEGATES_CLASS = ClassHelper
.make(VertexEntityDelegates.class);
private static final ClassNode VE_ITERABLE_DELEGATE_CLASS = ClassHelper
.make(IterableDelegate.class);
private static final ClassNode VE_NON_UNIQUE_EXCEPTION = ClassHelper
.make(NonUniqueResultException.class);
private static final Token TOKEN_PLUS = Token.newSymbol(Types.PLUS, -1, -1);
@Override
public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
if (sourceUnit.getAST() == null)
return;
List<ClassNode> classes = sourceUnit.getAST().getClasses();
for (ClassNode clazz : classes) {
processClass(clazz);
}
}
/**
* Process a class and make it a vertex entity class.
*
* @param clazz the class node
*/
private void processClass(ClassNode clazz) {
// check if class already was processed (has field v)
if (clazz.getField("v") != null) {
return;
}
// find all classes annotated with @ODocumentEntity
List<AnnotationNode> entityAnnotations = clazz.getAnnotations(VERTEX_ENTITY_CLASS);
if (entityAnnotations != null && !entityAnnotations.isEmpty()) {
Expression entityName = entityAnnotations.get(0).getMember("value");
Expression typeProperty = entityAnnotations.get(0).getMember("typeProperty");
if (typeProperty == null) {
// default value if none given
typeProperty = new ConstantExpression("_type");
}
Expression superEntityName = null;
FieldNode vertexField = null;
FieldNode graphField = null;
ClassNode superClass = clazz.getSuperClass();
if (superClass != null) {
List<AnnotationNode> superAnnotations = superClass
.getAnnotations(VERTEX_ENTITY_CLASS);
if (superAnnotations != null && !superAnnotations.isEmpty()) {
// super class is also a vertex entity
superEntityName = superAnnotations.get(0).getMember("value");
// super class must be processed first
processClass(superClass);
// use fields from super class
vertexField = clazz.getField("v");
graphField = clazz.getField("g");
}
else {
superClass = null;
}
}
// add the vertex field
if (vertexField == null) {
vertexField = clazz.addField("v", Modifier.PROTECTED, VERTEX_CLASS, null);
}
// add the graph field
if (graphField == null) {
graphField = clazz.addField("g", Modifier.PROTECTED, GRAPH_CLASS, null);
}
// add constructor
clazz.addConstructor(buildVertexGraphConstructor(vertexField, graphField, superClass,
typeProperty, entityName));
Map<String, Expression> initialExpressions = new HashMap<>();
// get all non-static properties
List<PropertyNode> properties = AbstractASTTransformUtil.getInstanceProperties(clazz);
List<PropertyNode> newProperties = new ArrayList<>();
for (PropertyNode property : properties) {
// TODO check for "transient" properties?
// TODO check not allowed property names, e.g. id, v, g
// TODO decide on kind of property
// collect initial expressions for create function
if (property.getField().getInitialExpression() != null) {
initialExpressions.put(property.getName(), property.getInitialExpression());
}
// add static findByX method
clazz.addMethod(buildFindByMethod(clazz, entityName, typeProperty,
property.getName(), property.getType()));
// add static findUniqueByX method
clazz.addMethod(buildGetByMethod(clazz, entityName, typeProperty,
property.getName(), property.getType()));
// update property
property.setGetterBlock(createGetter(property.getName(), vertexField,
property.getType(), property.getField().getInitialExpression()));
property.setSetterBlock(createSetter(property.getName(), vertexField));
newProperties.add(property);
}
// readd updated properties
for (PropertyNode property : newProperties) {
readdProperty(clazz, property);
}
// add the vertex getter
clazz.addMethod("getV", Modifier.PUBLIC, VERTEX_CLASS, //
new Parameter[0], new ClassNode[0],
new ReturnStatement(new FieldExpression(vertexField)));
// add the graph getter
clazz.addMethod("getG", Modifier.PUBLIC, GRAPH_CLASS, //
new Parameter[0], new ClassNode[0],
new ReturnStatement(new FieldExpression(graphField)));
// add the id getter
clazz.addMethod("getId", Modifier.PUBLIC, ClassHelper.OBJECT_TYPE, new Parameter[0],
new ClassNode[0],
new ReturnStatement(new MethodCallExpression(new FieldExpression(vertexField),
"getId", new ArgumentListExpression())));
// add delete method
clazz.addMethod(buildDeleteMethod(vertexField, graphField));
// add static create method
clazz.addMethod(buildCreateMethod(clazz, entityName, initialExpressions));
// add static findAll method
clazz.addMethod(buildFindAllMethod(clazz, entityName, typeProperty));
// add static getById method
clazz.addMethod(buildGetByIdMethod(clazz));
// add static initGraph method
clazz.addMethod(buildInitGraphMethod(entityName, superEntityName));
}
}
/**
* Create a static method that initializes a graph. For an
* {@link OrientGraph} it registers the entity class as a schema type.
*
* @param entityName the entity name
* @param superEntityName the super entity name, may be <code>null</code>
* @return the method
*/
private MethodNode buildInitGraphMethod(Expression entityName, Expression superEntityName) {
// graph (parameter)
VariableExpression graph = new VariableExpression("graph");
if (superEntityName == null) {
superEntityName = new ConstantExpression(null);
}
BlockStatement code = new BlockStatement();
// register class
code.addStatement(new ExpressionStatement(new StaticMethodCallExpression(VE_DELEGATES_CLASS,
VertexEntityDelegates.METHOD_REGISTER_CLASS,
new ArgumentListExpression(graph, entityName, superEntityName))));
return new MethodNode("initGraph", Modifier.PUBLIC | Modifier.STATIC, ClassHelper.VOID_TYPE,
new Parameter[] { new Parameter(GRAPH_CLASS, "graph") }, new ClassNode[0], code);
}
/**
* Create a call to initGraph(Graph).
*
* @param clazz the entity class
* @param graph the graph to initialize
* @return the method call statement
*/
private Statement callInitGraph(ClassNode clazz, Expression graph) {
return new ExpressionStatement(new StaticMethodCallExpression(clazz, "initGraph",
new ArgumentListExpression(graph)));
}
/**
* Create a method the removes the entity from the graph.
*
* @param vertexField the vertex field
* @param graphField the graph field
* @return the delete method
*/
private MethodNode buildDeleteMethod(FieldNode vertexField, FieldNode graphField) {
BlockStatement code = new BlockStatement();
// > g.removeVertex(v)
code.addStatement(new ExpressionStatement(
new MethodCallExpression(new FieldExpression(graphField), "removeVertex",
new ArgumentListExpression(new FieldExpression(vertexField)))));
// reset graph field
// > g = null
code.addStatement(AbstractASTTransformUtil.assignStatement(new FieldExpression(graphField),
new ConstantExpression(null)));
return new MethodNode("delete", Modifier.PUBLIC, ClassHelper.VOID_TYPE, new Parameter[0],
new ClassNode[0], code);
}
/**
* Create a static method that allows creating a new vertex and adding it to
* a graph.
*
* @param clazz the entity class
* @param entityName the entity name
* @param initialExpressions the initial expressions per property
* @return the static create method taking a graph as an argument
*/
private MethodNode buildCreateMethod(ClassNode clazz, Expression entityName,
Map<String, Expression> initialExpressions) {
clazz = ClassHelper.make(clazz.getName());
BlockStatement code = new BlockStatement();
// graph (parameter)
VariableExpression graph = new VariableExpression("graph");
// initialize graph
code.addStatement(callInitGraph(clazz, graph));
// vertex (local variable)
VariableExpression vertex = new VariableExpression("vertex");
// id (local variable)
VariableExpression id = new VariableExpression("id");
code.addStatement(AbstractASTTransformUtil.declStatement(id, new ConstantExpression(null)));
// id = OrientGraph.CLASS_PREFIX + entityName
Statement orientBlock = AbstractASTTransformUtil.assignStatement(id, new BinaryExpression(
new ConstantExpression(OrientGraph.CLASS_PREFIX), TOKEN_PLUS, entityName));
// > if (graph instanceof OrientGraph) {
// > id = OrientGraph.CLASS_PREFIX + entityName
// > }
code.addStatement(
new IfStatement(AbstractASTTransformUtil.isInstanceOf(graph, ORIENT_GRAPH_CLASS),
orientBlock, new EmptyStatement()));
// > vertex = graph.addVertex(id)
Statement assignVertex = AbstractASTTransformUtil.declStatement(vertex,
new MethodCallExpression(graph, new ConstantExpression("addVertex"),
new ArgumentListExpression(id)));
code.addStatement(assignVertex);
// set initial values on vertex
for (Entry<String, Expression> propertyInitial : initialExpressions.entrySet()) {
// > vertex.setProperty(name, initialValue)
code.addStatement(
new ExpressionStatement(new MethodCallExpression(vertex, "setProperty",
new ArgumentListExpression(
new ConstantExpression(propertyInitial.getKey()),
propertyInitial.getValue()))));
}
// > return new Entity(vertex, graph)
code.addStatement(new ReturnStatement(
new ConstructorCallExpression(clazz, new ArgumentListExpression(vertex, graph))));
return new MethodNode("create", Modifier.STATIC | Modifier.PUBLIC, clazz,
new Parameter[] { new Parameter(GRAPH_CLASS, "graph") }, new ClassNode[0], code);
}
/**
* Create a static method to retrieve all objects in a graph.
*
* @param clazz the entity class node
* @param entityName the entity name
* @param typeProperty the name of the property holding the entity name in a
* vertex
* @return the method
*/
private MethodNode buildFindAllMethod(ClassNode clazz, Expression entityName,
Expression typeProperty) {
clazz = ClassHelper.make(clazz.getName());
ClassNode returnType = ITERABLE_CLASS.getPlainNodeReference();
// add generic type argument
returnType.setGenericsTypes(new GenericsType[] { new GenericsType(clazz) });
BlockStatement code = new BlockStatement();
// initialize graph
code.addStatement(callInitGraph(clazz, new VariableExpression("graph")));
/*
* def vertices = VertexEntityDelegates.findAllDelegate(graph,
* entityName, typeProperty)
*/
VariableExpression vertices = new VariableExpression("vertices");
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new VariableExpression("graph"));
args.addExpression(entityName);
args.addExpression(typeProperty);
code.addStatement(
AbstractASTTransformUtil.declStatement(vertices, new StaticMethodCallExpression(
VE_DELEGATES_CLASS, VertexEntityDelegates.METHOD_FIND_ALL, args)));
/*
* return new IterableDelegate(vertices, EntityClass, graph)
*/
ArgumentListExpression createDelegateArgs = new ArgumentListExpression();
createDelegateArgs.addExpression(vertices);
createDelegateArgs.addExpression(new ClassExpression(clazz));
createDelegateArgs.addExpression(new VariableExpression("graph"));
code.addStatement(new ReturnStatement(
new ConstructorCallExpression(VE_ITERABLE_DELEGATE_CLASS, createDelegateArgs)));
return new MethodNode("findAll", Modifier.STATIC | Modifier.PUBLIC, returnType,
new Parameter[] { new Parameter(GRAPH_CLASS, "graph") }, new ClassNode[0], code);
}
/**
* Create a static method to retrieve objects by property value.
*
* @param clazz the entity class node
* @param entityName the entity name
* @param typeProperty the name of the property holding the entity name in a
* vertex
* @param propertyName the property name
* @param propertyType the property type
* @return the method
*/
private MethodNode buildFindByMethod(ClassNode clazz, Expression entityName,
Expression typeProperty, String propertyName, ClassNode propertyType) {
clazz = ClassHelper.make(clazz.getName());
propertyType = ClassHelper.make(propertyType.getName());
ClassNode returnType = ITERABLE_CLASS.getPlainNodeReference();
// add generic type argument
returnType.setGenericsTypes(new GenericsType[] { new GenericsType(clazz) });
String methodName = "findBy" + Character.toUpperCase(propertyName.charAt(0))
+ propertyName.substring(1);
BlockStatement code = new BlockStatement();
// initialize graph
code.addStatement(callInitGraph(clazz, new VariableExpression("graph")));
/*
* def vertices = VertexEntityDelegates.findByDelegate(graph,
* entityName, typeProperty, propertyName, value)
*/
VariableExpression vertices = new VariableExpression("vertices");
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new VariableExpression("graph"));
args.addExpression(entityName);
args.addExpression(typeProperty);
args.addExpression(new ConstantExpression(propertyName));
args.addExpression(new VariableExpression("value"));
code.addStatement(
AbstractASTTransformUtil.declStatement(vertices, new StaticMethodCallExpression(
VE_DELEGATES_CLASS, VertexEntityDelegates.METHOD_FIND_BY, args)));
/*
* return new IterableDelegate(vertices, EntityClass, graph)
*/
ArgumentListExpression createDelegateArgs = new ArgumentListExpression();
createDelegateArgs.addExpression(vertices);
createDelegateArgs.addExpression(new ClassExpression(clazz));
createDelegateArgs.addExpression(new VariableExpression("graph"));
code.addStatement(new ReturnStatement(
new ConstructorCallExpression(VE_ITERABLE_DELEGATE_CLASS, createDelegateArgs)));
return new MethodNode(methodName,
Modifier.STATIC | Modifier.PUBLIC, returnType, new Parameter[] {
new Parameter(GRAPH_CLASS, "graph"), new Parameter(propertyType, "value") },
new ClassNode[0], code);
}
/**
* Create a static method to get an entity by its ID.
*
* @param clazz the entity class node
* @return the method
*/
private MethodNode buildGetByIdMethod(ClassNode clazz) {
clazz = ClassHelper.make(clazz.getName());
BlockStatement code = new BlockStatement();
// initialize graph
code.addStatement(callInitGraph(clazz, new VariableExpression("graph")));
// def vertex = graph.getVertex(id)
VariableExpression vertex = new VariableExpression("vertex");
code.addStatement(AbstractASTTransformUtil.declStatement(vertex,
new MethodCallExpression(new VariableExpression("graph"), "getVertex",
new ArgumentListExpression(new VariableExpression("id")))));
/*
* return new EntityClass(vertex, graph)
*/
Statement returnEntity = new ReturnStatement(new ConstructorCallExpression(clazz,
new ArgumentListExpression(vertex, new VariableExpression("graph"))));
// return null
Statement returnNull = new ReturnStatement(new ConstantExpression(null));
// if (vertex == null) ... else ...
code.addStatement(new IfStatement(AbstractASTTransformUtil.equalsNullExpr(vertex),
returnNull, returnEntity));
return new MethodNode("getById", Modifier.STATIC | Modifier.PUBLIC, clazz,
new Parameter[] { new Parameter(GRAPH_CLASS, "graph"),
new Parameter(ClassHelper.OBJECT_TYPE, "id") },
new ClassNode[] { VE_NON_UNIQUE_EXCEPTION }, code);
}
/**
* Create a static method to retrieve an object by property value.
*
* @param clazz the entity class node
* @param entityName the entity name
* @param typeProperty the name of the property holding the entity name in a
* vertex
* @param propertyName the property name
* @param propertyType the property type
* @return the method
*/
private MethodNode buildGetByMethod(ClassNode clazz, Expression entityName,
Expression typeProperty, String propertyName, ClassNode propertyType) {
clazz = ClassHelper.make(clazz.getName());
propertyType = ClassHelper.make(propertyType.getName());
String methodName = "getBy" + Character.toUpperCase(propertyName.charAt(0))
+ propertyName.substring(1);
BlockStatement code = new BlockStatement();
// initialize graph
code.addStatement(callInitGraph(clazz, new VariableExpression("graph")));
/*
* def vertex = VertexEntityDelegates.findUniqueByDelegate(graph,
* entityName, typeProperty, propertyName, value)
*/
VariableExpression vertex = new VariableExpression("vertex");
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new VariableExpression("graph"));
args.addExpression(entityName);
args.addExpression(typeProperty);
args.addExpression(new ConstantExpression(propertyName));
args.addExpression(new VariableExpression("value"));
code.addStatement(
AbstractASTTransformUtil.declStatement(vertex, new StaticMethodCallExpression(
VE_DELEGATES_CLASS, VertexEntityDelegates.METHOD_GET_BY, args)));
/*
* return new EntityClass(vertex, graph)
*/
Statement returnEntity = new ReturnStatement(new ConstructorCallExpression(clazz,
new ArgumentListExpression(vertex, new VariableExpression("graph"))));
// return null
Statement returnNull = new ReturnStatement(new ConstantExpression(null));
// if (vertex == null) ... else ...
code.addStatement(new IfStatement(AbstractASTTransformUtil.equalsNullExpr(vertex),
returnNull, returnEntity));
return new MethodNode(methodName, Modifier.STATIC | Modifier.PUBLIC, clazz,
new Parameter[] { new Parameter(GRAPH_CLASS, "graph"),
new Parameter(propertyType, "value") },
new ClassNode[] { VE_NON_UNIQUE_EXCEPTION }, code);
}
/**
* Create a constructor taking a Vertex and a Graph as an argument,
* assigning them to the vertex and graph fields.
*
* @param vertexField the vertex field
* @param graphField the graph field
* @param superClass the vertex entity super class or <code>null</code>
* @param typeProperty the expression specifying the name of the type
* property
* @param entityName the expression specifying the entity name
* @return a constructor taking a Vertex as an argument
*/
private ConstructorNode buildVertexGraphConstructor(FieldNode vertexField, FieldNode graphField,
ClassNode superClass, Expression typeProperty, Expression entityName) {
BlockStatement block = new BlockStatement();
// parameter vertex
VariableExpression vertex = new VariableExpression("vertex");
// parameter graph
VariableExpression graph = new VariableExpression("graph");
if (superClass != null) {
// super(vertex, graph)
block.addStatement(new ExpressionStatement(new ConstructorCallExpression(
ClassNode.SUPER, new ArgumentListExpression(vertex, graph))));
}
else {
// > this.v = vertex
block.addStatement(AbstractASTTransformUtil.assignStatement(
new FieldExpression(vertexField), new VariableExpression("vertex")));
// > this.g = graph
block.addStatement(AbstractASTTransformUtil.assignStatement(
new FieldExpression(graphField), new VariableExpression("graph")));
}
// vertex.setProperty(typeProperty, entityName)
Statement notOrientStatement = new ExpressionStatement(
new MethodCallExpression(vertex, "setProperty",
new ArgumentListExpression(new Expression[] { typeProperty, entityName })));
// > if (!(graph instanceof OrientGraph))
// > this.v.setProperty(typeProperty, entityName)
block.addStatement(new IfStatement(
new NotExpression(AbstractASTTransformUtil.isInstanceOf(graph, ORIENT_GRAPH_CLASS)),
notOrientStatement, new EmptyStatement()));
return new ConstructorNode(Modifier.PUBLIC, new Parameter[] {
new Parameter(VERTEX_CLASS, "vertex"), new Parameter(GRAPH_CLASS, "graph") },
new ClassNode[0], block);
}
/**
* Add the given property and clean up the old with the same name.
*
* @param clazz the class node to add the property to
* @param property the property node
*/
private void readdProperty(ClassNode clazz, PropertyNode property) {
clazz.getProperties().remove(property);
final FieldNode fn = property.getField();
clazz.getFields().remove(fn);
clazz.addProperty(property.getName(), property.getModifiers(), property.getType(),
property.getInitialExpression(), property.getGetterBlock(),
property.getSetterBlock());
final FieldNode newfn = clazz.getField(fn.getName());
clazz.getFields().remove(newfn);
// the original field is not needed
// cNode.addField(fn);
}
private Statement createSetter(String name, FieldNode vertexField) {
BlockStatement block = new BlockStatement();
VariableExpression value = new VariableExpression("value");
/*
* v.setProperty(name, value)
*/
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new ConstantExpression(name));
args.addExpression(value);
Statement ifNotNull = new ExpressionStatement(
new MethodCallExpression(new FieldExpression(vertexField), "setProperty", args));
/*
* v.removeProperty(name)
*/
Statement ifNull = new ExpressionStatement(
new MethodCallExpression(new FieldExpression(vertexField), "removeProperty",
new ArgumentListExpression(new ConstantExpression(name))));
block.addStatement(
new IfStatement(AbstractASTTransformUtil.equalsNullExpr(value), ifNull, ifNotNull));
return block;
}
private Statement createGetter(String name, FieldNode vertexField, ClassNode propertyType,
Expression initialExpression) {
BlockStatement block = new BlockStatement();
// def tmp
VariableExpression tmpValue = new VariableExpression("tmp");
/*
* > tmp = v.getProperty(name)
*/
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new ConstantExpression(name));
block.addStatement(AbstractASTTransformUtil.declStatement(tmpValue,
new MethodCallExpression(new FieldExpression(vertexField), "getProperty", args)));
if (ClassHelper.isPrimitiveType(propertyType) && initialExpression != null) {
// if the class is a primitive, we must do a null check here
// if (tmp == null) return <initial-value>
block.addStatement(new IfStatement(AbstractASTTransformUtil.equalsNullExpr(tmpValue),
new ReturnStatement(initialExpression), new EmptyStatement()));
}
block.addStatement(new ReturnStatement(tmpValue));
return block;
}
}