use of org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement in project mdsal by opendaylight.
the class AbstractTypeObjectGenerator method createUnion.
@NonNull
private static GeneratedTransferObject createUnion(final List<GeneratedType> auxiliaryGeneratedTypes, final TypeBuilderFactory builderFactory, final EffectiveStatement<?, ?> definingStatement, final UnionDependencies dependencies, final JavaTypeName typeName, final ModuleGenerator module, final TypeEffectiveStatement<?> type, final boolean isTypedef, final TypeDefinition<?> typedef) {
final GeneratedUnionBuilder builder = builderFactory.newGeneratedUnionBuilder(typeName);
builder.addImplementsType(BindingTypes.TYPE_OBJECT);
builder.setIsUnion(true);
// builder.setSchemaPath(typedef.getPath());
builder.setModuleName(module.statement().argument().getLocalName());
builderFactory.addCodegenInformation(definingStatement, builder);
annotateDeprecatedIfNecessary(definingStatement, builder);
// Pattern string is the key, XSD regex is the value. The reason for this choice is that the pattern carries
// also negation information and hence guarantees uniqueness.
final Map<String, String> expressions = new HashMap<>();
// Linear list of properties generated from subtypes. We need this information for runtime types, as it allows
// direct mapping of type to corresponding property -- without having to resort to re-resolving the leafrefs
// again.
final List<String> typeProperties = new ArrayList<>();
for (EffectiveStatement<?, ?> stmt : type.effectiveSubstatements()) {
if (stmt instanceof TypeEffectiveStatement) {
final TypeEffectiveStatement<?> subType = (TypeEffectiveStatement<?>) stmt;
final QName subName = subType.argument();
final String localName = subName.getLocalName();
String propSource = localName;
final Type generatedType;
if (TypeDefinitions.UNION.equals(subName)) {
final JavaTypeName subUnionName = typeName.createEnclosed(provideAvailableNameForGenTOBuilder(typeName.simpleName()));
final GeneratedTransferObject subUnion = createUnion(auxiliaryGeneratedTypes, builderFactory, definingStatement, dependencies, subUnionName, module, subType, isTypedef, subType.getTypeDefinition());
builder.addEnclosingTransferObject(subUnion);
propSource = subUnionName.simpleName();
generatedType = subUnion;
} else if (TypeDefinitions.ENUMERATION.equals(subName)) {
final Enumeration subEnumeration = createEnumeration(builderFactory, typeName.createEnclosed(BindingMapping.getClassName(localName), "$"), module, (EnumTypeDefinition) subType.getTypeDefinition());
builder.addEnumeration(subEnumeration);
generatedType = subEnumeration;
} else if (TypeDefinitions.BITS.equals(subName)) {
final GeneratedTransferObject subBits = createBits(builderFactory, typeName.createEnclosed(BindingMapping.getClassName(localName), "$"), module, subType.getTypeDefinition(), isTypedef);
builder.addEnclosingTransferObject(subBits);
generatedType = subBits;
} else if (TypeDefinitions.IDENTITYREF.equals(subName)) {
generatedType = verifyNotNull(dependencies.identityTypes.get(stmt), "Cannot resolve identityref %s in %s", stmt, definingStatement).methodReturnType(builderFactory);
} else if (TypeDefinitions.LEAFREF.equals(subName)) {
generatedType = verifyNotNull(dependencies.leafTypes.get(stmt), "Cannot resolve leafref %s in %s", stmt, definingStatement).methodReturnType(builderFactory);
} else {
Type baseType = SIMPLE_TYPES.get(subName);
if (baseType == null) {
// This has to be a reference to a typedef, let's lookup it up and pick up its type
final AbstractTypeObjectGenerator<?, ?> baseGen = verifyNotNull(dependencies.baseTypes.get(subName), "Cannot resolve base type %s in %s", subName, definingStatement);
baseType = baseGen.methodReturnType(builderFactory);
// FIXME: This is legacy behaviour for leafrefs:
if (baseGen.refType instanceof TypeReference.Leafref) {
// if there already is a compatible property, do not generate a new one
final Type search = baseType;
final String matching = builder.getProperties().stream().filter(prop -> search == ((GeneratedPropertyBuilderImpl) prop).getReturnType()).findFirst().map(GeneratedPropertyBuilder::getName).orElse(null);
if (matching != null) {
typeProperties.add(matching);
continue;
}
// ... otherwise generate this weird property name
propSource = BindingMapping.getUnionLeafrefMemberName(builder.getName(), baseType.getName());
}
}
expressions.putAll(resolveRegExpressions(subType.getTypeDefinition()));
generatedType = restrictType(baseType, BindingGeneratorUtil.getRestrictions(type.getTypeDefinition()), builderFactory);
}
final String propName = BindingMapping.getPropertyName(propSource);
typeProperties.add(propName);
if (builder.containsProperty(propName)) {
/*
* FIXME: this is not okay, as we are ignoring multiple base types. For example in the case of:
*
* type union {
* type string {
* length 1..5;
* }
* type string {
* length 8..10;
* }
* }
*
* We are ending up losing the information about 8..10 being an alternative. This is also the case
* for leafrefs -- we are performing property compression as well (see above). While it is alluring
* to merge these into 'length 1..5|8..10', that may not be generally feasible.
*
* We should resort to a counter of conflicting names, i.e. the second string would be mapped to
* 'string1' or similar.
*/
continue;
}
final GeneratedPropertyBuilder propBuilder = builder.addProperty(propName).setReturnType(generatedType);
builder.addEqualsIdentity(propBuilder);
builder.addHashIdentity(propBuilder);
builder.addToStringProperty(propBuilder);
}
}
// Record property names if needed
builder.setTypePropertyNames(typeProperties);
addStringRegExAsConstant(builder, expressions);
addUnits(builder, typedef);
makeSerializable(builder);
final GeneratedTransferObject ret = builder.build();
// Define a corresponding union builder. Typedefs are always anchored at a Java package root,
// so we are placing the builder alongside the union.
final GeneratedTOBuilder unionBuilder = builderFactory.newGeneratedTOBuilder(unionBuilderName(typeName));
unionBuilder.setIsUnionBuilder(true);
unionBuilder.addMethod("getDefaultInstance").setAccessModifier(AccessModifier.PUBLIC).setStatic(true).setReturnType(ret).addParameter(Types.STRING, "defaultValue");
auxiliaryGeneratedTypes.add(unionBuilder.build());
return ret;
}
Aggregations