From: Robert Varga Date: Thu, 11 Jan 2024 22:37:43 +0000 (+0100) Subject: Reparent ChoiceCodecContext X-Git-Tag: v13.0.0~38 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=mdsal.git;a=commitdiff_plain;h=f3be50ed801e5de305eb46b824e6bc3c6075e4bc Reparent ChoiceCodecContext Choice as itself does not map to a DataObject, but rather to a ChoiceIn -- it is the individual cases that also map to DataObject. In this patch we reparent ChoiceCodecContext to be a subclass of DataContainerCodecContext, which allows us to ditch the idea that a there is a InstanceIdentifier.PathArgument corresponding to this context. A nice bonus is that we end up with exactly one serialization method, which is delegating to the individual case. Another nice thing is we have a natural place to host the case lookup logic -- which fits squarely with ChoiceCodecContext.bindingPathArgumentChild() contract. JIRA: MDSAL-815 Change-Id: I12a80c849f6405e0e5723afc3f31704a2ad604a6 Signed-off-by: Robert Varga --- diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractDataObjectModification.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractDataObjectModification.java index 57ab7c906e..71d306df30 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractDataObjectModification.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractDataObjectModification.java @@ -28,6 +28,8 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.mdsal.binding.api.DataObjectModification; import org.opendaylight.mdsal.binding.dom.codec.api.BindingAugmentationCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingChoiceCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataContainerCodecTreeNode; import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; import org.opendaylight.mdsal.binding.dom.codec.api.CommonDataObjectCodecTreeNode; import org.opendaylight.yangtools.yang.binding.Augmentation; @@ -321,7 +323,7 @@ abstract sealed class AbstractDataObjectModification> result, - final CommonDataObjectCodecTreeNode parentCodec, final DataTreeCandidateNode parent, + final BindingDataContainerCodecTreeNode parentCodec, final DataTreeCandidateNode parent, final Collection children) { final var augmentChildren = ArrayListMultimap., DataTreeCandidateNode>create(); @@ -341,6 +343,8 @@ abstract sealed class AbstractDataObjectModification childAugmentationCodec) { // Defer creation once we have collected all modified children augmentChildren.put(childAugmentationCodec, domChildNode); + } else if (childCodec instanceof BindingChoiceCodecTreeNode childChoiceCodec) { + populateList(result, childChoiceCodec, domChildNode, domChildNode.childNodes()); } else { throw new VerifyException("Unhandled codec %s for type %s".formatted(childCodec, type)); } diff --git a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingChoiceCodecTreeNode.java b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingChoiceCodecTreeNode.java new file mode 100644 index 0000000000..b9c72d25cf --- /dev/null +++ b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingChoiceCodecTreeNode.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.dom.codec.api; + +import org.opendaylight.yangtools.yang.binding.ChoiceIn; + +/** + * A {@link BindingDataContainerCodecTreeNode} corresponding to a base {@link ChoiceIn}. + * + * @param ChoiceIn type + */ +public interface BindingChoiceCodecTreeNode> extends BindingDataContainerCodecTreeNode { + +} diff --git a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataContainerCodecTreeNode.java b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataContainerCodecTreeNode.java index 7a6321d66c..c2ef310ca4 100644 --- a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataContainerCodecTreeNode.java +++ b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataContainerCodecTreeNode.java @@ -47,7 +47,7 @@ public non-sealed interface BindingDataContainerCodecTreeNode @Nullable CommonDataObjectCodecTreeNode streamChild(@NonNull Class childClass); + @Nullable BindingDataContainerCodecTreeNode streamChild(@NonNull Class childClass); default > @Nullable BindingAugmentationCodecTreeNode streamAugmentation( final @NonNull Class childClass) { diff --git a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeParent.java b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeParent.java index bfaf2aba4a..8ac63661a8 100644 --- a/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeParent.java +++ b/binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataObjectCodecTreeParent.java @@ -46,7 +46,7 @@ public interface BindingDataObjectCodecTreeParent { * @throws NullPointerException if {@code childClass} is {@code null} * @throws IllegalArgumentException If supplied child class is not valid in specified context. */ - @NonNull CommonDataObjectCodecTreeNode getStreamChild(@NonNull Class childClass); + @NonNull BindingDataContainerCodecTreeNode getStreamChild(@NonNull Class childClass); default > @NonNull BindingAugmentationCodecTreeNode getStreamAugmentation( final @NonNull Class childClass) { diff --git a/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java b/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java index f24235daec..3a1a8b3814 100644 --- a/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java +++ b/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java @@ -14,6 +14,7 @@ import java.util.Map.Entry; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.binding.dom.codec.api.BindingAugmentationCodecTreeNode; import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataContainerCodecTreeNode; import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; import org.opendaylight.mdsal.binding.dom.codec.api.BindingIdentityCodec; import org.opendaylight.mdsal.binding.dom.codec.api.BindingInstanceIdentifierCodec; @@ -251,7 +252,7 @@ public abstract class ForwardingBindingDOMCodecServices extends ForwardingObject } @Override - public CommonDataObjectCodecTreeNode getStreamChild(final Class childClass) { + public BindingDataContainerCodecTreeNode getStreamChild(final Class childClass) { return delegate().getStreamChild(childClass); } } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataObjectCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataObjectCodecContext.java index d0e2f04db3..65394235dd 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataObjectCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataObjectCodecContext.java @@ -43,8 +43,8 @@ import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus; public abstract sealed class AbstractDataObjectCodecContext extends CommonDataObjectCodecContext permits AugmentationCodecContext, DataObjectCodecContext { - private final ImmutableMap, CommonDataObjectCodecPrototype> byBindingArgClass; - private final ImmutableMap, CommonDataObjectCodecPrototype> byStreamClass; + private final ImmutableMap, DataContainerPrototype> byBindingArgClass; + private final ImmutableMap, DataContainerPrototype> byStreamClass; private final ImmutableMap byYang; private final ImmutableMap leafChild; @@ -64,7 +64,7 @@ public abstract sealed class AbstractDataObjectCodecContext streamChildPrototype(final Class childClass) { + DataContainerPrototype streamChildPrototype(final Class childClass) { return byStreamClass.get(childClass); } @@ -75,27 +75,17 @@ public abstract sealed class AbstractDataObjectCodecContext choice) { - choice.addYangPathArgument(arg, builder); - - final var caseType = arg.getCaseType(); - final var type = arg.getType(); - final DataContainerCodecContext caze; - if (caseType.isPresent()) { - // Non-ambiguous addressing this should not pose any problems - caze = choice.getStreamChild(caseType.orElseThrow()); - } else { - caze = choice.getCaseByChildClass(type); - } - - caze.addYangPathArgument(arg, builder); - return caze.bindingPathArgumentChild(arg, builder); - } context.addYangPathArgument(arg, builder); - return context; + if (context instanceof CommonDataObjectCodecContext dataObject) { + return dataObject; + } else if (context instanceof ChoiceCodecContext choice) { + return choice.bindingPathArgumentChild(arg, builder); + } else { + throw new IllegalStateException("Unhandled context " + context); + } } - @Nullable CommonDataObjectCodecPrototype pathChildPrototype(final @NonNull Class argType) { + @Nullable DataContainerPrototype pathChildPrototype(final @NonNull Class argType) { return byBindingArgClass.get(argType); } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AugmentationCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AugmentationCodecPrototype.java index 70b450387f..dccf09ae3c 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AugmentationCodecPrototype.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AugmentationCodecPrototype.java @@ -27,7 +27,7 @@ final class AugmentationCodecPrototype extends CommonDataObjectCodecPrototype(key, list, BindingCodecContext.this) : MapCodecContext.of(key, list, BindingCodecContext.this); } else if (childSchema instanceof ChoiceRuntimeType choice) { - return new ChoiceCodecContext<>(key, choice, BindingCodecContext.this); + return new ChoiceCodecContext<>(key.asSubclass(ChoiceIn.class), choice, BindingCodecContext.this); } else if (childSchema == null) { throw DataContainerCodecContext.childNullException(context, key, "%s is not top-level item.", key); } else { @@ -753,10 +753,10 @@ public final class BindingCodecContext extends AbstractBindingNormalizedNodeSeri @Override @SuppressWarnings("unchecked") - public CommonDataObjectCodecContext getStreamChild(final Class childClass) { + public DataContainerCodecContext getStreamChild(final Class childClass) { final var result = Notification.class.isAssignableFrom(childClass) ? getNotificationContext(childClass) : getOrRethrow(childrenByClass, childClass); - return (CommonDataObjectCodecContext) result; + return (DataContainerCodecContext) result; } @Override diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecContext.java index 8e0adc74b7..8454de4f25 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecContext.java @@ -9,7 +9,6 @@ package org.opendaylight.mdsal.binding.dom.codec.impl; import static com.google.common.base.Preconditions.checkArgument; -import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -17,25 +16,23 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.MultimapBuilder.SetMultimapBuilder; import com.google.common.collect.Multimaps; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; +import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeCachingCodec; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingChoiceCodecTreeNode; import org.opendaylight.mdsal.binding.model.api.JavaTypeName; import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext; import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType; import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType; -import org.opendaylight.yangtools.yang.binding.BindingObject; +import org.opendaylight.yangtools.yang.binding.ChoiceIn; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.binding.contract.Naming; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -94,8 +91,9 @@ import org.slf4j.LoggerFactory; * ambiguous reference and issue warn once when they are encountered -- tracking warning information in * {@link #ambiguousByCaseChildWarnings}. */ -final class ChoiceCodecContext extends CommonDataObjectCodecContext - implements BindingDataObjectCodecTreeNode { +final class ChoiceCodecContext> + extends DataContainerCodecContext> + implements BindingChoiceCodecTreeNode { private static final Logger LOG = LoggerFactory.getLogger(ChoiceCodecContext.class); private final ImmutableListMultimap, CommonDataObjectCodecPrototype> ambiguousByCaseChildClass; @@ -104,11 +102,12 @@ final class ChoiceCodecContext extends CommonDataObjectCod private final ImmutableMap, CommonDataObjectCodecPrototype> byClass; private final Set> ambiguousByCaseChildWarnings; - ChoiceCodecContext(final Class cls, final ChoiceRuntimeType type, final CodecContextFactory factory) { - this(new ChoiceCodecPrototype(Item.of(cls), type, factory)); + ChoiceCodecContext(final Class javaClass, final ChoiceRuntimeType runtimeType, + final CodecContextFactory contextFactory) { + this(new ChoiceCodecPrototype<>(contextFactory, runtimeType, javaClass)); } - ChoiceCodecContext(final ChoiceCodecPrototype prototype) { + ChoiceCodecContext(final ChoiceCodecPrototype prototype) { super(prototype); final var byYangCaseChildBuilder = new HashMap(); final var byClassBuilder = new HashMap, CommonDataObjectCodecPrototype>(); @@ -222,54 +221,43 @@ final class ChoiceCodecContext extends CommonDataObjectCod } @Override - CaseCodecPrototype yangChildSupplier(final NodeIdentifier arg) { + CodecContextSupplier yangChildSupplier(final NodeIdentifier arg) { return byYangCaseChild.get(arg); } @Override - @SuppressWarnings("unchecked") - @SuppressFBWarnings(value = "NP_NONNULL_RETURN_VIOLATION", justification = "See FIXME below") - public D deserialize(final NormalizedNode data) { - final var casted = checkDataArgument(ChoiceNode.class, data); - final var first = Iterables.getFirst(casted.body(), null); - - if (first == null) { - // FIXME: this needs to be sorted out + protected T deserializeObject(final NormalizedNode normalizedNode) { + final var casted = checkDataArgument(ChoiceNode.class, normalizedNode); + final var it = casted.body().iterator(); + if (!it.hasNext()) { + // FIXME: can this reasonably happen? Empty choice nodes do not have semantics, or do they? return null; } - final var caze = byYangCaseChild.get(first.name()); - return ((CaseCodecContext) caze.getCodecContext()).deserialize(data); - } - @Override - public NormalizedNode serialize(final D data) { - return serializeImpl(data); - } - - @Override - protected Object deserializeObject(final NormalizedNode normalizedNode) { - return deserialize(normalizedNode); + final var childName = it.next().name(); + final var caze = childNonNull(byYangCaseChild.get(childName), childName, "%s is not a valid case child of %s", + childName, this); + return (T) caze.getCodecContext().deserializeObject(casted); } @Override - public PathArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) { - checkArgument(getDomPathArgument().equals(arg)); - return null; - } - - @Override - public YangInstanceIdentifier.PathArgument serializePathArgument(final PathArgument arg) { - // FIXME: check for null, since binding container is null. - return getDomPathArgument(); - } + public CommonDataObjectCodecContext bindingPathArgumentChild(final PathArgument arg, + final List builder) { + final var caseType = arg.getCaseType(); + final var type = arg.getType(); + final DataContainerCodecContext caze; + if (caseType.isPresent()) { + // Non-ambiguous addressing this should not pose any problems + caze = getStreamChild(caseType.orElseThrow()); + } else { + caze = getCaseByChildClass(type); + } - @Override - public BindingNormalizedNodeCachingCodec createCachingCodec( - final ImmutableCollection> cacheSpecifier) { - return createCachingCodec(this, cacheSpecifier); + caze.addYangPathArgument(arg, builder); + return caze.bindingPathArgumentChild(arg, builder); } - DataContainerCodecContext getCaseByChildClass(final @NonNull Class type) { + private DataContainerCodecContext getCaseByChildClass(final @NonNull Class type) { var result = byCaseChildClass.get(type); if (result == null) { // We have not found an unambiguous result, try ambiguous ones @@ -282,13 +270,13 @@ final class ChoiceCodecContext extends CommonDataObjectCod Ambiguous reference {} to child of {} resolved to {}, the first case in {} This mapping is \ not guaranteed to be stable and is subject to variations based on runtime circumstances. \ Please see the stack trace for hints about the source of ambiguity.""", - type, bindingArg(), result.javaClass(), + type, getBindingClass(), result.javaClass(), Lists.transform(inexact, CommonDataObjectCodecPrototype::javaClass), new Throwable()); } } } - return childNonNull(result, type, "Class %s is not child of any cases for %s", type, bindingArg()) + return childNonNull(result, type, "Class %s is not child of any cases for %s", type, getBindingClass()) .getCodecContext(); } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecPrototype.java index 7fc1f3cca9..f5ac3d6702 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecPrototype.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecPrototype.java @@ -7,20 +7,40 @@ */ package org.opendaylight.mdsal.binding.dom.codec.impl; +import static java.util.Objects.requireNonNull; + +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; +import org.opendaylight.yangtools.yang.binding.ChoiceIn; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; /** * A prototype for {@link ChoiceCodecContext}. */ -final class ChoiceCodecPrototype extends DataObjectCodecPrototype { - ChoiceCodecPrototype(final Item item, final ChoiceRuntimeType type, final CodecContextFactory factory) { - super(item, NodeIdentifier.create(type.statement().argument()), type, factory); +final class ChoiceCodecPrototype> + extends DataContainerPrototype, ChoiceRuntimeType> { + private final @NonNull NodeIdentifier yangArg; + private final @NonNull Class javaClass; + + ChoiceCodecPrototype(final CodecContextFactory contextFactory, final ChoiceRuntimeType runtimeType, + final Class javaClass) { + super(contextFactory, runtimeType); + this.javaClass = requireNonNull(javaClass); + yangArg = NodeIdentifier.create(runtimeType.statement().argument()); + } + + @Override + Class javaClass() { + return javaClass; + } + + @Override + NodeIdentifier yangArg() { + return yangArg; } @Override - ChoiceCodecContext createInstance() { + ChoiceCodecContext createInstance() { return new ChoiceCodecContext<>(this); } } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecContext.java index f5416d24f5..219ef7ca84 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecContext.java @@ -12,7 +12,6 @@ import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; /** * Base implementation of {@link CommonDataObjectCodecTreeNode}. @@ -20,22 +19,11 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent abstract sealed class CommonDataObjectCodecContext extends DataContainerCodecContext> implements CommonDataObjectCodecTreeNode - permits AbstractDataObjectCodecContext, ChoiceCodecContext { + permits AbstractDataObjectCodecContext { CommonDataObjectCodecContext(final CommonDataObjectCodecPrototype prototype) { super(prototype); } - @SuppressWarnings("unchecked") - @Override - public final Class getBindingClass() { - return Class.class.cast(prototype().javaClass()); - } - - @Override - protected NodeIdentifier getDomPathArgument() { - return prototype().getYangArg(); - } - /** * Returns deserialized Binding Path Argument from YANG instance identifier. */ diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecPrototype.java index 49b863b006..0962fea4ad 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecPrototype.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecPrototype.java @@ -13,7 +13,6 @@ import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; /** * Common superclass for {@link DataObjectCodecPrototype} and {@link AugmentationCodecPrototype}. @@ -38,6 +37,4 @@ abstract sealed class CommonDataObjectCodecPrototype getBindingArg() { return bindingArg; } - - abstract @NonNull NodeIdentifier getYangArg(); } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerAnalysis.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerAnalysis.java index cbb3a97419..c799bbbbac 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerAnalysis.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerAnalysis.java @@ -26,6 +26,7 @@ import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType; import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType; import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType; import org.opendaylight.yangtools.util.ClassLoaderUtils; +import org.opendaylight.yangtools.yang.binding.ChoiceIn; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.OpaqueObject; import org.opendaylight.yangtools.yang.binding.contract.Naming; @@ -42,8 +43,8 @@ final class DataContainerAnalysis { private static final Logger LOG = LoggerFactory.getLogger(DataContainerAnalysis.class); // Needed for DataContainerCodecContext - final @NonNull ImmutableMap, CommonDataObjectCodecPrototype> byStreamClass; - final @NonNull ImmutableMap, CommonDataObjectCodecPrototype> byBindingArgClass; + final @NonNull ImmutableMap, DataContainerPrototype> byStreamClass; + final @NonNull ImmutableMap, DataContainerPrototype> byBindingArgClass; final @NonNull ImmutableMap byYang; final @NonNull ImmutableMap leafNodes; @@ -73,8 +74,8 @@ final class DataContainerAnalysis { } leafNodes = leafBuilder.build(); - final var byBindingArgClassBuilder = new HashMap, CommonDataObjectCodecPrototype>(); - final var byStreamClassBuilder = new HashMap, CommonDataObjectCodecPrototype>(); + final var byBindingArgClassBuilder = new HashMap, DataContainerPrototype>(); + final var byStreamClassBuilder = new HashMap, DataContainerPrototype>(); final var daoPropertiesBuilder = new HashMap, PropertyInfo>(); for (var childDataObj : clsToMethod.entrySet()) { final var method = childDataObj.getValue(); @@ -91,14 +92,11 @@ final class DataContainerAnalysis { final var childProto = getChildPrototype(runtimeType, factory, itemFactory, retClass); byStreamClassBuilder.put(childProto.javaClass(), childProto); - byYangBuilder.put(childProto.getYangArg(), childProto); - - // FIXME: It really feels like we should be specializing DataContainerCodecPrototype so as to ditch - // createInstance() and then we could do an instanceof check instead. - if (childProto.runtimeType() instanceof ChoiceRuntimeType) { - final var choice = (ChoiceCodecContext) childProto.getCodecContext(); - for (var cazeChild : choice.getCaseChildrenClasses()) { - byBindingArgClassBuilder.put(cazeChild, childProto); + byYangBuilder.put(childProto.yangArg(), childProto); + + if (childProto instanceof ChoiceCodecPrototype choiceProto) { + for (var cazeChild : choiceProto.getCodecContext().getCaseChildrenClasses()) { + byBindingArgClassBuilder.put(cazeChild, choiceProto); } } } @@ -127,7 +125,7 @@ final class DataContainerAnalysis { daoProperties = ImmutableMap.copyOf(daoPropertiesBuilder); } - private static @NonNull CommonDataObjectCodecPrototype getChildPrototype(final CompositeRuntimeType type, + private static @NonNull DataContainerPrototype getChildPrototype(final CompositeRuntimeType type, final CodecContextFactory factory, final CodecItemFactory itemFactory, final Class childClass) { final var child = type.bindingChild(JavaTypeName.create(childClass)); @@ -135,6 +133,11 @@ final class DataContainerAnalysis { throw DataContainerCodecContext.childNullException(factory.getRuntimeContext(), childClass, "Node %s does not have child named %s", type, childClass); } + + if (child instanceof ChoiceRuntimeType choice) { + return new ChoiceCodecPrototype<>(factory, choice, childClass.asSubclass(ChoiceIn.class)); + } + final var item = itemFactory.createItem(childClass, child.statement()); if (child instanceof ContainerLikeRuntimeType containerLike) { if (child instanceof ContainerRuntimeType container @@ -145,14 +148,11 @@ final class DataContainerAnalysis { } else if (child instanceof ListRuntimeType list) { return list.keyType() != null ? new MapCodecPrototype(item, list, factory) : new ListCodecPrototype(item, list, factory); - } else if (child instanceof ChoiceRuntimeType choice) { - return new ChoiceCodecPrototype(item, choice, factory); } else { throw new UnsupportedOperationException("Unhandled type " + child); } } - // FIXME: MDSAL-780: these methods perform analytics using java.lang.reflect to acquire the basic shape of the // class. This is not exactly AOT friendly, as most of the information should be provided by // CompositeRuntimeType. diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java index a1fd1bfc29..ebd628c0ff 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java @@ -65,7 +65,7 @@ import org.slf4j.LoggerFactory; abstract sealed class DataContainerCodecContext> extends CodecContext implements BindingDataContainerCodecTreeNode - permits CommonDataObjectCodecContext { + permits ChoiceCodecContext, CommonDataObjectCodecContext { private static final Logger LOG = LoggerFactory.getLogger(DataContainerCodecContext.class); private static final VarHandle EVENT_STREAM_SERIALIZER; @@ -95,6 +95,18 @@ abstract sealed class DataContainerCodecContext getBindingClass() { + return (Class) prototype().javaClass(); + } + + // overridden in AugmentationCodecContext + @Override + protected NodeIdentifier getDomPathArgument() { + return prototype.yangArg(); + } + @Override public final ChildAddressabilitySummary getChildAddressabilitySummary() { return childAddressabilitySummary; @@ -117,12 +129,8 @@ abstract sealed class DataContainerCodecContext bindingPathArgumentChild(final PathArgument arg, - final List builder) { - final var child = getStreamChild(arg.getType()); - child.addYangPathArgument(arg, builder); - return child; - } + public abstract CommonDataObjectCodecContext bindingPathArgumentChild(PathArgument arg, + List builder); /** * Serializes supplied Binding Path Argument and adds all necessary YANG instance identifiers to supplied list. @@ -144,19 +152,19 @@ abstract sealed class DataContainerCodecContext CommonDataObjectCodecContext getStreamChild(final Class childClass) { + public final DataContainerCodecContext getStreamChild(final Class childClass) { return childNonNull(streamChild(childClass), childClass, "Child %s is not valid child of %s", getBindingClass(), childClass); } @SuppressWarnings("unchecked") @Override - public final CommonDataObjectCodecContext streamChild(final Class childClass) { + public final DataContainerCodecContext streamChild(final Class childClass) { final var childProto = streamChildPrototype(requireNonNull(childClass)); - return childProto == null ? null : (CommonDataObjectCodecContext) childProto.getCodecContext(); + return childProto == null ? null : (DataContainerCodecContext) childProto.getCodecContext(); } - abstract @Nullable CommonDataObjectCodecPrototype streamChildPrototype(@NonNull Class childClass); + abstract @Nullable DataContainerPrototype streamChildPrototype(@NonNull Class childClass); @Override public String toString() { diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerPrototype.java index 9fbc08ec44..e8393140a9 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerPrototype.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerPrototype.java @@ -12,6 +12,7 @@ import static java.util.Objects.requireNonNull; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType; import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; /** * A prototype for codecs dealing with {@link DataContainer}s. @@ -19,8 +20,9 @@ import org.opendaylight.yangtools.yang.binding.DataContainer; * @param {@link CodecContext} type * @param {@link CompositeRuntimeType} type */ -abstract sealed class DataContainerPrototype - extends LazyCodecContextSupplier permits CommonDataObjectCodecPrototype { +abstract sealed class DataContainerPrototype, + R extends CompositeRuntimeType> + extends LazyCodecContextSupplier permits ChoiceCodecPrototype, CommonDataObjectCodecPrototype { private final @NonNull CodecContextFactory contextFactory; private final @NonNull R runtimeType; @@ -53,4 +55,6 @@ abstract sealed class DataContainerPrototype javaClass(); + + abstract @NonNull NodeIdentifier yangArg(); } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java index 5ba4e8fd96..8a45102c3b 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java @@ -150,13 +150,13 @@ public abstract sealed class DataObjectCodecContext pathChildPrototype(final Class argType) { + final DataContainerPrototype pathChildPrototype(final Class argType) { final var child = super.pathChildPrototype(argType); return child != null ? child : augmentToPrototype.get(argType); } @Override - final CommonDataObjectCodecPrototype streamChildPrototype(final Class childClass) { + final DataContainerPrototype streamChildPrototype(final Class childClass) { final var child = super.streamChildPrototype(childClass); if (child == null && Augmentation.class.isAssignableFrom(childClass)) { return getAugmentationProtoByClass(childClass); diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecPrototype.java index a414c2972c..e53354f09d 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecPrototype.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecPrototype.java @@ -16,7 +16,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; abstract sealed class DataObjectCodecPrototype extends CommonDataObjectCodecPrototype - permits CaseCodecPrototype, ChoiceCodecPrototype, ContainerLikeCodecPrototype, ListCodecPrototype, + permits CaseCodecPrototype, ContainerLikeCodecPrototype, ListCodecPrototype, NotificationCodecContext.Prototype { private final @NonNull NodeIdentifier yangArg; @@ -34,7 +34,7 @@ abstract sealed class DataObjectCodecPrototype e } @Override - final NodeIdentifier getYangArg() { + final NodeIdentifier yangArg() { return yangArg; } }