--- /dev/null
+/*
+ * Copyright (c) 2019 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.yangtools.yang.binding;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Utility class for {@link OpaqueData} implementations. This class provides baseline implementation of
+ * {@link #hashCode()} and {@link #equals(Object)} as specified by {@link OpaqueData}. For cases where the object
+ * model's objects do not provide a usable implementation of hashCode/equals, this class is expected to be subclassed
+ * to provide alternative implementation of {@link #dataHashCode()} and {@link #dataEquals(Object)} methods. Such
+ * class should be made public in a convenient place. Note such customized methods are required to maintain consistency
+ * between hashCode and equals, as well as the <i>reflexive</i>, <i>symmetric</i>, <i>transitive</i> and
+ * <i>consistent</i> properties as detailed in {@link Object#equals(Object)}.
+ *
+ * @param <T> Data object model type
+ */
+@Beta
+public abstract class AbstractOpaqueData<T> implements OpaqueData<T> {
+ @Override
+ public final int hashCode() {
+ return 31 * getObjectModel().hashCode() + dataHashCode();
+ }
+
+ @Override
+ public final boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof OpaqueData)) {
+ return false;
+ }
+ final OpaqueData<?> other = (OpaqueData<?>) obj;
+ return getObjectModel().equals(other.getObjectModel()) && dataEquals(other.getData());
+ }
+
+ @Override
+ public final String toString() {
+ return addToStringAttributes(MoreObjects.toStringHelper(this).add("objectModel", getObjectModel())).toString();
+ }
+
+ protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return helper.add("data", getData());
+ }
+
+ /**
+ * Determine hashCode of the data. The default implementation uses the data object's {@code hashCode} method.
+ *
+ * @return Hash code value of data
+ */
+ protected int dataHashCode() {
+ return getData().hashCode();
+ }
+
+ protected boolean dataEquals(final @NonNull Object otherData) {
+ return getData().equals(otherData);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 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.yangtools.yang.binding;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Utility base class for {@link OpaqueObject} implementations. This class provides baseline implementation of
+ * {@link #hashCode()} and {@link #equals(Object)} as specified by {@link OpaqueObject}.
+ *
+ * @param <T> Implemented OpaqueObject type
+ */
+@Beta
+public abstract class AbstractOpaqueObject<T extends OpaqueObject<T>> implements OpaqueObject<T> {
+ @Override
+ public final int hashCode() {
+ return 31 * getImplementedInterface().hashCode() + valueHashCode();
+ }
+
+ @Override
+ public final boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof OpaqueObject)) {
+ return false;
+ }
+ final OpaqueObject<?> other = (OpaqueObject<?>) obj;
+ return getImplementedInterface().equals(other.getImplementedInterface()) && valueEquals(other.getValue());
+ }
+
+ @Override
+ public final String toString() {
+ return addToStringAttributes(MoreObjects.toStringHelper(this)
+ .add("implementedInterface", getImplementedInterface())).toString();
+ }
+
+ protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return helper.add("value", getValue());
+ }
+
+ protected boolean valueEquals(final @NonNull OpaqueData<?> otherValue) {
+ return getValue().equals(otherValue);
+ }
+
+ protected int valueHashCode() {
+ return getValue().hashCode();
+ }
+}
* @return Data held in this object.
*/
@NonNull T getData();
+
+ /**
+ * The hash code of any {@link OpaqueData} instance is defined by the combination of its object model and the data
+ * it holds. This is inherently object-model-specific hence different OpaqueData defined by distinct object models
+ * will result in differing hash codes. This implies that node with differing object models cannot compare as equal.
+ * See {@link AbstractOpaqueData#hashCode()} for canonical implementation.
+ *
+ * @return a hash code value for this object.
+ */
+ @Override
+ int hashCode();
+
+ /**
+ * Compare this object to another object. The comparison needs to take into account {@link #getObjectModel()}
+ * first and then follow comparison on {@link #getData()}. For canonical algorithm please refer to
+ * {@link AbstractOpaqueData#equals(Object)}.
+ *
+ * @param obj the reference object with which to compare.
+ * @return {@code true} if this object is the same as the obj argument; {@code false} otherwise.
+ */
+ @Override
+ boolean equals(Object obj);
}
* of {@link #getImplementedInterface()} bound to itself. The value is communicated through {@link #getValue()}, which
* is only an encapsulation holding information about the object model and the data in that object model.
*
+ * <p>
+ * Implementations are strongly encouraged to use {@link AbstractOpaqueObject} as their base implementation class.
+ *
* @param <T> Generated interface
*/
@Beta
ValueAware<OpaqueData<?>> {
@Override
Class<T> getImplementedInterface();
+
+ /**
+ * Hash code value of this object. This is a combination of {@link #getImplementedInterface()} and the value being
+ * held. The canonical computation algorithm is defined in {@link AbstractOpaqueObject#hashCode()}.
+ *
+ * @return a hash code value for this object.
+ */
+ @Override
+ int hashCode();
+
+ /**
+ * Compare this object to another object. The comparison needs to take into account
+ * {@link #getImplementedInterface()} first and then follow comparison on {@link #getValue()}. For canonical
+ * algorithm please refer to {@link AbstractOpaqueObject#equals(Object)}.
+ *
+ * @param obj the reference object with which to compare.
+ * @return {@code true} if this object is the same as the obj argument; {@code false} otherwise.
+ */
+ @Override
+ boolean equals(Object obj);
}