private void createMethodsForSingleField(FieldNode fieldNode) { if (shouldFieldBeIgnored(fieldNode)) return; if (hasAnnotation(fieldNode.getType(), DSL_CONFIG_ANNOTATION)) { createSingleDSLObjectClosureMethod(fieldNode); createSingleFieldSetterMethod(fieldNode); } else if (ASTHelper.isMap(fieldNode.getType())) createMapMethod(fieldNode); else if (ASTHelper.isList(fieldNode.getType())) createListMethod(fieldNode); else createSingleFieldSetterMethod(fieldNode); }
private void createSingleFieldSetterMethod(FieldNode fieldNode) { MethodBuilder.createPublicMethod(fieldNode.getName()) .param(fieldNode.getType(), "value") .assignToProperty(fieldNode.getName(), varX("value")) .addTo(annotatedClass); if (fieldNode.getType().equals(ClassHelper.boolean_TYPE)) { MethodBuilder.createPublicMethod(fieldNode.getName()) .callThis(fieldNode.getName(), constX(true)) .addTo(annotatedClass); } }
private Statement createConstructorStatement( ClassNode cNode, PropertyNode pNode, List<String> knownImmutableClasses, List<String> knownImmutables) { FieldNode fNode = pNode.getField(); final ClassNode fieldType = fNode.getType(); Statement statement = null; if (fieldType.isArray() || isOrImplements(fieldType, CLONEABLE_TYPE)) { statement = createConstructorStatementArrayOrCloneable(fNode); } else if (isKnownImmutableClass(fieldType, knownImmutableClasses) || isKnownImmutable(pNode.getName(), knownImmutables)) { statement = createConstructorStatementDefault(fNode); } else if (fieldType.isDerivedFrom(DATE_TYPE)) { statement = createConstructorStatementDate(fNode); } else if (isOrImplements(fieldType, COLLECTION_TYPE) || fieldType.isDerivedFrom(COLLECTION_TYPE) || isOrImplements(fieldType, MAP_TYPE) || fieldType.isDerivedFrom(MAP_TYPE)) { statement = createConstructorStatementCollection(fNode); } else if (fieldType.isResolved()) { addError( createErrorMessage(cNode.getName(), fNode.getName(), fieldType.getName(), "compiling"), fNode); statement = EmptyStatement.INSTANCE; } else { statement = createConstructorStatementGuarded(cNode, fNode); } return statement; }
private void assertMembersNamesAreUnique() { Map<String, FieldNode> allDslCollectionFieldNodesOfHierarchy = new HashMap<String, FieldNode>(); for (ClassNode level : ASTHelper.getHierarchyOfDSLObjectAncestors(annotatedClass)) { for (FieldNode field : level.getFields()) { if (!ASTHelper.isListOrMap(field.getType())) continue; String memberName = getElementNameForCollectionField(field); FieldNode conflictingField = allDslCollectionFieldNodesOfHierarchy.get(memberName); if (conflictingField != null) { addCompileError( String.format( "Member name %s is used more than once: %s:%s and %s:%s", memberName, field.getOwner().getName(), field.getName(), conflictingField.getOwner().getName(), conflictingField.getName()), field); return; } allDslCollectionFieldNodesOfHierarchy.put(memberName, field); } } }
@SuppressWarnings("ConstantConditions") private GenericsType[] getGenericsTypes(FieldNode fieldNode) { GenericsType[] types = fieldNode.getType().getGenericsTypes(); if (types == null) addCompileError("Lists and Maps need to be assigned an explicit Generic Type", fieldNode); return types; }
private FieldNode getKeyField(ClassNode target) { List<FieldNode> annotatedFields = getAnnotatedFieldsOfHierarchy(target, KEY_ANNOTATION); if (annotatedFields.isEmpty()) return null; if (annotatedFields.size() > 1) { addCompileError( String.format( "Found more than one key fields, only one is allowed in hierarchy (%s, %s)", getQualifiedName(annotatedFields.get(0)), getQualifiedName(annotatedFields.get(1))), annotatedFields.get(0)); return null; } FieldNode result = annotatedFields.get(0); if (!result.getType().equals(ClassHelper.STRING_TYPE)) { addCompileError( String.format( "Key field '%s' must be of type String, but is '%s' instead", result.getName(), result.getType().getName()), result); return null; } ClassNode ancestor = ASTHelper.getHighestAncestorDSLObject(target); if (target.equals(ancestor)) return result; FieldNode firstKey = getKeyField(ancestor); if (firstKey == null) { addCompileError( String.format( "Inconsistent hierarchy: Toplevel class %s has no key, but child class %s defines '%s'.", ancestor.getName(), target.getName(), result.getName()), result); return null; } return result; }
private void validateFieldAnnotations() { for (FieldNode fieldNode : annotatedClass.getFields()) { if (shouldFieldBeIgnored(fieldNode)) continue; AnnotationNode annotation = getAnnotation(fieldNode, DSL_FIELD_ANNOTATION); if (annotation == null) continue; if (ASTHelper.isListOrMap(fieldNode.getType())) return; if (annotation.getMember("members") != null) { addCompileError( String.format( "@Field.members is only valid for List or Map fields, but field %s is of type %s", fieldNode.getName(), fieldNode.getType().getName()), annotation); } } }
private void preventOwnerOverride() { MethodBuilder.createPublicMethod(setterName(ownerField)) .param(OBJECT_TYPE, "value") .statement( ifS( andX( isInstanceOfX(varX("value"), ownerField.getType()), notX(propX(varX("this"), ownerField.getName()))), assignX(propX(varX("this"), ownerField.getName()), varX("value")))) .addTo(annotatedClass); }
private Statement createGetterBody(FieldNode fNode) { BlockStatement body = new BlockStatement(); final ClassNode fieldType = fNode.getType(); final Statement statement; if (fieldType.isArray() || isOrImplements(fieldType, CLONEABLE_TYPE)) { statement = createGetterBodyArrayOrCloneable(fNode); } else if (fieldType.isDerivedFrom(DATE_TYPE)) { statement = createGetterBodyDate(fNode); } else { statement = createGetterBodyDefault(fNode); } body.addStatement(statement); return body; }
private Statement createConstructorStatementArrayOrCloneable(FieldNode fNode) { final Expression fieldExpr = new VariableExpression(fNode); Expression initExpr = fNode.getInitialValueExpression(); ClassNode fieldType = fNode.getType(); if (initExpr == null) initExpr = new ConstantExpression(null); final Expression array = findArg(fNode.getName()); return new IfStatement( equalsNullExpr(array), new IfStatement( equalsNullExpr(initExpr), assignStatement(fieldExpr, new ConstantExpression(null)), assignStatement(fieldExpr, cloneArrayOrCloneableExpr(initExpr, fieldType))), assignStatement(fieldExpr, cloneArrayOrCloneableExpr(array, fieldType))); }
private void createMapOfSimpleElementsMethods( FieldNode fieldNode, ClassNode keyType, ClassNode valueType) { String methodName = fieldNode.getName(); MethodBuilder.createPublicMethod(methodName) .param(fieldNode.getType(), "values") .callMethod(propX(varX("this"), fieldNode.getName()), "putAll", varX("values")) .addTo(annotatedClass); String singleElementMethod = getElementNameForCollectionField(fieldNode); MethodBuilder.createPublicMethod(singleElementMethod) .param(keyType, "key") .param(valueType, "value") .callMethod(propX(varX("this"), fieldNode.getName()), "put", args("key", "value")) .addTo(annotatedClass); }
private void createListOfSimpleElementsMethods(FieldNode fieldNode, ClassNode elementType) { MethodBuilder.createPublicMethod(fieldNode.getName()) .arrayParam(elementType, "values") .statement(callX(propX(varX("this"), fieldNode.getName()), "addAll", varX("values"))) .addTo(annotatedClass); MethodBuilder.createPublicMethod(fieldNode.getName()) .param(fieldNode.getType(), "values") .statement(callX(propX(varX("this"), fieldNode.getName()), "addAll", varX("values"))) .addTo(annotatedClass); MethodBuilder.createPublicMethod(getElementNameForCollectionField(fieldNode)) .param(elementType, "value") .statement(callX(propX(varX("this"), fieldNode.getName()), "add", varX("value"))) .addTo(annotatedClass); }
private Statement createGetterBodyArrayOrCloneable(FieldNode fNode) { final Expression fieldExpr = new VariableExpression(fNode); final Expression expression = cloneArrayOrCloneableExpr(fieldExpr, fNode.getType()); return safeExpression(fieldExpr, expression); }
private void createSingleDSLObjectClosureMethod(FieldNode fieldNode) { String methodName = fieldNode.getName(); ClassNode targetFieldType = fieldNode.getType(); FieldNode targetTypeKeyField = getKeyField(targetFieldType); String targetOwnerFieldName = getOwnerFieldName(targetFieldType); if (!ASTHelper.isAbstract(targetFieldType)) { MethodBuilder.createPublicMethod(methodName) .returning(targetFieldType) .namedParams("values") .optionalStringParam("key", targetTypeKeyField) .delegatingClosureParam(targetFieldType) .declareVariable( "created", callX(classX(targetFieldType), "newInstance", optionalKeyArg(targetTypeKeyField))) .callMethod("created", "copyFromTemplate") .optionalAssignThisToPropertyS("created", targetOwnerFieldName, targetOwnerFieldName) .assignToProperty( fieldNode.getName(), callX(varX("created"), "apply", args("values", "closure"))) .callValidationOn("created") .doReturn("created") .addTo(annotatedClass); MethodBuilder.createPublicMethod(methodName) .returning(targetFieldType) .optionalStringParam("key", targetTypeKeyField) .delegatingClosureParam(targetFieldType) .declareVariable( "created", callX(classX(targetFieldType), "newInstance", optionalKeyArg(targetTypeKeyField))) .callMethod("created", "copyFromTemplate") .optionalAssignThisToPropertyS("created", targetOwnerFieldName, targetOwnerFieldName) .assignToProperty(fieldNode.getName(), callX(varX("created"), "apply", varX("closure"))) .callValidationOn("created") .doReturn("created") .addTo(annotatedClass); } if (!isFinal(targetFieldType)) { MethodBuilder.createPublicMethod(methodName) .returning(targetFieldType) .namedParams("values") .classParam("typeToCreate", targetFieldType) .optionalStringParam("key", targetTypeKeyField) .delegatingClosureParam(targetFieldType) .declareVariable( "created", callX(varX("typeToCreate"), "newInstance", optionalKeyArg(targetTypeKeyField))) .callMethod("created", "copyFromTemplate") .optionalAssignThisToPropertyS("created", targetOwnerFieldName, targetOwnerFieldName) .assignToProperty( fieldNode.getName(), callX(varX("created"), "apply", args("values", "closure"))) .callValidationOn("created") .doReturn("created") .addTo(annotatedClass); MethodBuilder.createPublicMethod(methodName) .returning(targetFieldType) .classParam("typeToCreate", targetFieldType) .optionalStringParam("key", targetTypeKeyField) .delegatingClosureParam(targetFieldType) .declareVariable( "created", callX(varX("typeToCreate"), "newInstance", optionalKeyArg(targetTypeKeyField))) .callMethod("created", "copyFromTemplate") .optionalAssignThisToPropertyS("created", targetOwnerFieldName, targetOwnerFieldName) .assignToProperty(fieldNode.getName(), callX(varX("created"), "apply", varX("closure"))) .callValidationOn("created") .doReturn("created") .addTo(annotatedClass); } }