Split up DataObjectCodecPrototype 28/106728/8
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 27 Jun 2023 19:20:37 +0000 (21:20 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 27 Jun 2023 22:25:19 +0000 (00:25 +0200)
Having a type-based dispatch during createInstance() is not exactly
nice. This patch splits up DataObjectCodecPrototype.createInstance()
into individual prototypes, so that we have a prototype for pretty-much
each CodecContext type.

This also improves type safety, as CodecContexts now can be directly
instantiated (and create a prototype internally).

Change-Id: If740949bc15890f0ce4bfa5b59cda030b33e66a1
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
23 files changed:
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingToNormalizedStreamWriter.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CaseCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecPrototype.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CodecDataObject.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CodecDataObjectAnalysis.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ContainerLikeCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ContainerLikeCodecPrototype.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/InstanceIdentifierCodec.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LazyBindingList.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LazyBindingMap.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ListCodecContext.java [moved from binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ListNodeCodecContext.java with 84% similarity]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ListCodecPrototype.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/MapCodecContext.java [moved from binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/KeyedListNodeCodecContext.java with 68% similarity]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/MapCodecPrototype.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/NotificationCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/RootCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/StructuralContainerCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/StructuralContainerCodecPrototype.java [new file with mode: 0644]

index b1c52f73067b5ccf02d2461cb40eea1ab0094120..9e29114da4c3a728d7e3aca5ec87f827a39c6d6d 100644 (file)
@@ -253,7 +253,7 @@ public final class BindingCodecContext extends AbstractBindingNormalizedNodeSeri
     @Nullable BindingDataObjectCodecTreeNode<?> getCodecContextNode(final @NonNull YangInstanceIdentifier dom,
             final @Nullable Collection<InstanceIdentifier.PathArgument> bindingArguments) {
         CodecContext currentNode = root;
-        ListNodeCodecContext<?> currentList = null;
+        ListCodecContext<?> currentList = null;
 
         for (var domArg : dom.getPathArguments()) {
             checkArgument(currentNode instanceof DataContainerCodecContext,
@@ -292,7 +292,7 @@ public final class BindingCodecContext extends AbstractBindingNormalizedNodeSeri
                 }
                 currentList = null;
                 currentNode = nextNode;
-            } else if (nextNode instanceof ListNodeCodecContext<?> listNode) {
+            } else if (nextNode instanceof ListCodecContext<?> listNode) {
                 // We enter list, we do not update current Node yet,
                 // since we need to verify
                 currentList = listNode;
index 61885141bf607c7ad2ceba51ac22207d89b9aaa1..d2a88f7626bef56fc05aaaa54d66dff73122014b 100644 (file)
@@ -188,7 +188,7 @@ final class BindingToNormalizedStreamWriter implements AnydataBindingStreamWrite
     @Override
     public void startMapEntryNode(final Key<?> key, final int childSizeHint) throws IOException {
         duplicateSchemaEnter();
-        NodeIdentifierWithPredicates identifier = ((KeyedListNodeCodecContext<?, ?>) current()).serialize(key);
+        NodeIdentifierWithPredicates identifier = ((MapCodecContext<?, ?>) current()).serialize(key);
         delegate.startMapEntryNode(identifier, childSizeHint);
     }
 
index da204eb6cbc8c6cb94c94b5e7587790537ea4870..351c0d2f854114e9d06f9e25a31b46f3dc35b217 100644 (file)
@@ -16,7 +16,7 @@ final class CaseCodecPrototype extends DataObjectCodecPrototype<CaseRuntimeType>
     }
 
     @Override
-    DataContainerCodecContext<?, CaseRuntimeType> createInstance() {
+    CaseNodeCodecContext<?> createInstance() {
         return new CaseNodeCodecContext<>(this);
     }
 }
\ No newline at end of file
index f111721f99126d594a4fd4b23483f492f64c306d..b2f443d8d346a4f49d8ed7d0c0eb8f23fc750096 100644 (file)
@@ -35,6 +35,7 @@ import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.yangtools.yang.binding.BindingObject;
 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;
@@ -98,15 +99,19 @@ final class ChoiceCodecContext<D extends DataObject> extends DataContainerCodecC
         implements BindingDataObjectCodecTreeNode<D> {
     private static final Logger LOG = LoggerFactory.getLogger(ChoiceCodecContext.class);
 
-    private final ImmutableMap<NodeIdentifier, DataContainerCodecPrototype<?>> byYangCaseChild;
     private final ImmutableListMultimap<Class<?>, DataContainerCodecPrototype<?>> ambiguousByCaseChildClass;
     private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClass;
+    private final ImmutableMap<NodeIdentifier, CaseCodecPrototype> byYangCaseChild;
     private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byClass;
     private final Set<Class<?>> ambiguousByCaseChildWarnings;
 
-    ChoiceCodecContext(final DataContainerCodecPrototype<ChoiceRuntimeType> prototype) {
+    ChoiceCodecContext(final Class<D> cls, final ChoiceRuntimeType type, final CodecContextFactory factory) {
+        this(new ChoiceCodecPrototype(Item.of(cls), type, factory));
+    }
+
+    ChoiceCodecContext(final ChoiceCodecPrototype prototype) {
         super(prototype);
-        final var byYangCaseChildBuilder = new HashMap<NodeIdentifier, DataContainerCodecPrototype<?>>();
+        final var byYangCaseChildBuilder = new HashMap<NodeIdentifier, CaseCodecPrototype>();
         final var byClassBuilder = new HashMap<Class<?>, DataContainerCodecPrototype<?>>();
         final var childToCase = SetMultimapBuilder.hashKeys().hashSetValues()
             .<Class<?>, DataContainerCodecPrototype<?>>build();
@@ -245,7 +250,7 @@ final class ChoiceCodecContext<D extends DataObject> extends DataContainerCodecC
             return null;
         }
         final var caze = byYangCaseChild.get(first.name());
-        return (D) caze.getDataObject().deserialize(data);
+        return ((CaseNodeCodecContext<D>) caze.get()).deserialize(data);
     }
 
     @Override
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
new file mode 100644 (file)
index 0000000..7fc1f3c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023 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.impl;
+
+import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+
+/**
+ * A prototype for {@link ChoiceCodecContext}.
+ */
+final class ChoiceCodecPrototype extends DataObjectCodecPrototype<ChoiceRuntimeType> {
+    ChoiceCodecPrototype(final Item<?> item, final ChoiceRuntimeType type, final CodecContextFactory factory) {
+        super(item, NodeIdentifier.create(type.statement().argument()), type, factory);
+    }
+
+    @Override
+    ChoiceCodecContext<?> createInstance() {
+        return new ChoiceCodecContext<>(this);
+    }
+}
index 2377d7f2e639d941154b41de901aaeb5dd52c013..18b195540c624964cb4403eff27c6a9a7f15e0d3 100644 (file)
@@ -129,7 +129,7 @@ public abstract class CodecDataObject<T extends DataObject> implements DataObjec
         if (!(data instanceof MapEntryNode mapEntry)) {
             throw new VerifyException("Unsupported value " + data);
         }
-        if (!(context instanceof KeyedListNodeCodecContext<?, ?> listContext)) {
+        if (!(context instanceof MapCodecContext<?, ?> listContext)) {
             throw new VerifyException("Unexpected context " + context);
         }
 
index af08f5d4a4b109a86378fa3d193985c42d520699..fb20719dc8453c1f132c6d0fe5a0011f6157bc9f 100644 (file)
@@ -26,6 +26,9 @@ import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
+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.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -33,6 +36,7 @@ import org.opendaylight.yangtools.yang.binding.OpaqueObject;
 import org.opendaylight.yangtools.yang.binding.contract.Naming;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.model.api.stmt.PresenceEffectiveStatement;
 
 /**
  * Analysis of a {@link DataObject} specialization class. The primary point of this class is to separate out creation
@@ -163,9 +167,21 @@ final class CodecDataObjectAnalysis<R extends CompositeRuntimeType> {
             throw DataContainerCodecContext.childNullException(factory.getRuntimeContext(), childClass,
                 "Node %s does not have child named %s", type, childClass);
         }
-
-        return DataContainerCodecPrototype.from(itemFactory.createItem(childClass, child.statement()),
-            (CompositeRuntimeType) child, factory);
+        final var item = itemFactory.createItem(childClass, child.statement());
+        if (child instanceof ContainerLikeRuntimeType containerLike) {
+            if (child instanceof ContainerRuntimeType container
+                && container.statement().findFirstEffectiveSubstatement(PresenceEffectiveStatement.class).isEmpty()) {
+                return new StructuralContainerCodecPrototype(item, container, factory);
+            }
+            return new ContainerLikeCodecPrototype(item, containerLike, factory);
+        } 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);
+        }
     }
 
 
index cef279a5c5043ab9251179929371479321dbed40..b906ff3f2569dd35575f42b41d94127dc6451ac1 100644 (file)
@@ -9,13 +9,19 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 sealed class ContainerLikeCodecContext<D extends DataObject>
         extends DataObjectCodecContext<D, ContainerLikeRuntimeType<?, ?>> implements RpcInputCodec<D>
         permits StructuralContainerCodecContext {
-    ContainerLikeCodecContext(final DataContainerCodecPrototype<ContainerLikeRuntimeType<?, ?>> prototype) {
+    ContainerLikeCodecContext(final Class<D> cls, final ContainerLikeRuntimeType<?, ?> type,
+            final CodecContextFactory factory) {
+        this(new ContainerLikeCodecPrototype(Item.of(cls), type, factory));
+    }
+
+    ContainerLikeCodecContext(final ContainerLikeCodecPrototype prototype) {
         super(prototype);
     }
 
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ContainerLikeCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ContainerLikeCodecPrototype.java
new file mode 100644 (file)
index 0000000..bfc9f00
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2023 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.impl;
+
+import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+
+/**
+ * A prototype for a {@link ContainerLikeCodecContext}.
+ */
+sealed class ContainerLikeCodecPrototype extends DataObjectCodecPrototype<ContainerLikeRuntimeType<?, ?>>
+        permits StructuralContainerCodecPrototype {
+    ContainerLikeCodecPrototype(final Item<?> item, final ContainerLikeRuntimeType<?, ?> type,
+            final CodecContextFactory factory) {
+        super(item, NodeIdentifier.create(type.statement().argument()), type, factory);
+    }
+
+    @Override
+    ContainerLikeCodecContext<?> createInstance() {
+        return new ContainerLikeCodecContext<>(this);
+    }
+}
index 2a05e7df36f0b4b59a2ab91839ca568420250bd8..984d3ebee26318d3e3be8ccdbb3ac815a1842c1f 100644 (file)
@@ -7,18 +7,15 @@
  */
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
-import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.dom.codec.api.CommonDataObjectCodecTreeNode.ChildAddressabilitySummary;
-import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeTypeContainer;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode;
@@ -149,22 +146,6 @@ abstract sealed class DataContainerCodecPrototype<T extends RuntimeTypeContainer
         return haveUnaddressable ? ChildAddressabilitySummary.MIXED : ChildAddressabilitySummary.ADDRESSABLE;
     }
 
-    static <T extends CompositeRuntimeType> DataContainerCodecPrototype<T> from(final Class<?> cls, final T type,
-            final CodecContextFactory factory) {
-        return new DataObjectCodecPrototype<>(cls, createIdentifier(type), type, factory);
-    }
-
-    static <T extends CompositeRuntimeType> DataContainerCodecPrototype<T> from(final Item<?> bindingArg, final T type,
-            final CodecContextFactory factory) {
-        return new DataObjectCodecPrototype<>(bindingArg, createIdentifier(type), type, factory);
-    }
-
-    private static @NonNull NodeIdentifier createIdentifier(final CompositeRuntimeType type) {
-        final Object arg = type.statement().argument();
-        verify(arg instanceof QName, "Unexpected type %s argument %s", type, arg);
-        return NodeIdentifier.create((QName) arg);
-    }
-
     final @NonNull T getType() {
         return type;
     }
@@ -197,13 +178,6 @@ abstract sealed class DataContainerCodecPrototype<T extends RuntimeTypeContainer
         return existing != null ? existing : loadInstance();
     }
 
-    @SuppressWarnings("unchecked")
-    final <R extends CompositeRuntimeType> DataObjectCodecContext<?, R> getDataObject() {
-        final var context = get();
-        verify(context instanceof DataObjectCodecContext, "Unexpected instance %s", context);
-        return (DataObjectCodecContext<?, R>) context;
-    }
-
     private @NonNull DataContainerCodecContext<?, T> loadInstance() {
         final var tmp = createInstance();
         final var witness = (DataContainerCodecContext<?, T>) INSTANCE.compareAndExchangeRelease(this, null, tmp);
index 4c9b0c5a8d908ef76b843547fc9df6117d6c6111..c2fa64c67cc2fc7bb19efb15b1e58c95e4dbec4c 100644 (file)
@@ -48,7 +48,7 @@ import org.slf4j.LoggerFactory;
 @Beta
 public abstract sealed class DataObjectCodecContext<D extends DataObject, T extends CompositeRuntimeType>
         extends AbstractDataObjectCodecContext<D, T> implements BindingDataObjectCodecTreeNode<D>
-        permits CaseNodeCodecContext, ContainerLikeCodecContext, ListNodeCodecContext, NotificationCodecContext {
+        permits CaseNodeCodecContext, ContainerLikeCodecContext, ListCodecContext, NotificationCodecContext {
     private static final Logger LOG = LoggerFactory.getLogger(DataObjectCodecContext.class);
 
     private static final VarHandle MISMATCHED_AUGMENTED;
index 21d8acde3e4e907712728bd8a72fb35d65a5fad0..be2fb03a182a18b21add4475ffb2d9d02be610e3 100644 (file)
@@ -10,21 +10,17 @@ 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.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeTypeContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
-import org.opendaylight.yangtools.yang.binding.KeyAware;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.model.api.stmt.PresenceEffectiveStatement;
 
-// FIXME: abstract and sealed
-non-sealed class DataObjectCodecPrototype<T extends RuntimeTypeContainer> extends DataContainerCodecPrototype<T> {
+abstract sealed class DataObjectCodecPrototype<T extends RuntimeTypeContainer> extends DataContainerCodecPrototype<T>
+        permits CaseCodecPrototype, ChoiceCodecPrototype, ContainerLikeCodecPrototype, ListCodecPrototype,
+                NotificationCodecContext.Prototype, RootCodecContext.Prototype {
     private final @NonNull NodeIdentifier yangArg;
 
+    // FIXME: this should not be needed
     @SuppressWarnings("unchecked")
     DataObjectCodecPrototype(final Class<?> cls, final NodeIdentifier yangArg, final T type,
             final CodecContextFactory factory) {
@@ -41,25 +37,4 @@ non-sealed class DataObjectCodecPrototype<T extends RuntimeTypeContainer> extend
     final NodeIdentifier getYangArg() {
         return yangArg;
     }
-
-    @Override
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    DataContainerCodecContext<?, T> createInstance() {
-        final var type = getType();
-        if (type instanceof ContainerLikeRuntimeType containerLike) {
-            if (containerLike instanceof ContainerRuntimeType container
-                && container.statement().findFirstEffectiveSubstatement(PresenceEffectiveStatement.class)
-                    .isEmpty()) {
-                return new StructuralContainerCodecContext(this);
-            }
-            return new ContainerLikeCodecContext(this);
-        } else if (type instanceof ListRuntimeType) {
-            return KeyAware.class.isAssignableFrom(getBindingClass())
-                    ? KeyedListNodeCodecContext.create((DataContainerCodecPrototype<ListRuntimeType>) this)
-                            : new ListNodeCodecContext(this);
-        } else if (type instanceof ChoiceRuntimeType) {
-            return new ChoiceCodecContext(this);
-        }
-        throw new IllegalArgumentException("Unsupported type " + getBindingClass() + " " + type);
-    }
-}
\ No newline at end of file
+}
index 09590791b34441b3fa28c386cfd2409b8b43d18d..b7f60447f3aa50f4bf007c4e96d823a01e7d0301 100644 (file)
@@ -36,7 +36,7 @@ final class InstanceIdentifierCodec implements BindingInstanceIdentifierCodec,
         if (codec == null) {
             return null;
         }
-        if (codec instanceof ListNodeCodecContext && Iterables.getLast(builder) instanceof InstanceIdentifier.Item) {
+        if (codec instanceof ListCodecContext && Iterables.getLast(builder) instanceof InstanceIdentifier.Item) {
             // We ended up in list, but without key, which means it represent list as a whole,
             // which is not binding representable.
             return null;
index adbc7ffeb6fdd047b9fb4782d69a1695b974e87d..66bc4574df7e133fc173b2b018844e449b418269 100644 (file)
@@ -63,16 +63,16 @@ final class LazyBindingList<E extends DataObject> extends AbstractList<E> implem
         }
     }
 
-    private final ListNodeCodecContext<E> codec;
+    private final ListCodecContext<E> codec;
     private final Object[] objects;
 
-    private LazyBindingList(final ListNodeCodecContext<E> codec,
+    private LazyBindingList(final ListCodecContext<E> codec,
             final Collection<? extends NormalizedNodeContainer<?>> entries) {
         this.codec = requireNonNull(codec);
         objects = entries.toArray();
     }
 
-    static <E extends DataObject> @NonNull List<E> create(final ListNodeCodecContext<E> codec, final int size,
+    static <E extends DataObject> @NonNull List<E> create(final ListCodecContext<E> codec, final int size,
             final Collection<? extends DataContainerNode> entries) {
         if (size == 1) {
             // Do not bother with lazy instantiation in case of a singleton
@@ -81,7 +81,7 @@ final class LazyBindingList<E extends DataObject> extends AbstractList<E> implem
         return size > LAZY_CUTOFF ? new LazyBindingList<>(codec, entries) : eagerList(codec, size, entries);
     }
 
-    private static <E extends DataObject> @NonNull List<E> eagerList(final ListNodeCodecContext<E> codec,
+    private static <E extends DataObject> @NonNull List<E> eagerList(final ListCodecContext<E> codec,
             final int size, final Collection<? extends DataContainerNode> entries) {
         @SuppressWarnings("unchecked")
         final E[] objs = (E[]) new DataObject[size];
index bd84cc66e329c60b8c47fa86a724fd2540ab97a2..14b6946c0af59d38550b3945d3f1d2ac65ac6b01 100644 (file)
@@ -20,7 +20,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.dom.codec.impl.KeyedListNodeCodecContext.Unordered;
+import org.opendaylight.mdsal.binding.dom.codec.impl.MapCodecContext.Unordered;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Key;
@@ -14,20 +14,24 @@ import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
 
-sealed class ListNodeCodecContext<D extends DataObject> extends DataObjectCodecContext<D, ListRuntimeType>
-        permits KeyedListNodeCodecContext {
-    ListNodeCodecContext(final DataContainerCodecPrototype<ListRuntimeType> prototype) {
+sealed class ListCodecContext<D extends DataObject> extends DataObjectCodecContext<D, ListRuntimeType>
+        permits MapCodecContext {
+    ListCodecContext(final Class<D> cls, final ListRuntimeType list, final CodecContextFactory factory) {
+        this(new ListCodecPrototype(Item.of(cls), list, factory));
+    }
+
+    ListCodecContext(final ListCodecPrototype prototype) {
         super(prototype);
     }
 
-    ListNodeCodecContext(final DataContainerCodecPrototype<ListRuntimeType> prototype,
-            final Method keyMethod) {
+    ListCodecContext(final ListCodecPrototype prototype, final Method keyMethod) {
         super(prototype, keyMethod);
     }
 
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ListCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ListCodecPrototype.java
new file mode 100644 (file)
index 0000000..f63eaa2
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023 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.impl;
+
+import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+
+/**
+ * A prototype for {@link ListCodecContext}.
+ */
+sealed class ListCodecPrototype extends DataObjectCodecPrototype<ListRuntimeType> permits MapCodecPrototype {
+    ListCodecPrototype(final Item<?> item, final ListRuntimeType type, final CodecContextFactory factory) {
+        super(item, NodeIdentifier.create(type.statement().argument()), type, factory);
+    }
+
+    @Override
+    ListCodecContext<?> createInstance() {
+        return new ListCodecContext<>(this);
+    }
+}
@@ -17,6 +17,7 @@ import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.binding.Key;
 import org.opendaylight.yangtools.yang.binding.KeyAware;
 import org.opendaylight.yangtools.yang.binding.contract.Naming;
@@ -25,19 +26,18 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 
-abstract sealed class KeyedListNodeCodecContext<I extends Key<D>, D extends DataObject & KeyAware<I>>
-        extends ListNodeCodecContext<D> {
+abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & KeyAware<I>>
+        extends ListCodecContext<D> {
     private static final class Ordered<I extends Key<D>, D extends DataObject & KeyAware<I>>
-            extends KeyedListNodeCodecContext<I, D> {
-        Ordered(final DataContainerCodecPrototype<ListRuntimeType> prototype, final Method keyMethod,
-                final IdentifiableItemCodec codec) {
+            extends MapCodecContext<I, D> {
+        Ordered(final MapCodecPrototype prototype, final Method keyMethod, final IdentifiableItemCodec codec) {
             super(prototype, keyMethod, codec);
         }
     }
 
     static final class Unordered<I extends Key<D>, D extends DataObject & KeyAware<I>>
-            extends KeyedListNodeCodecContext<I, D> {
-        Unordered(final DataContainerCodecPrototype<ListRuntimeType> prototype, final Method keyMethod,
+            extends MapCodecContext<I, D> {
+        private Unordered(final MapCodecPrototype prototype, final Method keyMethod,
                 final IdentifiableItemCodec codec) {
             super(prototype, keyMethod, codec);
         }
@@ -50,15 +50,19 @@ abstract sealed class KeyedListNodeCodecContext<I extends Key<D>, D extends Data
 
     private final IdentifiableItemCodec codec;
 
-    KeyedListNodeCodecContext(final DataContainerCodecPrototype<ListRuntimeType> prototype,
-            final Method keyMethod, final IdentifiableItemCodec codec) {
+    private MapCodecContext(final MapCodecPrototype prototype, final Method keyMethod,
+            final IdentifiableItemCodec codec) {
         super(prototype, keyMethod);
         this.codec = requireNonNull(codec);
     }
 
-    @SuppressWarnings("rawtypes")
-    static KeyedListNodeCodecContext create(final DataContainerCodecPrototype<ListRuntimeType> prototype) {
-        final Class<?> bindingClass = prototype.getBindingClass();
+    static @NonNull MapCodecContext<?, ?>  of(final Class<? extends DataObject> cls,
+            final ListRuntimeType list, final CodecContextFactory factory) {
+        return of(new MapCodecPrototype(Item.of(cls), list, factory));
+    }
+
+    static @NonNull MapCodecContext<?, ?> of(final MapCodecPrototype prototype) {
+        final var bindingClass = prototype.getBindingClass();
         final Method keyMethod;
         try {
             keyMethod = bindingClass.getMethod(Naming.KEY_AWARE_KEY_NAME);
@@ -66,8 +70,8 @@ abstract sealed class KeyedListNodeCodecContext<I extends Key<D>, D extends Data
             throw new IllegalStateException("Required method not available", e);
         }
 
-        final ListRuntimeType type = prototype.getType();
-        final IdentifiableItemCodec codec = prototype.getFactory().getPathArgumentCodec(bindingClass, type);
+        final var type = prototype.getType();
+        final var codec = prototype.getFactory().getPathArgumentCodec(bindingClass, type);
 
         return type.statement().ordering() == Ordering.SYSTEM ? new Unordered<>(prototype, keyMethod, codec)
             : new Ordered<>(prototype, keyMethod, codec);
@@ -92,28 +96,30 @@ abstract sealed class KeyedListNodeCodecContext<I extends Key<D>, D extends Data
     }
 
     @Override
-    protected InstanceIdentifier.PathArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
+    protected final InstanceIdentifier.PathArgument getBindingPathArgument(
+            final YangInstanceIdentifier.PathArgument domArg) {
         return domArg instanceof NodeIdentifierWithPredicates nip ? codec.domToBinding(nip)
             : super.getBindingPathArgument(domArg);
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    NodeIdentifierWithPredicates serialize(final Key<?> key) {
+    final NodeIdentifierWithPredicates serialize(final Key<?> key) {
         return codec.bindingToDom(IdentifiableItem.of((Class)getBindingClass(), (Key)key));
     }
 
-    @NonNull Key<?> deserialize(final @NonNull NodeIdentifierWithPredicates arg) {
+    final @NonNull Key<?> deserialize(final @NonNull NodeIdentifierWithPredicates arg) {
         return codec.deserializeIdentifier(arg);
     }
 
     @Override
-    public YangInstanceIdentifier.PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) {
+    public final YangInstanceIdentifier.PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) {
         return arg instanceof IdentifiableItem<?, ?> identifiable ? codec.bindingToDom(identifiable)
             : super.serializePathArgument(arg);
     }
 
     @Override
-    public InstanceIdentifier.PathArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) {
+    public final InstanceIdentifier.PathArgument deserializePathArgument(
+        final YangInstanceIdentifier.PathArgument arg) {
         return arg instanceof NodeIdentifierWithPredicates nip ? codec.domToBinding(nip)
             : super.deserializePathArgument(arg);
     }
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/MapCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/MapCodecPrototype.java
new file mode 100644 (file)
index 0000000..da5885f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023 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.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.KeyAware;
+
+/**
+ * A prototype for a {@link MapCodecContext}.
+ */
+final class MapCodecPrototype extends ListCodecPrototype {
+    MapCodecPrototype(final Item<?> item, final ListRuntimeType type, final CodecContextFactory factory) {
+        super(item, type, factory);
+        final var clazz = getBindingClass();
+        checkArgument(KeyAware.class.isAssignableFrom(clazz), "%s is not KeyAware", clazz);
+    }
+
+    @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    ListCodecContext createInstance() {
+        return MapCodecContext.of(this);
+    }
+}
index 9bae0af94c1d7ee0808ae55e72eaf5786686d41f..8c9ea4ac3cd0b43d065ce71543a6fb78293af6d4 100644 (file)
@@ -123,17 +123,17 @@ final class NotificationCodecContext<D extends DataObject & BaseNotification>
     }
 
     /**
-     * Prototype for a {@code notiofication}. This class only exists because DataContainerCodecContext requires a
+     * Prototype for a {@code notification}. This class only exists because DataContainerCodecContext requires a
      * prototype.
      */
-    private static final class Prototype<D extends DataObject & BaseNotification>
+    static final class Prototype<D extends DataObject & BaseNotification>
             extends DataObjectCodecPrototype<NotificationRuntimeType> {
-        Prototype(final Class<?> cls, final NotificationRuntimeType type, final CodecContextFactory factory) {
+        private Prototype(final Class<?> cls, final NotificationRuntimeType type, final CodecContextFactory factory) {
             super(cls, NodeIdentifier.create(type.statement().argument()), type, factory);
         }
 
         @Override
-        DataContainerCodecContext<?, NotificationRuntimeType> createInstance() {
+        NotificationCodecContext<?> createInstance() {
             throw new UnsupportedOperationException("Should never be invoked");
         }
     }
index fcf8a03ba092652f1a0561943052f999c778a728..d0ca5f876eab3aad719ff0f240d6dfa42053ed12 100644 (file)
@@ -33,9 +33,10 @@ import org.opendaylight.mdsal.binding.runtime.api.ActionRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeTypes;
 import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.DataRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.NotificationRuntimeType;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.yangtools.util.ClassLoaderUtils;
@@ -64,6 +65,7 @@ import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.stmt.PresenceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 
 final class RootCodecContext<D extends DataObject> extends DataContainerCodecContext<D, BindingRuntimeTypes>
@@ -72,15 +74,15 @@ final class RootCodecContext<D extends DataObject> extends DataContainerCodecCon
      * Prototype for the root of YANG modeled world. This class only exists because DataContainerCodecContext requires
      * a prototype.
      */
-    private static final class Prototype extends DataObjectCodecPrototype<BindingRuntimeTypes> {
+    static final class Prototype extends DataObjectCodecPrototype<BindingRuntimeTypes> {
         private static final @NonNull NodeIdentifier ROOT_NODEID = NodeIdentifier.create(SchemaContext.NAME);
 
-        Prototype(final CodecContextFactory factory) {
+        private Prototype(final CodecContextFactory factory) {
             super(DataRoot.class, ROOT_NODEID, factory.getRuntimeContext().getTypes(), factory);
         }
 
         @Override
-        DataContainerCodecContext<?, BindingRuntimeTypes> createInstance() {
+        RootCodecContext<?> createInstance() {
             throw new UnsupportedOperationException("Should never be invoked");
         }
     }
@@ -160,11 +162,11 @@ final class RootCodecContext<D extends DataObject> extends DataContainerCodecCon
                         final ContainerLike schema = getRpcDataSchema(potential, qname);
                         checkArgument(schema != null, "Schema for %s does not define input / output.", potentialQName);
 
-                        final ContainerLikeRuntimeType<?, ?> type = lookup.apply(context.getTypes(), potentialQName)
+                        final var type = lookup.apply(context.getTypes(), potentialQName)
                             .orElseThrow(() -> new IllegalArgumentException("Cannot find runtime type for " + key));
 
-                        return (ContainerLikeCodecContext) DataContainerCodecPrototype.from(key,
-                            (ContainerLikeRuntimeType<?, ?>) type, factory).get();
+                        // FIXME: accurate type
+                        return new ContainerLikeCodecContext(key, type, factory);
                     }
                 }
 
@@ -288,8 +290,17 @@ final class RootCodecContext<D extends DataObject> extends DataContainerCodecCon
     DataContainerCodecContext<?, ?> createDataTreeChildContext(final Class<? extends DataObject> key) {
         final var childSchema = childNonNull(type().bindingChild(JavaTypeName.create(key)), key,
             "%s is not top-level item.", key);
-        if (childSchema instanceof CompositeRuntimeType composite && childSchema instanceof DataRuntimeType) {
-            return DataContainerCodecPrototype.from(key, composite, factory()).get();
+        if (childSchema instanceof ContainerLikeRuntimeType containerLike) {
+            if (childSchema instanceof ContainerRuntimeType container
+                && container.statement().findFirstEffectiveSubstatement(PresenceEffectiveStatement.class).isEmpty()) {
+                return new StructuralContainerCodecContext<>(key, container, factory());
+            }
+            return new ContainerLikeCodecContext<>(key, containerLike, factory());
+        } else if (childSchema instanceof ListRuntimeType list) {
+            return list.keyType() == null ? new ListCodecContext<>(key, list, factory())
+                : MapCodecContext.of(key, list, factory());
+        } else if (childSchema instanceof ChoiceRuntimeType choice) {
+            return new ChoiceCodecContext<>(key, choice, factory());
         }
         throw new IncorrectNestingException("%s is not a valid data tree child of %s", key, this);
     }
@@ -313,10 +324,8 @@ final class RootCodecContext<D extends DataObject> extends DataContainerCodecCon
         checkArgument(args.length == expectedArgsLength, "Unexpected (%s) Action generatic arguments", args.length);
         final ActionRuntimeType schema = factory().getRuntimeContext().getActionDefinition(action);
         return new ActionCodecContext(
-            DataContainerCodecPrototype.from(asClass(args[inputOffset], RpcInput.class), schema.input(),
-                factory()).getDataObject(),
-            DataContainerCodecPrototype.from(asClass(args[outputOffset], RpcOutput.class), schema.output(),
-                factory()).getDataObject());
+            new ContainerLikeCodecContext(asClass(args[inputOffset], RpcInput.class), schema.input(), factory()),
+            new ContainerLikeCodecContext(asClass(args[outputOffset], RpcOutput.class), schema.output(), factory()));
     }
 
     private static <T extends DataObject> Class<? extends T> asClass(final Type type, final Class<T> target) {
@@ -353,9 +362,8 @@ final class RootCodecContext<D extends DataObject> extends DataContainerCodecCon
             throw new IllegalArgumentException(caseType + " does not refer to a choice");
         }
 
-        final var choice = DataContainerCodecPrototype.from(choiceClass, choiceType, factory()).get();
-        verify(choice instanceof ChoiceCodecContext);
-        return (ChoiceCodecContext<?>) choice;
+        // FIXME: accurate type!
+        return new ChoiceCodecContext(choiceClass, choiceType, factory());
     }
 
     @Override
index 3a7953180752a28fd70daa4c0981dddd923d4ced..def7a91d9b3ee0559209cc633462ba2a3a2cb174 100644 (file)
@@ -10,8 +10,9 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 
 /**
@@ -32,7 +33,12 @@ final class StructuralContainerCodecContext<D extends DataObject> extends Contai
     @SuppressWarnings("unused")
     private volatile D emptyObject;
 
-    StructuralContainerCodecContext(final DataContainerCodecPrototype<ContainerLikeRuntimeType<?, ?>> prototype) {
+    StructuralContainerCodecContext(final Class<D> cls, final ContainerRuntimeType type,
+            final CodecContextFactory factory) {
+        this(new StructuralContainerCodecPrototype(Item.of(cls), type, factory));
+    }
+
+    StructuralContainerCodecContext(final StructuralContainerCodecPrototype prototype) {
         super(prototype);
     }
 
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/StructuralContainerCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/StructuralContainerCodecPrototype.java
new file mode 100644 (file)
index 0000000..4fb130c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023 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.impl;
+
+import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+
+/**
+ * A prototype for a {@link StructuralContainerCodecContext}.
+ */
+final class StructuralContainerCodecPrototype extends ContainerLikeCodecPrototype {
+    StructuralContainerCodecPrototype(final Item<?> item, final ContainerRuntimeType container,
+            final CodecContextFactory factory) {
+        super(item, container, factory);
+    }
+
+    @Override
+    StructuralContainerCodecContext<?> createInstance() {
+        return new StructuralContainerCodecContext<>(this);
+    }
+}