diff --git a/api/src/main/java/jakarta/json/AbstractJsonArray.java b/api/src/main/java/jakarta/json/AbstractJsonArray.java
new file mode 100644
index 00000000..857c70c8
--- /dev/null
+++ b/api/src/main/java/jakarta/json/AbstractJsonArray.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+package jakarta.json;
+
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.Stream;
+
+/**
+ * Abstract JsonArray which delegates calls to an encapsulated
+ * JsonArray delegate.
+ *
+ * Extend this class when you want to implement your own JsonArray,
+ * based on another JsonArray, without having to reimplement
+ * all the methods yourself.
+ *
+ * Example usage: Encapsulation of utility method.
+ *
+ * //Instead of this utility method which pollutes the code and
+ * //will probably never be tested...
+ *
+ * public static JsonArray buildArray(JsonValue... values) {
+ * List<JsonValue> values = Arrays.asList(values);
+ * JsonArray array = values.stream().collect(
+ * JsonCollectors.toJsonArray()
+ * );
+ * }
+ *
+ * //There should be the following class. Logic becomes
+ * //decoupled, encapsulated and testable.
+ *
+ * public final class CollectedJsonArray extends AbstractJsonArray {
+ *
+ * public CollectedJsonArry(final JsonValue... values) {
+ * this(Arrays.asList(values));
+ * }
+ *
+ * public CollectedJsonArray(final List<JsonValue> values) {
+ * super(
+ * values.stream().collect(
+ * JsonCollectors.toJsonArray()
+ * )
+ * );
+ * }
+ * }
+ *
+ */
+public abstract class AbstractJsonArray implements JsonArray {
+
+ /**
+ * JsonArray delegate. You may also think of it as the
+ * "backbone" of your JsonArray implementation.
+ */
+ private final JsonArray delegate;
+
+ /**
+ * Constructor.
+ * @param delegate Delegate JsonArray. The "backbone" of your
+ * implementation.
+ */
+ public AbstractJsonArray(final JsonArray delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public JsonObject getJsonObject(int index) {
+ return this.delegate.getJsonObject(index);
+ }
+
+ @Override
+ public JsonArray getJsonArray(int index) {
+ return this.delegate.getJsonArray(index);
+ }
+
+ @Override
+ public JsonNumber getJsonNumber(int index) {
+ return this.delegate.getJsonNumber(index);
+ }
+
+ @Override
+ public JsonString getJsonString(int index) {
+ return this.delegate.getJsonString(index);
+ }
+
+ @Override
+ public List getValuesAs(Class clazz) {
+ return this.delegate.getValuesAs(clazz);
+ }
+
+ @Override
+ public List getValuesAs(Function func) {
+ return this.delegate.getValuesAs(func);
+ }
+
+ @Override
+ public String getString(int index) {
+ return this.delegate.getString(index);
+ }
+
+ @Override
+ public String getString(int index, String defaultValue) {
+ return this.delegate.getString(index, defaultValue);
+ }
+
+ @Override
+ public int getInt(int index) {
+ return this.delegate.getInt(index);
+ }
+
+ @Override
+ public int getInt(int index, int defaultValue) {
+ return this.delegate.getInt(index, defaultValue);
+ }
+
+ @Override
+ public boolean getBoolean(int index) {
+ return this.delegate.getBoolean(index);
+ }
+
+ @Override
+ public boolean getBoolean(int index, boolean defaultValue) {
+ return this.delegate.getBoolean(index, defaultValue);
+ }
+
+ @Override
+ public boolean isNull(int index) {
+ return this.delegate.isNull(index);
+ }
+
+ @Override
+ public JsonValue getValue(String jsonPointer) {
+ return this.delegate.getValue(jsonPointer);
+ }
+
+ @Override
+ public ValueType getValueType() {
+ return this.delegate.getValueType();
+ }
+
+ @Override
+ public JsonObject asJsonObject() {
+ return this.delegate.asJsonObject();
+ }
+
+ @Override
+ public JsonArray asJsonArray() {
+ return this.delegate.asJsonArray();
+ }
+
+ @Override
+ public String toString() {
+ return this.delegate.toString();
+ }
+
+ @Override
+ public int size() {
+ return this.delegate.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.delegate.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return this.delegate.contains(o);
+ }
+
+ @Override
+ public Iterator iterator() {
+ return this.delegate.iterator();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return this.delegate.toArray();
+ }
+
+ @Override
+ public T[] toArray(T[] a) {
+ return this.delegate.toArray(a);
+ }
+
+ @Override
+ public boolean add(JsonValue jsonValue) {
+ return this.delegate.add(jsonValue);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return this.delegate.remove(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection> c) {
+ return this.delegate.containsAll(c);
+ }
+
+ @Override
+ public boolean addAll(Collection extends JsonValue> c) {
+ return this.delegate.addAll(c);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection extends JsonValue> c) {
+ return this.delegate.addAll(index, c);
+ }
+
+ @Override
+ public boolean removeAll(Collection> c) {
+ return this.delegate.removeAll(c);
+ }
+
+ @Override
+ public boolean retainAll(Collection> c) {
+ return this.delegate.retainAll(c);
+ }
+
+ @Override
+ public void replaceAll(UnaryOperator operator) {
+ this.delegate.replaceAll(operator);
+ }
+
+ @Override
+ public void sort(Comparator super JsonValue> c) {
+ this.delegate.sort(c);
+ }
+
+ @Override
+ public void clear() {
+ this.delegate.clear();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return this.delegate.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.delegate.hashCode();
+ }
+
+ @Override
+ public JsonValue get(int index) {
+ return this.delegate.get(index);
+ }
+
+ @Override
+ public JsonValue set(int index, JsonValue element) {
+ return this.delegate.set(index, element);
+ }
+
+ @Override
+ public void add(int index, JsonValue element) {
+ this.delegate.add(index, element);
+ }
+
+ @Override
+ public JsonValue remove(int index) {
+ return this.delegate.remove(index);
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return this.delegate.indexOf(o);
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return this.delegate.lastIndexOf(o);
+ }
+
+ @Override
+ public ListIterator listIterator() {
+ return this.delegate.listIterator();
+ }
+
+ @Override
+ public ListIterator listIterator(int index) {
+ return this.delegate.listIterator(index);
+ }
+
+ @Override
+ public List subList(int fromIndex, int toIndex) {
+ return this.delegate.subList(fromIndex, toIndex);
+ }
+
+ @Override
+ public Spliterator spliterator() {
+ return this.delegate.spliterator();
+ }
+
+ @Override
+ public boolean removeIf(Predicate super JsonValue> filter) {
+ return this.delegate.removeIf(filter);
+ }
+
+ @Override
+ public Stream stream() {
+ return this.delegate.stream();
+ }
+
+ @Override
+ public Stream parallelStream() {
+ return this.delegate.parallelStream();
+ }
+
+ @Override
+ public void forEach(Consumer super JsonValue> action) {
+ this.delegate.forEach(action);
+ }
+}
diff --git a/api/src/main/java/jakarta/json/AbstractJsonObject.java b/api/src/main/java/jakarta/json/AbstractJsonObject.java
new file mode 100644
index 00000000..6fb82b03
--- /dev/null
+++ b/api/src/main/java/jakarta/json/AbstractJsonObject.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+package jakarta.json;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * Abstract JsonObject which delegates calls to an encapsulated
+ * JsonObject delegate.
+ *
+ * Extend this class when you want to implement your own JsonObject,
+ * based on another JsonObject, without having to reimplement
+ * all the methods yourself.
+ *
+ * Example usage: Polymorphism.
+ *
+ *
+ * //Container which is also a JsonObject.
+ * public interface Container extends JsonObject {
+ * //...other methods of Container.
+ * }
+ *
+ * public final class JsonContainer implements Container extends AbstractJsonObject {
+ *
+ * public ContainerImpl(final JsonObject representation) {
+ * super(representation);
+ * }
+ * }
+ *
+ */
+public abstract class AbstractJsonObject implements JsonObject {
+
+ /**
+ * JsonObject delegate. You may also think of it as the
+ * "backbone" of your JsonObject implementation.
+ */
+ private final JsonObject delegate;
+
+ /**
+ * Constructor.
+ * @param delegate Delegate JsonObject. The "backbone" of your
+ * implementation.
+ */
+ public AbstractJsonObject(final JsonObject delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public JsonArray getJsonArray(String name) {
+ return this.delegate.getJsonArray(name);
+ }
+
+ @Override
+ public JsonObject getJsonObject(String name) {
+ return this.delegate.getJsonObject(name);
+ }
+
+ @Override
+ public JsonNumber getJsonNumber(String name) {
+ return this.delegate.getJsonNumber(name);
+ }
+
+ @Override
+ public JsonString getJsonString(String name) {
+ return this.delegate.getJsonString(name);
+ }
+
+ @Override
+ public String getString(String name) {
+ return this.delegate.getString(name);
+ }
+
+ @Override
+ public String getString(String name, String defaultValue) {
+ return this.delegate.getString(name, defaultValue);
+ }
+
+ @Override
+ public int getInt(String name) {
+ return this.delegate.getInt(name);
+ }
+
+ @Override
+ public int getInt(String name, int defaultValue) {
+ return this.delegate.getInt(name, defaultValue);
+ }
+
+ @Override
+ public boolean getBoolean(String name) {
+ return this.delegate.getBoolean(name);
+ }
+
+ @Override
+ public boolean getBoolean(String name, boolean defaultValue) {
+ return this.delegate.getBoolean(name, defaultValue);
+ }
+
+ @Override
+ public boolean isNull(String name) {
+ return this.delegate.isNull(name);
+ }
+
+ @Override
+ public JsonValue getValue(String jsonPointer) {
+ return this.delegate.getValue(jsonPointer);
+ }
+
+ @Override
+ public ValueType getValueType() {
+ return this.delegate.getValueType();
+ }
+
+ @Override
+ public JsonObject asJsonObject() {
+ return this.delegate.asJsonObject();
+ }
+
+ @Override
+ public JsonArray asJsonArray() {
+ return this.delegate.asJsonArray();
+ }
+
+ @Override
+ public String toString() {
+ return this.delegate.toString();
+ }
+
+ @Override
+ public int size() {
+ return this.delegate.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.delegate.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return this.delegate.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return this.delegate.containsValue(value);
+ }
+
+ @Override
+ public JsonValue get(Object key) {
+ return this.delegate.get(key);
+ }
+
+ @Override
+ public JsonValue put(String key, JsonValue value) {
+ return this.delegate.put(key, value);
+ }
+
+ @Override
+ public JsonValue remove(Object key) {
+ return this.delegate.remove(key);
+ }
+
+ @Override
+ public void putAll(Map extends String, ? extends JsonValue> m) {
+ this.delegate.putAll(m);
+ }
+
+ @Override
+ public void clear() {
+ this.delegate.clear();
+ }
+
+ @Override
+ public Set keySet() {
+ return this.delegate.keySet();
+ }
+
+ @Override
+ public Collection values() {
+ return this.delegate.values();
+ }
+
+ @Override
+ public Set> entrySet() {
+ return this.delegate.entrySet();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return this.delegate.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.delegate.hashCode();
+ }
+
+ @Override
+ public JsonValue getOrDefault(Object key, JsonValue defaultValue) {
+ return this.delegate.getOrDefault(key, defaultValue);
+ }
+
+ @Override
+ public void forEach(BiConsumer super String, ? super JsonValue> action) {
+ this.delegate.forEach(action);
+ }
+
+ @Override
+ public void replaceAll(BiFunction super String, ? super JsonValue, ? extends JsonValue> function) {
+ this.delegate.replaceAll(function);
+ }
+
+ @Override
+ public JsonValue putIfAbsent(String key, JsonValue value) {
+ return this.delegate.putIfAbsent(key, value);
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ return this.delegate.remove(key, value);
+ }
+
+ @Override
+ public boolean replace(String key, JsonValue oldValue, JsonValue newValue) {
+ return this.delegate.replace(key, oldValue, newValue);
+ }
+
+ @Override
+ public JsonValue replace(String key, JsonValue value) {
+ return this.delegate.replace(key, value);
+ }
+
+ @Override
+ public JsonValue computeIfAbsent(String key, Function super String, ? extends JsonValue> mappingFunction) {
+ return this.delegate.computeIfAbsent(key, mappingFunction);
+ }
+
+ @Override
+ public JsonValue computeIfPresent(String key, BiFunction super String, ? super JsonValue, ? extends JsonValue> remappingFunction) {
+ return this.delegate.computeIfPresent(key, remappingFunction);
+ }
+
+ @Override
+ public JsonValue compute(String key, BiFunction super String, ? super JsonValue, ? extends JsonValue> remappingFunction) {
+ return this.delegate.compute(key, remappingFunction);
+ }
+
+ @Override
+ public JsonValue merge(String key, JsonValue value, BiFunction super JsonValue, ? super JsonValue, ? extends JsonValue> remappingFunction) {
+ return this.delegate.merge(key, value, remappingFunction);
+ }
+}