use of com.datastax.oss.driver.internal.mapper.processor.util.generation.PropertyType in project java-driver by datastax.
the class EntityHelperGetMethodGenerator method convertUdtsIntoEntities.
/**
* Generates the code to convert a collection of UDT instances, for example a {@code Map<String,
* UdtValue>} into a {@code Map<String, Product>}.
*
* @param rawObjectName the name of the local variable containing the value to convert.
* @param mappedObjectName the name of the local variable that will hold the converted value (it
* already exists).
* @param type the type of the value.
* @param getBuilder the method where the generated code will be appended.
*/
private void convertUdtsIntoEntities(String rawObjectName, String mappedObjectName, PropertyType type, MethodSpec.Builder getBuilder) {
if (type instanceof PropertyType.SingleEntity) {
ClassName entityClass = ((PropertyType.SingleEntity) type).entityName;
String entityHelperName = enclosingClass.addEntityHelperField(entityClass);
getBuilder.addStatement("$L = $L.get($L, lenient)", mappedObjectName, entityHelperName, rawObjectName);
} else if (type instanceof PropertyType.EntityList) {
getBuilder.addStatement("$L = $T.newArrayListWithExpectedSize($L.size())", mappedObjectName, Lists.class, rawObjectName);
PropertyType mappedElementType = ((PropertyType.EntityList) type).elementType;
TypeName rawElementType = mappedElementType.asRawTypeName();
String rawElementName = enclosingClass.getNameIndex().uniqueField("rawElement");
getBuilder.beginControlFlow("for ($T $L: $L)", rawElementType, rawElementName, rawObjectName);
String mappedElementName = enclosingClass.getNameIndex().uniqueField("mappedElement");
getBuilder.addStatement("$T $L", mappedElementType.asTypeName(), mappedElementName);
convertUdtsIntoEntities(rawElementName, mappedElementName, mappedElementType, getBuilder);
getBuilder.addStatement("$L.add($L)", mappedObjectName, mappedElementName).endControlFlow();
} else if (type instanceof PropertyType.EntitySet) {
getBuilder.addStatement("$L = $T.newLinkedHashSetWithExpectedSize($L.size())", mappedObjectName, Sets.class, rawObjectName);
PropertyType mappedElementType = ((PropertyType.EntitySet) type).elementType;
TypeName rawElementType = mappedElementType.asRawTypeName();
String rawElementName = enclosingClass.getNameIndex().uniqueField("rawElement");
getBuilder.beginControlFlow("for ($T $L: $L)", rawElementType, rawElementName, rawObjectName);
String mappedElementName = enclosingClass.getNameIndex().uniqueField("mappedElement");
getBuilder.addStatement("$T $L", mappedElementType.asTypeName(), mappedElementName);
convertUdtsIntoEntities(rawElementName, mappedElementName, mappedElementType, getBuilder);
getBuilder.addStatement("$L.add($L)", mappedObjectName, mappedElementName).endControlFlow();
} else if (type instanceof PropertyType.EntityMap) {
getBuilder.addStatement("$L = $T.newLinkedHashMapWithExpectedSize($L.size())", mappedObjectName, Maps.class, rawObjectName);
PropertyType mappedKeyType = ((PropertyType.EntityMap) type).keyType;
PropertyType mappedValueType = ((PropertyType.EntityMap) type).valueType;
String rawEntryName = enclosingClass.getNameIndex().uniqueField("rawEntry");
getBuilder.beginControlFlow("for ($T $L: $L.entrySet())", ParameterizedTypeName.get(ClassName.get(Map.Entry.class), mappedKeyType.asRawTypeName(), mappedValueType.asRawTypeName()), rawEntryName, rawObjectName);
String rawKeyName = CodeBlock.of("$L.getKey()", rawEntryName).toString();
String mappedKeyName;
if (mappedKeyType instanceof PropertyType.Simple) {
// no conversion, use the instance as-is
mappedKeyName = rawKeyName;
} else {
mappedKeyName = enclosingClass.getNameIndex().uniqueField("mappedKey");
getBuilder.addStatement("$T $L", mappedKeyType.asTypeName(), mappedKeyName);
convertUdtsIntoEntities(rawKeyName, mappedKeyName, mappedKeyType, getBuilder);
}
String rawValueName = CodeBlock.of("$L.getValue()", rawEntryName).toString();
String mappedValueName;
if (mappedValueType instanceof PropertyType.Simple) {
mappedValueName = rawValueName;
} else {
mappedValueName = enclosingClass.getNameIndex().uniqueField("mappedValue");
getBuilder.addStatement("$T $L", mappedValueType.asTypeName(), mappedValueName);
convertUdtsIntoEntities(rawValueName, mappedValueName, mappedValueType, getBuilder);
}
getBuilder.addStatement("$L.put($L, $L)", mappedObjectName, mappedKeyName, mappedValueName).endControlFlow();
} else {
throw new AssertionError("Unsupported type " + type.asTypeName());
}
}
use of com.datastax.oss.driver.internal.mapper.processor.util.generation.PropertyType in project java-driver by datastax.
the class EntityHelperGetMethodGenerator method generate.
@Override
public Optional<MethodSpec> generate() {
MethodSpec.Builder getBuilder = MethodSpec.methodBuilder("get").addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).addParameter(ParameterSpec.builder(ClassName.get(GettableByName.class), "source").build()).addParameter(ParameterSpec.builder(TypeName.BOOLEAN, "lenient").build()).returns(entityDefinition.getClassName());
TypeName returnType = entityDefinition.getClassName();
String resultName = "returnValue";
boolean mutable = entityDefinition.isMutable();
if (mutable) {
// Create an instance now, we'll call the setters as we go through the properties
getBuilder.addStatement("$1T $2L = new $1T()", returnType, resultName);
}
// We store each read property into a local variable, store the names here (this is only used if
// the entity is immutable, we'll call the all-arg constructor at the end).
List<String> propertyValueNames = new ArrayList<>();
for (PropertyDefinition property : entityDefinition.getAllValues()) {
PropertyType type = property.getType();
CodeBlock cqlName = property.getCqlName();
String setterName = property.getSetterName();
String propertyValueName = enclosingClass.getNameIndex().uniqueField("propertyValue");
propertyValueNames.add(propertyValueName);
if (type instanceof PropertyType.Simple) {
TypeName typeName = ((PropertyType.Simple) type).typeName;
String primitiveAccessor = GeneratedCodePatterns.PRIMITIVE_ACCESSORS.get(typeName);
if (primitiveAccessor != null) {
// int propertyValue1 = source.getInt("length");
if (mutable) {
getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName).addStatement("$T $L = source.get$L($L)", typeName, propertyValueName, primitiveAccessor, cqlName).addStatement("$L.$L($L)", resultName, setterName, propertyValueName).endControlFlow();
} else {
getBuilder.addStatement("$T $L = !lenient || hasProperty(source, $L) ? source.get$L($L) : $L", typeName, propertyValueName, cqlName, primitiveAccessor, cqlName, typeName.equals(TypeName.BOOLEAN) ? false : 0);
}
} else if (typeName instanceof ClassName) {
// UUID propertyValue1 = source.get("id", UUID.class);
if (mutable) {
getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName).addStatement("$T $L = source.get($L, $T.class)", typeName, propertyValueName, cqlName, typeName).addStatement("$L.$L($L)", resultName, setterName, propertyValueName).endControlFlow();
} else {
getBuilder.addStatement("$T $L = !lenient || hasProperty(source, $L) ? source.get($L, $T.class) : null", typeName, propertyValueName, cqlName, cqlName, typeName);
}
} else {
// advantage in calling them instead of the generic get().
if (mutable) {
getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName).addStatement("$T $L = source.get($L, $L)", typeName, propertyValueName, cqlName, enclosingClass.addGenericTypeConstant(typeName)).addStatement("$L.$L($L)", resultName, setterName, propertyValueName).endControlFlow();
} else {
getBuilder.addStatement("$T $L = !lenient || hasProperty(source, $L) ? source.get($L, $L) : null", typeName, propertyValueName, cqlName, cqlName, enclosingClass.addGenericTypeConstant(typeName));
}
}
} else if (type instanceof PropertyType.SingleEntity) {
ClassName entityClass = ((PropertyType.SingleEntity) type).entityName;
// Other entity class: the CQL column is a mapped UDT:
// Dimensions propertyValue1;
// UdtValue udtValue1 = source.getUdtValue("dimensions");
// propertyValue1 = udtValue1 == null ? null : dimensionsHelper.get(udtValue1);
String udtValueName = enclosingClass.getNameIndex().uniqueField("udtValue");
if (mutable) {
getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName);
getBuilder.addStatement("$T $L", entityClass, propertyValueName);
} else {
getBuilder.addStatement("$T $L = null", entityClass, propertyValueName);
getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName);
}
getBuilder.addStatement("$T $L = source.getUdtValue($L)", UdtValue.class, udtValueName, cqlName);
// Get underlying udt object and set it on return type
String childHelper = enclosingClass.addEntityHelperField(entityClass);
getBuilder.addStatement("$L = $L == null ? null : $L.get($L, lenient)", propertyValueName, udtValueName, childHelper, udtValueName);
if (mutable) {
getBuilder.addStatement("$L.$L($L)", resultName, setterName, propertyValueName);
}
getBuilder.endControlFlow();
} else {
// }
if (mutable) {
getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName);
getBuilder.addStatement("$T $L", type.asTypeName(), propertyValueName);
} else {
getBuilder.addStatement("$T $L = null", type.asTypeName(), propertyValueName);
getBuilder.beginControlFlow("if (!lenient || hasProperty(source, $L))", cqlName);
}
String rawCollectionName = enclosingClass.getNameIndex().uniqueField("rawCollection");
TypeName rawCollectionType = type.asRawTypeName();
getBuilder.addStatement("$T $L = source.get($L, $L)", rawCollectionType, rawCollectionName, cqlName, enclosingClass.addGenericTypeConstant(rawCollectionType));
getBuilder.beginControlFlow("if ($L == null)", rawCollectionName).addStatement("$L = null", propertyValueName).nextControlFlow("else");
convertUdtsIntoEntities(rawCollectionName, propertyValueName, type, getBuilder);
getBuilder.endControlFlow();
if (mutable) {
getBuilder.addStatement("$L.$L($L)", resultName, setterName, propertyValueName);
}
getBuilder.endControlFlow();
}
}
if (mutable) {
// We've already created an instance and filled the properties as we went
getBuilder.addStatement("return returnValue");
} else {
// Assume an all-arg constructor exists, and call it with all the temporary variables
getBuilder.addCode("$[return new $T(", returnType);
for (int i = 0; i < propertyValueNames.size(); i++) {
getBuilder.addCode((i == 0 ? "\n$L" : ",\n$L"), propertyValueNames.get(i));
}
getBuilder.addCode(")$];");
}
return Optional.of(getBuilder.build());
}
use of com.datastax.oss.driver.internal.mapper.processor.util.generation.PropertyType 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;
}
Aggregations