in mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoIncrementMethodGenerator.java [81:226]
public Optional<MethodSpec> generate() {
TypeElement entityElement = getEntityClassFromAnnotation(Increment.class);
EntityDefinition entityDefinition;
if (entityElement == null) {
context
.getMessager()
.error(
methodElement,
"Missing entity class: %s methods must always have an 'entityClass' argument",
Increment.class.getSimpleName());
return Optional.empty();
} else {
entityDefinition = context.getEntityFactory().getDefinition(entityElement);
}
// Validate the parameters:
// - all the PK components of the entity, in order.
// - one or more increment parameters that must match non-PK columns.
// - a Function<BoundStatementBuilder, BoundStatementBuilder> can be added in last position.
List<? extends VariableElement> parameters = methodElement.getParameters();
VariableElement boundStatementFunction = findBoundStatementFunction(methodElement);
if (boundStatementFunction != null) {
parameters = parameters.subList(0, parameters.size() - 1);
}
List<? extends VariableElement> primaryKeyParameters = parameters;
// Must have at least enough parameters for the full PK
if (primaryKeyParameters.size() < entityDefinition.getPrimaryKey().size()) {
List<TypeName> primaryKeyTypes =
entityDefinition.getPrimaryKey().stream()
.map(d -> d.getType().asTypeName())
.collect(Collectors.toList());
context
.getMessager()
.error(
methodElement,
"Invalid parameter list: %s methods must specify the entire primary key "
+ "(expected primary keys of %s: %s)",
Increment.class.getSimpleName(),
entityElement.getSimpleName(),
primaryKeyTypes);
return Optional.empty();
} else {
primaryKeyParameters =
primaryKeyParameters.subList(0, entityDefinition.getPrimaryKey().size());
warnIfCqlNamePresent(primaryKeyParameters);
}
// PK parameter types must match
if (!EntityUtils.areParametersValid(
entityElement,
entityDefinition,
primaryKeyParameters,
Increment.class,
context,
methodElement,
processedType,
"" /* no condition, @Increment must always have the full PK */)) {
return Optional.empty();
}
// The remaining parameters are the increments to the counter columns
List<? extends VariableElement> incrementParameters =
parameters.subList(primaryKeyParameters.size(), parameters.size());
if (!validateCqlNamesPresent(incrementParameters)) {
return Optional.empty();
}
for (VariableElement parameter : incrementParameters) {
TypeMirror type = parameter.asType();
if (type.getKind() != TypeKind.LONG && !context.getClassUtils().isSame(type, Long.class)) {
context
.getMessager()
.error(
methodElement,
"Invalid argument type: increment parameters of %s methods can only be "
+ "primitive longs or java.lang.Long. Offending parameter: '%s' (%s)",
Increment.class.getSimpleName(),
parameter.getSimpleName(),
type);
return Optional.empty();
}
}
// Validate the return type:
DaoReturnType returnType =
parseAndValidateReturnType(getSupportedReturnTypes(), Increment.class.getSimpleName());
if (returnType == null) {
return Optional.empty();
}
// Generate the method:
String helperFieldName = enclosingClass.addEntityHelperField(ClassName.get(entityElement));
String statementName =
enclosingClass.addPreparedStatement(
methodElement,
(methodBuilder, requestName) ->
generatePrepareRequest(
methodBuilder,
requestName,
entityDefinition,
helperFieldName,
incrementParameters));
CodeBlock.Builder updateStatementBlock = CodeBlock.builder();
updateStatementBlock.addStatement(
"$T boundStatementBuilder = $L.boundStatementBuilder()",
BoundStatementBuilder.class,
statementName);
populateBuilderWithStatementAttributes(updateStatementBlock, methodElement);
populateBuilderWithFunction(updateStatementBlock, boundStatementFunction);
// Bind the counter increments. The bind parameter names are always the raw parameter names, see
// generatePrepareRequest.
List<CodeBlock> bindMarkerNames =
incrementParameters.stream()
.map(p -> CodeBlock.of("$S", p.getSimpleName()))
.collect(Collectors.toList());
// Force the null saving strategy. This will fail if the user targets Cassandra 2.2, but
// SET_TO_NULL would not work with counters anyway.
updateStatementBlock.addStatement(
"final $1T nullSavingStrategy = $1T.$2L",
NullSavingStrategy.class,
NullSavingStrategy.DO_NOT_SET);
GeneratedCodePatterns.bindParameters(
incrementParameters, bindMarkerNames, updateStatementBlock, enclosingClass, context, true);
// Bind the PK columns
List<CodeBlock> primaryKeyNames =
entityDefinition.getPrimaryKey().stream()
.map(PropertyDefinition::getCqlName)
.collect(Collectors.toList());
GeneratedCodePatterns.bindParameters(
primaryKeyParameters,
primaryKeyNames,
updateStatementBlock,
enclosingClass,
context,
false);
updateStatementBlock.addStatement(
"$T boundStatement = boundStatementBuilder.build()", BoundStatement.class);
return crudMethod(updateStatementBlock, returnType, helperFieldName);
}