Search in sources :

Example 1 with CqlName

use of com.datastax.oss.driver.api.mapper.annotations.CqlName in project java-driver by datastax.

the class GeneratedCodePatterns method bindParameters.

/**
 * Treats a list of method parameters as bind variables in a query, assuming that the bind markers
 * have the same names as the parameters, unless they are annotated with {@link CqlName}.
 *
 * <p>The generated code assumes that a {@code BoundStatementBuilder boundStatementBuilder} local
 * variable already exists.
 */
public static void bindParameters(@NonNull List<? extends VariableElement> parameters, CodeBlock.Builder methodBuilder, BindableHandlingSharedCode enclosingClass, ProcessorContext context, boolean useNullSavingStrategy) {
    List<CodeBlock> bindMarkerNames = new ArrayList<>();
    for (VariableElement parameter : parameters) {
        CqlName cqlName = parameter.getAnnotation(CqlName.class);
        String parameterName;
        if (cqlName == null) {
            parameterName = parameter.getSimpleName().toString();
        } else {
            parameterName = cqlName.value();
        }
        bindMarkerNames.add(CodeBlock.of("$S", parameterName));
    }
    bindParameters(parameters, bindMarkerNames, methodBuilder, enclosingClass, context, useNullSavingStrategy);
}
Also used : CqlName(com.datastax.oss.driver.api.mapper.annotations.CqlName) CodeBlock(com.squareup.javapoet.CodeBlock) ArrayList(java.util.ArrayList) VariableElement(javax.lang.model.element.VariableElement)

Example 2 with CqlName

use of com.datastax.oss.driver.api.mapper.annotations.CqlName in project java-driver by datastax.

the class DaoMethodGenerator method validateCqlNamesPresent.

protected boolean validateCqlNamesPresent(List<? extends VariableElement> parameters) {
    boolean valid = true;
    if (isFromClassFile()) {
        for (VariableElement parameter : parameters) {
            CqlName cqlName = parameter.getAnnotation(CqlName.class);
            if (cqlName == null) {
                context.getMessager().error(methodElement, "Parameter %s is declared in a compiled method " + "and refers to a bind marker " + "and thus must be annotated with @%s", parameter.getSimpleName(), CqlName.class.getSimpleName());
                valid = false;
            }
        }
    }
    return valid;
}
Also used : CqlName(com.datastax.oss.driver.api.mapper.annotations.CqlName) VariableElement(javax.lang.model.element.VariableElement)

Example 3 with CqlName

use of com.datastax.oss.driver.api.mapper.annotations.CqlName in project java-driver by datastax.

the class DaoIncrementMethodGenerator method generatePrepareRequest.

private void generatePrepareRequest(MethodSpec.Builder methodBuilder, String requestName, EntityDefinition entityDefinition, String helperFieldName, List<? extends VariableElement> incrementParameters) {
    if (incrementParameters.isEmpty()) {
        context.getMessager().error(methodElement, "%s method must take at least one parameter representing an increment to a " + "counter column", Increment.class.getSimpleName());
        return;
    }
    methodBuilder.addStatement("$L.throwIfKeyspaceMissing()", helperFieldName).addCode("$[$1T $2L = (($3L.getKeyspaceId() == null)\n" + "? $4T.update($3L.getTableId())\n" + ": $4T.update($3L.getKeyspaceId(), $3L.getTableId()))", SimpleStatement.class, requestName, helperFieldName, QueryBuilder.class);
    // =>  `.append("one_star", QueryBuilder.bindMarker("oneStar"))`
    for (VariableElement parameter : incrementParameters) {
        CodeBlock cqlName = null;
        CqlName annotation = parameter.getAnnotation(CqlName.class);
        if (annotation != null) {
            // If a CQL name is provided, use that
            cqlName = CodeBlock.of("$S", annotation.value());
        } else {
            // example parameter `oneStar` matches `ProductRating.getOneStar()`.
            for (PropertyDefinition property : entityDefinition.getRegularColumns()) {
                if (property.getJavaName().equals(parameter.getSimpleName().toString())) {
                    cqlName = property.getCqlName();
                    break;
                }
            }
            if (cqlName == null) {
                List<String> javaNames = StreamSupport.stream(entityDefinition.getRegularColumns().spliterator(), false).map(PropertyDefinition::getJavaName).collect(Collectors.toList());
                context.getMessager().error(parameter, "Could not match '%s' with any counter column in %s (expected one of: %s). " + "You can also specify a CQL name directly with @%s.", parameter.getSimpleName(), entityDefinition.getClassName().simpleName(), javaNames, CqlName.class.getSimpleName());
                // incorrect, but that doesn't matter since we've already thrown a compile error.
                break;
            }
        }
        // Always use the parameter name. This is what the binding code will expect (see
        // GeneratedCodePatterns.bindParameters call in generate())
        String bindMarkerName = parameter.getSimpleName().toString();
        // We use `append` to generate "c=c+?". QueryBuilder also has `increment` that produces
        // "c+=?", but that doesn't work with Cassandra 2.1.
        methodBuilder.addCode("\n.append($1L, $2T.bindMarker($3S))", cqlName, QueryBuilder.class, bindMarkerName);
    }
    for (PropertyDefinition property : entityDefinition.getPrimaryKey()) {
        methodBuilder.addCode("\n.where($1T.column($2L).isEqualTo($3T.bindMarker($2L)))", Relation.class, property.getCqlName(), QueryBuilder.class);
    }
    methodBuilder.addCode("\n.build()$];\n");
}
Also used : CqlName(com.datastax.oss.driver.api.mapper.annotations.CqlName) Increment(com.datastax.oss.driver.api.mapper.annotations.Increment) CodeBlock(com.squareup.javapoet.CodeBlock) VariableElement(javax.lang.model.element.VariableElement) PropertyDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition)

Example 4 with CqlName

use of com.datastax.oss.driver.api.mapper.annotations.CqlName in project java-driver by datastax.

the class DefaultEntityFactory method getDefinition.

@Override
public EntityDefinition getDefinition(TypeElement processedClass) {
    Set<TypeMirror> types = HierarchyScanner.resolveTypeHierarchy(processedClass, context);
    Set<TypeElement> typeHierarchy = Sets.newLinkedHashSet();
    for (TypeMirror type : types) {
        typeHierarchy.add((TypeElement) context.getTypeUtils().asElement(type));
    }
    Language language = Language.detect(typeHierarchy);
    Optional<PropertyStrategy> propertyStrategy = getPropertyStrategy(typeHierarchy);
    GetterStyle getterStyle = propertyStrategy.map(PropertyStrategy::getterStyle).orElse(language.defaultGetterStyle);
    SetterStyle setterStyle = propertyStrategy.map(PropertyStrategy::setterStyle).orElse(language.defaultSetterStyle);
    boolean mutable = propertyStrategy.map(PropertyStrategy::mutable).orElse(language.defaultMutable);
    CqlNameGenerator cqlNameGenerator = buildCqlNameGenerator(typeHierarchy);
    Set<String> transientProperties = getTransientPropertyNames(typeHierarchy);
    Set<String> encounteredPropertyNames = Sets.newHashSet();
    SortedMap<Integer, PropertyDefinition> partitionKey = new TreeMap<>();
    SortedMap<Integer, PropertyDefinition> clusteringColumns = new TreeMap<>();
    ImmutableList.Builder<PropertyDefinition> regularColumns = ImmutableList.builder();
    ImmutableList.Builder<PropertyDefinition> computedValues = ImmutableList.builder();
    // scan hierarchy for properties
    for (TypeElement typeElement : typeHierarchy) {
        for (Element child : typeElement.getEnclosedElements()) {
            Set<Modifier> modifiers = child.getModifiers();
            if (child.getKind() != ElementKind.METHOD || modifiers.contains(Modifier.STATIC) || modifiers.contains(Modifier.PRIVATE)) {
                continue;
            }
            ExecutableElement getMethod = (ExecutableElement) child;
            if (!getMethod.getParameters().isEmpty()) {
                continue;
            }
            TypeMirror typeMirror = getMethod.getReturnType();
            if (typeMirror.getKind() == TypeKind.VOID) {
                continue;
            }
            String getMethodName = getMethod.getSimpleName().toString();
            // hashCode() and a few Scala or Kotlin methods.
            if (getMethodName.equals("toString") || getMethodName.equals("hashCode") || (language == Language.SCALA_CASE_CLASS && (getMethodName.equals("productPrefix") || getMethodName.equals("productArity") || getMethodName.equals("productIterator") || getMethodName.equals("productElementNames") || getMethodName.startsWith("copy$default$"))) || (language == Language.KOTLIN_DATA_CLASS && getMethodName.matches("component[0-9]+"))) {
                continue;
            }
            String propertyName = inferPropertyName(getMethodName, getterStyle, typeMirror);
            if (propertyName == null) {
                // getMethodName does not follow a known pattern => this is not a getter, skip
                continue;
            }
            // skip properties we've already encountered.
            if (encounteredPropertyNames.contains(propertyName)) {
                continue;
            }
            String setMethodName;
            if (mutable) {
                setMethodName = inferSetMethodName(propertyName, setterStyle);
                ExecutableElement setMethod = findSetMethod(typeHierarchy, setMethodName, typeMirror);
                if (setMethod == null) {
                    // must have both
                    continue;
                }
            } else {
                setMethodName = null;
            }
            VariableElement field = findField(typeHierarchy, propertyName, typeMirror);
            Map<Class<? extends Annotation>, Annotation> propertyAnnotations = scanPropertyAnnotations(typeHierarchy, getMethod, field);
            if (isTransient(propertyAnnotations, propertyName, transientProperties, getMethod, field)) {
                continue;
            }
            int partitionKeyIndex = getPartitionKeyIndex(propertyAnnotations);
            int clusteringColumnIndex = getClusteringColumnIndex(propertyAnnotations);
            Optional<String> customCqlName = getCustomCqlName(propertyAnnotations);
            Optional<String> computedFormula = getComputedFormula(propertyAnnotations, getMethod, field);
            PropertyType propertyType = PropertyType.parse(typeMirror, context);
            PropertyDefinition property = new DefaultPropertyDefinition(propertyName, customCqlName, computedFormula, getMethodName, setMethodName, propertyType, cqlNameGenerator);
            encounteredPropertyNames.add(propertyName);
            if (partitionKeyIndex >= 0) {
                PropertyDefinition previous = partitionKey.putIfAbsent(partitionKeyIndex, property);
                if (previous != null) {
                    context.getMessager().error(getMethod, "Duplicate partition key index: if multiple properties are annotated " + "with @%s, the annotation must be parameterized with an integer " + "indicating the position. Found duplicate index %d for %s and %s.", PartitionKey.class.getSimpleName(), partitionKeyIndex, previous.getGetterName(), property.getGetterName());
                }
            } else if (clusteringColumnIndex >= 0) {
                PropertyDefinition previous = clusteringColumns.putIfAbsent(clusteringColumnIndex, property);
                if (previous != null) {
                    context.getMessager().error(getMethod, "Duplicate clustering column index: if multiple properties are annotated " + "with @%s, the annotation must be parameterized with an integer " + "indicating the position. Found duplicate index %d for %s and %s.", ClusteringColumn.class.getSimpleName(), clusteringColumnIndex, previous.getGetterName(), property.getGetterName());
                }
            } else if (computedFormula.isPresent()) {
                computedValues.add(property);
            } else {
                regularColumns.add(property);
            }
        }
    }
    if (encounteredPropertyNames.isEmpty()) {
        context.getMessager().error(processedClass, "@%s-annotated class must have at least one property defined.", Entity.class.getSimpleName());
    }
    String entityName = Capitalizer.decapitalize(processedClass.getSimpleName().toString());
    String defaultKeyspace = processedClass.getAnnotation(Entity.class).defaultKeyspace();
    EntityDefinition entityDefinition = new DefaultEntityDefinition(ClassName.get(processedClass), entityName, defaultKeyspace.isEmpty() ? null : defaultKeyspace, Optional.ofNullable(processedClass.getAnnotation(CqlName.class)).map(CqlName::value), ImmutableList.copyOf(partitionKey.values()), ImmutableList.copyOf(clusteringColumns.values()), regularColumns.build(), computedValues.build(), cqlNameGenerator, mutable);
    validateConstructor(entityDefinition, processedClass);
    return entityDefinition;
}
Also used : Entity(com.datastax.oss.driver.api.mapper.annotations.Entity) SetterStyle(com.datastax.oss.driver.api.mapper.entity.naming.SetterStyle) ImmutableList(com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList) VariableElement(javax.lang.model.element.VariableElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) ExecutableElement(javax.lang.model.element.ExecutableElement) VariableElement(javax.lang.model.element.VariableElement) PropertyType(com.datastax.oss.driver.internal.mapper.processor.util.generation.PropertyType) GetterStyle(com.datastax.oss.driver.api.mapper.entity.naming.GetterStyle) TypeMirror(javax.lang.model.type.TypeMirror) Modifier(javax.lang.model.element.Modifier) CqlName(com.datastax.oss.driver.api.mapper.annotations.CqlName) TypeElement(javax.lang.model.element.TypeElement) TreeMap(java.util.TreeMap) ResolvedAnnotation(com.datastax.oss.driver.internal.mapper.processor.util.ResolvedAnnotation) Annotation(java.lang.annotation.Annotation) PropertyStrategy(com.datastax.oss.driver.api.mapper.annotations.PropertyStrategy) PartitionKey(com.datastax.oss.driver.api.mapper.annotations.PartitionKey)

Aggregations

CqlName (com.datastax.oss.driver.api.mapper.annotations.CqlName)4 VariableElement (javax.lang.model.element.VariableElement)4 CodeBlock (com.squareup.javapoet.CodeBlock)2 Entity (com.datastax.oss.driver.api.mapper.annotations.Entity)1 Increment (com.datastax.oss.driver.api.mapper.annotations.Increment)1 PartitionKey (com.datastax.oss.driver.api.mapper.annotations.PartitionKey)1 PropertyStrategy (com.datastax.oss.driver.api.mapper.annotations.PropertyStrategy)1 GetterStyle (com.datastax.oss.driver.api.mapper.entity.naming.GetterStyle)1 SetterStyle (com.datastax.oss.driver.api.mapper.entity.naming.SetterStyle)1 PropertyDefinition (com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition)1 ResolvedAnnotation (com.datastax.oss.driver.internal.mapper.processor.util.ResolvedAnnotation)1 PropertyType (com.datastax.oss.driver.internal.mapper.processor.util.generation.PropertyType)1 ImmutableList (com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList)1 Annotation (java.lang.annotation.Annotation)1 ArrayList (java.util.ArrayList)1 TreeMap (java.util.TreeMap)1 Element (javax.lang.model.element.Element)1 ExecutableElement (javax.lang.model.element.ExecutableElement)1 Modifier (javax.lang.model.element.Modifier)1 TypeElement (javax.lang.model.element.TypeElement)1