*/
package org.opendaylight.mdsal.binding.generator.impl.reactor;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Verify.verify;
import static com.google.common.base.Verify.verifyNotNull;
import org.opendaylight.mdsal.binding.model.ri.Types;
import org.opendaylight.mdsal.binding.model.ri.generated.type.builder.AbstractEnumerationBuilder;
import org.opendaylight.mdsal.binding.model.ri.generated.type.builder.GeneratedPropertyBuilderImpl;
+import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.binding.RegexPatterns;
* type indirection in YANG constructs is therefore explicitly excluded from the generated Java code, but the Binding
* Specification still takes them into account when determining types as outlined above.
*/
-abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> extends AbstractDependentGenerator<T> {
+abstract class AbstractTypeObjectGenerator<S extends EffectiveStatement<?, ?>, R extends RuntimeType>
+ extends AbstractDependentGenerator<S, R> {
private static final class UnionDependencies implements Immutable {
private final Map<EffectiveStatement<?, ?>, TypeReference> identityTypes = new HashMap<>();
private final Map<EffectiveStatement<?, ?>, TypeReference> leafTypes = new HashMap<>();
private final TypeEffectiveStatement<?> type;
+ // FIXME: these fields should be better-controlled with explicit sequencing guards. It it currently stands, we are
+ // expending two (or more) additional fields to express downstream linking. If we had the concept of
+ // resolution step (an enum), we could just get by with a simple queue of Step/Callback pairs, which would
+ // trigger as needed. See how we manage baseGen/inferred fields.
+
/**
* The generator corresponding to our YANG base type. It produces the superclass of our encapsulated type. If it is
* {@code null}, this generator is the root of the hierarchy.
private TypeReference refType;
private List<GeneratedType> auxiliaryGeneratedTypes = List.of();
private UnionDependencies unionDependencies;
- private List<AbstractTypeObjectGenerator<?>> inferred = List.of();
+ private List<AbstractTypeObjectGenerator<?, ?>> inferred = List.of();
+
+ /**
+ * The type of single-element return type of the getter method associated with this generator. This is retained for
+ * run-time type purposes. It may be uninitialized, in which case this object must have a generated type.
+ */
+ private Type methodReturnTypeElement;
- AbstractTypeObjectGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
+ AbstractTypeObjectGenerator(final S statement, final AbstractCompositeGenerator<?, ?> parent) {
super(statement, parent);
type = statement().findFirstEffectiveSubstatement(TypeEffectiveStatement.class).orElseThrow();
}
return;
}
- final AbstractExplicitGenerator<?> prev = previous();
+ final AbstractExplicitGenerator<S, R> prev = previous();
if (prev != null) {
verify(prev instanceof AbstractTypeObjectGenerator, "Unexpected previous %s", prev);
- ((AbstractTypeObjectGenerator<?>) prev).linkInferred(this);
+ ((AbstractTypeObjectGenerator<S, R>) prev).linkInferred(this);
} else {
linkBaseGen(context.resolveTypedef(typeName));
}
}
- private void linkInferred(final AbstractTypeObjectGenerator<?> downstream) {
+ private void linkInferred(final AbstractTypeObjectGenerator<?, ?> downstream) {
if (inferred == null) {
downstream.linkBaseGen(verifyNotNull(baseGen, "Mismatch on linking between %s and %s", this, downstream));
return;
private void linkBaseGen(final TypedefGenerator upstreamBaseGen) {
verify(baseGen == null, "Attempted to replace base %s with %s in %s", baseGen, upstreamBaseGen, this);
- final List<AbstractTypeObjectGenerator<?>> downstreams = verifyNotNull(inferred,
+ final List<AbstractTypeObjectGenerator<?, ?>> downstreams = verifyNotNull(inferred,
"Duplicated linking of %s", this);
baseGen = verifyNotNull(upstreamBaseGen);
baseGen.addDerivedGenerator(this);
inferred = null;
- for (AbstractTypeObjectGenerator<?> downstream : downstreams) {
+ for (AbstractTypeObjectGenerator<?, ?> downstream : downstreams) {
downstream.linkBaseGen(upstreamBaseGen);
}
}
.map(context::resolveIdentity)
.collect(Collectors.toUnmodifiableList()));
} else if (TypeDefinitions.LEAFREF.equals(arg)) {
- refType = TypeReference.leafRef(context.resolveLeafref(
- type.findFirstEffectiveSubstatementArgument(PathEffectiveStatement.class).orElseThrow()));
+ final AbstractTypeObjectGenerator<?, ?> targetGenerator = context.resolveLeafref(
+ type.findFirstEffectiveSubstatementArgument(PathEffectiveStatement.class).orElseThrow());
+ checkArgument(targetGenerator != this, "Effective model contains self-referencing leaf %s",
+ statement().argument());
+ refType = TypeReference.leafRef(targetGenerator);
} else if (TypeDefinitions.UNION.equals(arg)) {
unionDependencies = new UnionDependencies(type, context);
LOG.trace("Resolved union {} to dependencies {}", type, unionDependencies);
return methodReturnElementType(builderFactory);
}
+ @Override
+ final Type runtimeJavaType() {
+ if (methodReturnTypeElement != null) {
+ return methodReturnTypeElement;
+ }
+ final var genType = generatedType();
+ if (genType.isPresent()) {
+ return genType.orElseThrow();
+ }
+ final var prev = verifyNotNull(previous(), "No previous generator for %s", this);
+ return prev.runtimeJavaType();
+ }
+
final @NonNull Type methodReturnElementType(final @NonNull TypeBuilderFactory builderFactory) {
+ var local = methodReturnTypeElement;
+ if (local == null) {
+ methodReturnTypeElement = local = createMethodReturnElementType(builderFactory);
+ }
+ return local;
+ }
+
+ private @NonNull Type createMethodReturnElementType(final @NonNull TypeBuilderFactory builderFactory) {
final GeneratedType generatedType = tryGeneratedType(builderFactory);
if (generatedType != null) {
// We have generated a type here, so return it. This covers 'bits', 'enumeration' and 'union'.
return refType.methodReturnType(builderFactory);
}
- final AbstractExplicitGenerator<?> prev = previous();
+ final AbstractExplicitGenerator<?, ?> prev = previous();
if (prev != null) {
// We have been added through augment/uses, defer to the original definition
return prev.methodReturnType(builderFactory);
return;
}
- final AbstractTypeObjectGenerator<?> prev =
- (AbstractTypeObjectGenerator<?>) verifyNotNull(previous(), "Missing previous link in %s", this);
+ final AbstractTypeObjectGenerator<?, ?> prev =
+ (AbstractTypeObjectGenerator<?, ?>) verifyNotNull(previous(), "Missing previous link in %s", this);
if (prev.refType instanceof ResolvedLeafref) {
// We should be already inheriting the correct type
return;
// builder.setSchemaPath(typedef.getPath());
builder.setModuleName(module.statement().argument().getLocalName());
- addCodegenInformation(typedef, builder);
+ builderFactory.addCodegenInformation(typedef, builder);
annotateDeprecatedIfNecessary(typedef, builder);
makeSerializable(builder);
return builder.build();
// builder.setSchemaPath(typedef.getPath());
builder.setModuleName(moduleName);
- addCodegenInformation(typedef, builder);
+ builderFactory.addCodegenInformation(typedef, builder);
annotateDeprecatedIfNecessary(typedef, builder);
// builder.setSchemaPath(typedef.getPath());
builder.setModuleName(module.statement().argument().getLocalName());
- addCodegenInformation(definingStatement, builder);
+ builderFactory.addCodegenInformation(definingStatement, builder);
annotateDeprecatedIfNecessary(definingStatement, builder);
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(
+ final AbstractTypeObjectGenerator<?, ?> baseGen = verifyNotNull(
dependencies.baseTypes.get(subName), "Cannot resolve base type %s in %s", subName,
definingStatement);
baseType = baseGen.methodReturnType(builderFactory);
for (String part : unionName.localNameComponents()) {
sb.append(part);
}
- return JavaTypeName.create(unionName.packageName(), sb.append("Builder").toString());
+ return JavaTypeName.create(unionName.packageName(), sb.append(BindingMapping.BUILDER_SUFFIX).toString());
}
// FIXME: we should not rely on TypeDefinition