Binding v2 DOM Codec - generator - SPI - part 2 49/58349/12
authorJakub Toth <jakub.toth@pantheon.tech>
Tue, 6 Jun 2017 13:20:02 +0000 (15:20 +0200)
committerRobert Varga <nite@hq.sk>
Fri, 9 Jun 2017 14:42:50 +0000 (14:42 +0000)
  * prepare base SPI parts of generating serializers for writers
  * added implementation of StreamWriterGenerator

Change-Id: I9445495e5893296e1384b258856eca8236ea6698
Signed-off-by: Jakub Toth <jakub.toth@pantheon.tech>
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/impl/StreamWriterGenerator.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/generator/AbstractStreamWriterGenerator.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/source/AbstractAugmentableDataNodeContainerEmitterSource.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/source/AbstractDataNodeContainerSerializerSource.java [new file with mode: 0644]
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/source/AbstractSource.java
binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/source/AbstractTreeNodeSerializerSource.java

diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/impl/StreamWriterGenerator.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/impl/StreamWriterGenerator.java
new file mode 100644 (file)
index 0000000..78ab7da
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies 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.javav2.dom.codec.generator.impl;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.api.TreeNodeSerializerGenerator;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.generator.AbstractStreamWriterGenerator;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.source.AbstractAugmentableDataNodeContainerEmitterSource;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.source.AbstractDataNodeContainerSerializerSource;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.source.AbstractTreeNodeSerializerSource;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer.AugmentableDispatchSerializer;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer.ChoiceDispatchSerializer;
+import org.opendaylight.mdsal.binding.javav2.generator.impl.util.javassist.JavassistUtils;
+import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerImplementation;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+
+/**
+ * Concrete implementation of {@link AbstractStreamWriterGenerator} which in
+ * runtime generates classes implementing
+ * {@link TreeNodeSerializerImplementation} interface and are used to serialize
+ * Binding {@link TreeNode}.
+ *
+ * Actual implementation of codecs is done via static methods, which allows for
+ * static wiring of codecs. Choice codec and Augmentable codecs are static
+ * properties of parent codec and stateless implementations are used (
+ * {@link ChoiceDispatchSerializer}, {@link AugmentableDispatchSerializer},
+ * which uses registry to dispatch to concrete item codec.
+ *
+ */
+@Beta
+public class StreamWriterGenerator extends AbstractStreamWriterGenerator {
+
+    private static final String UNKNOWN_SIZE = BindingStreamEventWriter.class.getName() + ".UNKNOWN_SIZE";
+
+    private StreamWriterGenerator(final JavassistUtils utils, final Void ignore) {
+        super(utils);
+    }
+
+    /**
+     * Create a new instance backed by a specific {@link JavassistUtils}
+     * instance.
+     *
+     * @param utils
+     *            JavassistUtils instance to use
+     * @return A new generator
+     */
+    public static TreeNodeSerializerGenerator create(final JavassistUtils utils) {
+        return new StreamWriterGenerator(utils, null);
+    }
+
+    @Override
+    protected AbstractTreeNodeSerializerSource generateContainerSerializer(final GeneratedType type,
+            final ContainerSchemaNode node) {
+
+        return new AbstractAugmentableDataNodeContainerEmitterSource(this, type, node) {
+            @Override
+            public CharSequence emitStartEvent() {
+                return startContainerNode(classReference(type), UNKNOWN_SIZE);
+            }
+        };
+    }
+
+    @Override
+    protected AbstractTreeNodeSerializerSource generateNotificationSerializer(final GeneratedType type,
+            final NotificationDefinition node) {
+
+        return new AbstractAugmentableDataNodeContainerEmitterSource(this, type, node) {
+            @Override
+            public CharSequence emitStartEvent() {
+                return startContainerNode(classReference(type), UNKNOWN_SIZE);
+            }
+        };
+    }
+
+    @Override
+    protected AbstractTreeNodeSerializerSource generateCaseSerializer(final GeneratedType type,
+            final ChoiceCaseNode node) {
+        return new AbstractAugmentableDataNodeContainerEmitterSource(this, type, node) {
+            @Override
+            public CharSequence emitStartEvent() {
+                return startCaseNode(classReference(type), UNKNOWN_SIZE);
+            }
+        };
+    }
+
+    @Override
+    protected AbstractTreeNodeSerializerSource generateUnkeyedListEntrySerializer(final GeneratedType type,
+            final ListSchemaNode node) {
+        return new AbstractAugmentableDataNodeContainerEmitterSource(this, type, node) {
+
+            @Override
+            public CharSequence emitStartEvent() {
+                return startUnkeyedListItem(UNKNOWN_SIZE);
+            }
+        };
+    }
+
+    @Override
+    protected AbstractTreeNodeSerializerSource generateSerializer(final GeneratedType type,
+            final AugmentationSchema schema) {
+        return new AbstractDataNodeContainerSerializerSource(this, type, schema) {
+
+            @Override
+            public CharSequence emitStartEvent() {
+                return startAugmentationNode(classReference(type));
+            }
+        };
+    }
+
+    @Override
+    protected AbstractTreeNodeSerializerSource generateMapEntrySerializer(final GeneratedType type,
+            final ListSchemaNode node) {
+        return new AbstractAugmentableDataNodeContainerEmitterSource(this, type, node) {
+            @Override
+            public CharSequence emitStartEvent() {
+                return startMapEntryNode(invoke(INPUT, "getKey"), UNKNOWN_SIZE);
+            }
+        };
+    }
+}
index 4924d3f161978a9ddb14adb956e53bc5371c62f1..8831609f21ee908547b7cbc26ef7604a6b8f0cf8 100644 (file)
@@ -53,7 +53,7 @@ public abstract class AbstractStreamWriterGenerator extends AbstractGenerator im
     private static final Logger LOG = LoggerFactory.getLogger(AbstractStreamWriterGenerator.class);
 
     public static final String SERIALIZE_METHOD_NAME = "serialize";
-    protected static final AugmentableDispatchSerializer AUGMENTABLE = new AugmentableDispatchSerializer();
+    public static final AugmentableDispatchSerializer AUGMENTABLE = new AugmentableDispatchSerializer();
     private static final Field FIELD_MODIFIERS;
 
     private final LoadingCache<Class<?>, TreeNodeSerializerImplementation> implementations;
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/source/AbstractAugmentableDataNodeContainerEmitterSource.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/source/AbstractAugmentableDataNodeContainerEmitterSource.java
new file mode 100644 (file)
index 0000000..5ddd7ee
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies 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.javav2.dom.codec.generator.spi.source;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.impl.StreamWriterGenerator;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.generator.AbstractStreamWriterGenerator;
+import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerImplementation;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+
+@Beta
+public abstract class AbstractAugmentableDataNodeContainerEmitterSource
+        extends AbstractDataNodeContainerSerializerSource {
+
+    private static final String AUGMENTABLE_SERIALIZER = "AUGMENTABLE_SERIALIZER";
+
+    public AbstractAugmentableDataNodeContainerEmitterSource(final AbstractStreamWriterGenerator generator,
+            final GeneratedType type, final DataNodeContainer node) {
+        super(generator, type, node);
+        /*
+         * Eventhough intuition says the serializer could reference the
+         * generator directly, that is not true in OSGi environment -- so we
+         * need to resolve the reference first and inject it as a static
+         * constant.
+         */
+        staticConstant(AUGMENTABLE_SERIALIZER, TreeNodeSerializerImplementation.class,
+                StreamWriterGenerator.AUGMENTABLE);
+    }
+
+    @Override
+    protected void emitAfterBody(final StringBuilder b) {
+        b.append(statement(invoke(AUGMENTABLE_SERIALIZER, "serialize", REGISTRY, INPUT, STREAM)));
+    }
+}
diff --git a/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/source/AbstractDataNodeContainerSerializerSource.java b/binding2/mdsal-binding2-dom-codec/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/codec/generator/spi/source/AbstractDataNodeContainerSerializerSource.java
new file mode 100644 (file)
index 0000000..a66cfa5
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies 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.javav2.dom.codec.generator.spi.source;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.impl.StreamWriterGenerator;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.generator.spi.generator.AbstractGenerator;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer.ChoiceDispatchSerializer;
+import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
+import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
+import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.javav2.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding.javav2.model.api.ParameterizedType;
+import org.opendaylight.mdsal.binding.javav2.model.api.Type;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingSerializer;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerImplementation;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializerRegistry;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+public abstract class AbstractDataNodeContainerSerializerSource extends AbstractTreeNodeSerializerSource {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractDataNodeContainerSerializerSource.class);
+
+    protected static final String INPUT = "_input";
+    private static final String CHOICE_PREFIX = "CHOICE_";
+
+    private final DataNodeContainer schemaNode;
+    private final GeneratedType dtoType;
+
+    public AbstractDataNodeContainerSerializerSource(final AbstractGenerator generator, final GeneratedType type,
+            final DataNodeContainer node) {
+        super(generator);
+        this.dtoType = Preconditions.checkNotNull(type);
+        this.schemaNode = Preconditions.checkNotNull(node);
+    }
+
+    /**
+     * Return the character sequence which should be used for start event.
+     *
+     * @return Start event character sequence
+     */
+    protected abstract CharSequence emitStartEvent();
+
+    @Override
+    public CharSequence getSerializerBody() {
+        final StringBuilder b = new StringBuilder();
+        b.append("{\n");
+        b.append(statement(assign(TreeNodeSerializerRegistry.class.getName(), REGISTRY, "$1")));
+        b.append(statement(assign(dtoType.getFullyQualifiedName(), INPUT,
+                cast(dtoType.getFullyQualifiedName(), "$2"))));
+        b.append(statement(assign(BindingStreamEventWriter.class.getName(), STREAM, cast(BindingStreamEventWriter.class.getName(), "$3"))));
+        b.append(statement(assign(BindingSerializer.class.getName(), SERIALIZER, null)));
+        b.append("if (");
+        b.append(STREAM);
+        b.append(" instanceof ");
+        b.append(BindingSerializer.class.getName());
+        b.append(") {");
+        b.append(statement(assign(SERIALIZER, cast(BindingSerializer.class.getName(), STREAM))));
+        b.append('}');
+        b.append(statement(emitStartEvent()));
+
+        emitBody(b);
+        emitAfterBody(b);
+        b.append(statement(endNode()));
+        b.append(statement("return null"));
+        b.append('}');
+        return b;
+    }
+
+    /**
+     * Allows for customization of emitting code, which is processed after
+     * normal DataNodeContainer body. Ideal for augmentations or others.
+     */
+    protected void emitAfterBody(final StringBuilder b) {
+    }
+
+    private static Map<String, Type> collectAllProperties(final GeneratedType type, final Map<String, Type> hashMap) {
+        for (final MethodSignature definition : type.getMethodDefinitions()) {
+            hashMap.put(definition.getName(), definition.getReturnType());
+        }
+        for (final Type parent : type.getImplements()) {
+            if (parent instanceof GeneratedType) {
+                collectAllProperties((GeneratedType) parent, hashMap);
+            }
+        }
+        return hashMap;
+    }
+
+    private static String getGetterName(final DataSchemaNode node) {
+        final TypeDefinition<?> type;
+        if (node instanceof TypedSchemaNode) {
+            type = ((TypedSchemaNode) node).getType();
+        } else {
+            type = null;
+        }
+
+        final String prefix;
+        if (type instanceof BooleanTypeDefinition || type instanceof EmptyTypeDefinition) {
+            prefix = "is";
+        } else {
+            prefix = "get";
+        }
+        return prefix + JavaIdentifierNormalizer.normalizeSpecificIdentifier(node.getQName().getLocalName(), JavaIdentifier.CLASS);
+    }
+
+    private void emitBody(final StringBuilder b) {
+        final Map<String, Type> getterToType = collectAllProperties(dtoType, new HashMap<String, Type>());
+        for (final DataSchemaNode schemaChild : schemaNode.getChildNodes()) {
+            if (!schemaChild.isAugmenting()) {
+                final String getter = getGetterName(schemaChild);
+                final Type childType = getterToType.get(getter);
+                if (childType == null) {
+                    // FIXME AnyXml nodes are ignored, since their type cannot be found in generated bindnig
+                    // Bug-706 https://bugs.opendaylight.org/show_bug.cgi?id=706
+                    if (schemaChild instanceof AnyXmlSchemaNode) {
+                        LOG.warn("Node {} will be ignored. AnyXml is not yet supported from binding aware code." +
+                                "Binding Independent code can be used to serialize anyXml nodes.", schemaChild.getPath());
+                        continue;
+                    }
+
+                    throw new IllegalStateException(
+                        String.format("Unable to find type for child node %s. Expected child nodes: %s",
+                            schemaChild.getPath(), getterToType));
+                }
+                emitChild(b, getter, childType, schemaChild);
+            }
+        }
+    }
+
+    private void emitChild(final StringBuilder b, final String getterName, final Type childType,
+            final DataSchemaNode schemaChild) {
+        b.append(statement(assign(childType, getterName, cast(childType, invoke(INPUT, getterName)))));
+
+        b.append("if (").append(getterName).append(" != null) {\n");
+        emitChildInner(b, getterName, childType, schemaChild);
+        b.append("}\n");
+    }
+
+    private void emitChildInner(final StringBuilder b, final String getterName, final Type childType,
+            final DataSchemaNode child) {
+        if (child instanceof LeafSchemaNode) {
+            b.append(statement(leafNode(child.getQName().getLocalName(), getterName)));
+        } else if (child instanceof AnyXmlSchemaNode) {
+            b.append(statement(anyxmlNode(child.getQName().getLocalName(), getterName)));
+        } else if (child instanceof LeafListSchemaNode) {
+            final CharSequence startEvent;
+            if (((LeafListSchemaNode) child).isUserOrdered()) {
+                startEvent = startOrderedLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"));
+            } else {
+                startEvent = startLeafSet(child.getQName().getLocalName(),invoke(getterName, "size"));
+            }
+            b.append(statement(startEvent));
+            final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+            b.append(forEach(getterName, valueType, statement(leafSetEntryNode(CURRENT))));
+            b.append(statement(endNode()));
+        } else if (child instanceof ListSchemaNode) {
+            final Type valueType = ((ParameterizedType) childType).getActualTypeArguments()[0];
+            final ListSchemaNode casted = (ListSchemaNode) child;
+            emitList(b, getterName, valueType, casted);
+        } else if (child instanceof ContainerSchemaNode) {
+            b.append(tryToUseCacheElse(getterName,statement(staticInvokeEmitter(childType, getterName))));
+        } else if (child instanceof ChoiceSchemaNode) {
+            final String propertyName = CHOICE_PREFIX + childType.getName();
+            staticConstant(propertyName, TreeNodeSerializerImplementation.class, ChoiceDispatchSerializer.from(loadClass(childType)));
+            b.append(tryToUseCacheElse(getterName,statement(invoke(propertyName, StreamWriterGenerator.SERIALIZE_METHOD_NAME, REGISTRY, cast(TreeNode.class.getName(),getterName), STREAM))));
+        }
+    }
+
+    private static StringBuilder tryToUseCacheElse(final String getterName, final CharSequence statement) {
+        final StringBuilder b = new StringBuilder();
+
+        b.append("if ( ");
+        b.append(SERIALIZER).append("== null || ");
+        b.append(invoke(SERIALIZER, "serialize", getterName)).append("== null");
+        b.append(") {");
+        b.append(statement);
+        b.append('}');
+        return b;
+    }
+
+    private void emitList(final StringBuilder b, final String getterName, final Type valueType,
+            final ListSchemaNode child) {
+        final CharSequence startEvent;
+
+        b.append(statement(assign("int", "_count", invoke(getterName, "size"))));
+        if (child.getKeyDefinition().isEmpty()) {
+            startEvent = startUnkeyedList(classReference(valueType), "_count");
+        } else if (child.isUserOrdered()) {
+            startEvent = startOrderedMapNode(classReference(valueType), "_count");
+        } else {
+            startEvent = startMapNode(classReference(valueType), "_count");
+        }
+        b.append(statement(startEvent));
+        b.append(forEach(getterName, valueType, tryToUseCacheElse(CURRENT,statement(staticInvokeEmitter(valueType, CURRENT)))));
+        b.append(statement(endNode()));
+    }
+}
index 0d44cc4280ddef3f8fcd8499416c9e31bc5cdc4a..97c6efbff363053b2609b528c6d012581e69b65e 100644 (file)
@@ -94,7 +94,7 @@ abstract class AbstractSource {
      *            - arguments of method
      * @return invoking method on object with more arguments as String
      */
-    static final CharSequence invoke(final CharSequence object, final String methodName,
+    protected static final CharSequence invoke(final CharSequence object, final String methodName,
             final Object... args) {
         final StringBuilder sb = prepareCommonInvokePart(object, methodName);
 
index d6307d03b6034e90cabde88dabcde896c5b6b817..16675cf68548d9be31ff92e8fc57a946c7c059e6 100644 (file)
@@ -138,7 +138,7 @@ public abstract class AbstractTreeNodeSerializerSource extends AbstractSource {
      *            - argument for invoking startContainerNode
      * @return invoking startContainerNode method as String
      */
-    static final CharSequence startContainerNode(final CharSequence type, final CharSequence expected) {
+    public static final CharSequence startContainerNode(final CharSequence type, final CharSequence expected) {
         return invoke(STREAM, "startContainerNode", type, expected);
     }
 
@@ -163,7 +163,7 @@ public abstract class AbstractTreeNodeSerializerSource extends AbstractSource {
      *            - argument for invoking startUnkeyedListItem
      * @return invoking startUnkeyedListItem method as String
      */
-    static final CharSequence startUnkeyedListItem(final CharSequence expected) {
+    protected static final CharSequence startUnkeyedListItem(final CharSequence expected) {
         return invoke(STREAM, "startUnkeyedListItem", expected);
     }
 
@@ -204,7 +204,7 @@ public abstract class AbstractTreeNodeSerializerSource extends AbstractSource {
      *            - argument for invoking startMapEntryNode
      * @return invoking startMapEntryNode method as String
      */
-    static final CharSequence startMapEntryNode(final CharSequence key, final CharSequence expected) {
+    protected static final CharSequence startMapEntryNode(final CharSequence key, final CharSequence expected) {
         return invoke(STREAM, "startMapEntryNode", key, expected);
     }
 
@@ -215,7 +215,7 @@ public abstract class AbstractTreeNodeSerializerSource extends AbstractSource {
      *            - argument for invoking startAugmentationNode
      * @return invoking startAugmentationNode method as String
      */
-    static final CharSequence startAugmentationNode(final CharSequence key) {
+    protected static final CharSequence startAugmentationNode(final CharSequence key) {
         return invoke(STREAM, "startAugmentationNode", key);
     }
 
@@ -243,7 +243,7 @@ public abstract class AbstractTreeNodeSerializerSource extends AbstractSource {
      *            - argument for invoking startCaseNode
      * @return invoking startCaseNode method as String
      */
-    static final CharSequence startCaseNode(final CharSequence localName, final CharSequence expected) {
+    protected static final CharSequence startCaseNode(final CharSequence localName, final CharSequence expected) {
         return invoke(STREAM, "startCase", localName, expected);
     }
 
@@ -308,7 +308,7 @@ public abstract class AbstractTreeNodeSerializerSource extends AbstractSource {
      *            - type for referencing class
      * @return referenced class of type
      */
-    static final CharSequence classReference(final Type type) {
+    protected static final CharSequence classReference(final Type type) {
         return type.getFullyQualifiedName() + ".class";
     }