import static org.opendaylight.mdsal.binding.model.util.Types.listTypeFor;
import static org.opendaylight.mdsal.binding.model.util.Types.listenableFutureTypeFor;
import static org.opendaylight.mdsal.binding.model.util.Types.mapTypeFor;
+import static org.opendaylight.mdsal.binding.model.util.Types.primitiveBooleanType;
import static org.opendaylight.mdsal.binding.model.util.Types.primitiveIntType;
import static org.opendaylight.mdsal.binding.model.util.Types.primitiveVoidType;
import static org.opendaylight.mdsal.binding.model.util.Types.wildcardTypeFor;
.setAccessModifier(AccessModifier.PUBLIC)
.setStatic(true)
.setReturnType(primitiveIntType());
+ typeBuilder.addMethod(BindingMapping.BINDING_EQUALS_NAME)
+ .setAccessModifier(AccessModifier.PUBLIC)
+ .setStatic(true)
+ .setReturnType(primitiveBooleanType());
typeBuilder.addMethod(BindingMapping.BINDING_TO_STRING_NAME)
.setAccessModifier(AccessModifier.PUBLIC)
.setStatic(true)
assertNotNull("Generated Interface cannot contain NULL reference for Method Signature Definitions!", methods);
// FIXME: split this into getter/default/static asserts
- assertEquals(18, methods.size());
+ assertEquals(19, methods.size());
Enumeration ianaIfType = null;
for (final MethodSignature method : methods) {
if (method.getName().equals("getType")) {
assertNotNull("Generated Type Interface cannot contain NULL reference to Enumeration types!", methods);
// FIXME: split this into getter/default/static asserts
- assertEquals(8, methods.size());
+ assertEquals(9, methods.size());
for (final MethodSignature method : methods) {
if (method.getName().equals("getLinkUpDownTrapEnable")) {
linkUpDownTrapEnable = method.getReturnType();
assertNotNull(simpleContainer);
assertNotNull(nestedContainer);
// FIXME: split this into getter/default/static asserts
- assertEquals(6, simpleContainer.getMethodDefinitions().size());
+ assertEquals(7, simpleContainer.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(5, nestedContainer.getMethodDefinitions().size());
+ assertEquals(6, nestedContainer.getMethodDefinitions().size());
int getFooMethodCounter = 0;
int getBarMethodCounter = 0;
assertNotNull(simpleContainer);
assertNotNull(nestedContainer);
// FIXME: split this into getter/default/static asserts
- assertEquals(6, simpleContainer.getMethodDefinitions().size());
+ assertEquals(7, simpleContainer.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(5, nestedContainer.getMethodDefinitions().size());
+ assertEquals(6, nestedContainer.getMethodDefinitions().size());
int getFooMethodCounter = 0;
int getBarMethodCounter = 0;
}
// FIXME: split this into getter/default/static asserts
- assertEquals(5, listParentContainerMethodsCount);
+ assertEquals(6, listParentContainerMethodsCount);
// FIXME: split this into getter/default/static asserts
- assertEquals(4, listChildContainerMethodsCount);
+ assertEquals(5, listChildContainerMethodsCount);
assertEquals(1, getSimpleListKeyMethodCount);
assertEquals(1, listKeyClassCount);
assertEquals(1, getBarMethodCount);
// FIXME: split this into getter/default/static asserts
- assertEquals(9, simpleListMethodsCount);
+ assertEquals(10, simpleListMethodsCount);
}
@Test
final MethodSignature bindingHashCode = it.next();
assertEquals(BindingMapping.BINDING_HASHCODE_NAME, bindingHashCode.getName());
+ final MethodSignature bindingEquals = it.next();
+ assertEquals(BindingMapping.BINDING_EQUALS_NAME, bindingEquals.getName());
final MethodSignature bindingToString = it.next();
assertEquals(BindingMapping.BINDING_TO_STRING_NAME, bindingToString.getName());
containsInterface("GroupingCaseTest", caseC);
// FIXME: split this into getter/default/static asserts
- assertEquals(3, caseC.getMethodDefinitions().size());
+ assertEquals(4, caseC.getMethodDefinitions().size());
assertEquals("Number of method in GroupingCaseTest is incorrect", 2, groupingCaseTest.getMethodDefinitions()
.size());
assertEquals("Number of method in GroupingContainerTestis incorrect", 3, groupingContainerTest
.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(4, containerTest.getMethodDefinitions().size());
+ assertEquals(5, containerTest.getMethodDefinitions().size());
containsMethods(groupingContainerTest.getMethodDefinitions(), new NameTypePattern(
"getLeafGroupingContainerTest1", "String"), new NameTypePattern("getLeafGroupingContainerTest2",
assertEquals("Number of method in GroupingListTest is incorrect", 6, groupingListTest.getMethodDefinitions()
.size());
// FIXME: split this into getter/default/static asserts
- assertEquals(4, listTest.getMethodDefinitions().size());
+ assertEquals(5, listTest.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(4, containerGroupingListTest.getMethodDefinitions().size());
+ assertEquals(5, containerGroupingListTest.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(4, listGroupingListTest.getMethodDefinitions().size());
+ assertEquals(5, listGroupingListTest.getMethodDefinitions().size());
containsMethods(groupingListTest.getMethodDefinitions(), new NameTypePattern("getContainerGroupingListTest",
"ContainerGroupingListTest"), new NameTypePattern("getLeafGroupingListTest", "String"),
containsInterface("GroupingRpcOutputTest", rpcTestOutput);
// FIXME: split this into getter/default/static asserts
- assertEquals(3, rpcTestInput.getMethodDefinitions().size());
+ assertEquals(4, rpcTestInput.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(3, rpcTestOutput.getMethodDefinitions().size());
+ assertEquals(4, rpcTestOutput.getMethodDefinitions().size());
assertEquals("Number of method in GroupingRpcInputTest is incorrect", 3, groupingRpcInputTest
.getMethodDefinitions().size());
assertEquals("Number of method in GroupingRpcOutputTest is incorrect", 2, groupingRpcOutputTest
.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(4, containerGroupingRpcInputTest.getMethodDefinitions().size());
+ assertEquals(5, containerGroupingRpcInputTest.getMethodDefinitions().size());
containsMethods(groupingRpcInputTest.getMethodDefinitions(), new NameTypePattern(
"getContainerGroupingRpcInputTest", "ContainerGroupingRpcInputTest"), new NameTypePattern(
containsInterface("GroupingAugmentTest", containerAugment1);
// FIXME: split this into getter/default/static asserts
- assertEquals(3, containerAugment1.getMethodDefinitions().size());
+ assertEquals(4, containerAugment1.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(3, containerAugment1.getMethodDefinitions().size());
+ assertEquals(4, containerAugment1.getMethodDefinitions().size());
assertEquals("Number of method in GroupingCaseTest is incorrect", 2, groupingAugmentTest.getMethodDefinitions()
.size());
containsInterface("GroupingNotificationTest", notificationTest);
// FIXME: split this into getter/default/static asserts
- assertEquals(4, notificationTest.getMethodDefinitions().size());
+ assertEquals(5, notificationTest.getMethodDefinitions().size());
assertEquals("Number of method in GroupingNotificationTest is incorrect", 3, groupingNotificationTest
.getMethodDefinitions().size());
// FIXME: split this into getter/default/static asserts
- assertEquals(4, containerGroupingNotificationTest.getMethodDefinitions().size());
+ assertEquals(5, containerGroupingNotificationTest.getMethodDefinitions().size());
containsMethods(notificationTest.getMethodDefinitions(), new NameTypePattern("getLeafNotificationTest",
"String"));
private static final @NonNull ConcreteType LISTENABLE_FUTURE = typeForClass(ListenableFuture.class);
private static final @NonNull ConcreteType MAP_TYPE = typeForClass(Map.class);
private static final @NonNull ConcreteType OBJECT = typeForClass(Object.class);
+ private static final @NonNull ConcreteType PRIMITIVE_BOOLEAN = typeForClass(boolean.class);
private static final @NonNull ConcreteType PRIMITIVE_INT = typeForClass(int.class);
private static final @NonNull ConcreteType PRIMITIVE_VOID = typeForClass(void.class);
private static final @NonNull ConcreteType SERIALIZABLE = typeForClass(Serializable.class);
return OBJECT;
}
+ /**
+ * Returns an instance of {@link ConcreteType} which represents JAVA <code>boolean</code> type.
+ *
+ * @return <code>ConcreteType</code> instance which represents JAVA <code>boolean</code>
+ */
+ public static @NonNull ConcreteType primitiveBooleanType() {
+ return PRIMITIVE_BOOLEAN;
+ }
+
/**
* Returns an instance of {@link ConcreteType} which represents JAVA <code>int</code> type.
*
*/
package org.opendaylight.mdsal.binding.java.api.generator
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_OBJECT
import static org.opendaylight.mdsal.binding.model.util.Types.STRING;
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTATION_FIELD
-import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTABLE_AUGMENTATION_NAME
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_EQUALS_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_HASHCODE_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_TO_STRING_NAME
-import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME
import java.util.Collection
import java.util.List
«IF !properties.empty || augmentType !== null»
@«OVERRIDE.importedName»
public boolean equals(«Types.objectType().importedName» obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof «DATA_OBJECT.importedName»)) {
- return false;
- }
- if (!«targetType.importedName».class.equals(((«DATA_OBJECT.importedName»)obj).«DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME»())) {
- return false;
- }
- «targetType.importedName» other = («targetType.importedName»)obj;
- «FOR property : properties»
- «val fieldName = property.fieldName»
- if (!«property.importedUtilClass».equals(«fieldName», other.«property.getterName»())) {
- return false;
- }
- «ENDFOR»
- «IF augmentType !== null»
- if (getClass() == obj.getClass()) {
- // Simple case: we are comparing against self
- «type.name» otherImpl = («type.name») obj;
- if (!«JU_OBJECTS.importedName».equals(augmentations(), otherImpl.augmentations())) {
- return false;
- }
- } else {
- // Hard case: compare our augments with presence there...
- for («JU_MAP.importedName».Entry<«CLASS.importedName»<? extends «augmentType.importedName»>, «augmentType.importedName»> e : augmentations().entrySet()) {
- if (!e.getValue().equals(other.«AUGMENTABLE_AUGMENTATION_NAME»(e.getKey()))) {
- return false;
- }
- }
- // .. and give the other one the chance to do the same
- if (!obj.equals(this)) {
- return false;
- }
- }
- «ENDIF»
- return true;
+ return «targetType.importedName».«BINDING_EQUALS_NAME»(this, obj);
}
«ENDIF»
'''
*/
package org.opendaylight.mdsal.binding.java.api.generator
-import static org.opendaylight.mdsal.binding.model.util.Types.STRING;
import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getGetterMethodForNonnull
import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.isGetterMethodName
import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.isNonnullMethodName
+import static org.opendaylight.mdsal.binding.model.util.Types.STRING;
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTATION_FIELD
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_EQUALS_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_HASHCODE_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_TO_STRING_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME
import org.opendaylight.mdsal.binding.model.api.GeneratedType
import org.opendaylight.mdsal.binding.model.api.MethodSignature
import org.opendaylight.mdsal.binding.model.api.Type
+import org.opendaylight.mdsal.binding.model.util.Types
import org.opendaylight.mdsal.binding.model.util.TypeConstants
/**
def private generateStaticMethod(MethodSignature method) {
switch method.name {
+ case BINDING_EQUALS_NAME : generateBindingEquals
case BINDING_HASHCODE_NAME : generateBindingHashCode
case BINDING_TO_STRING_NAME : generateBindingToString
}
/**
* Default implementation of {@link «Object.importedName»#hashCode()} contract for this interface.
* Implementations of this interface are encouraged to defer to this method to get consistent hashing
- * results across all implementation.
+ * results across all implementations.
*
«IF augmentable»
- * <p>
* @param <T$$> implementation type, which has to also implement «AUGMENTATION_HOLDER.importedName» interface
* contract.
«ENDIF»
* @throws «NPE.importedName» if {@code obj} is null
*/
«IF augmentable»
- static <T$$ extends «type.fullyQualifiedName» & «AUGMENTATION_HOLDER.importedName»<?>> int «BINDING_HASHCODE_NAME»(final @«NONNULL.importedName» T$$ obj) {
+ static <T$$ extends «type.fullyQualifiedName» & «AUGMENTATION_HOLDER.importedName»<?>> int «BINDING_HASHCODE_NAME»(final @«NONNULL.importedName» T$$ obj) {
«ELSE»
- static int «BINDING_HASHCODE_NAME»(final «type.fullyQualifiedName» obj) {
+ static int «BINDING_HASHCODE_NAME»(final «type.fullyQualifiedName» obj) {
«ENDIF»
final int prime = 31;
int result = 1;
}
'''
+ def private generateBindingEquals() '''
+ «val augmentable = analyzeType»
+ «IF augmentable || !typeAnalysis.value.isEmpty»
+ /**
+ * Default implementation of {@link «Object.importedName»#equals(«Object.importedName»)} contract for this interface.
+ * Implementations of this interface are encouraged to defer to this method to get consistent equality
+ * results across all implementations.
+ *
+ «IF augmentable»
+ * @param <T$$> implementation type, which has to also implement «AUGMENTATION_HOLDER.importedName» interface
+ * contract.
+ «ENDIF»
+ * @param thisObj Object acting as the receiver of equals invocation
+ * @param obj Object acting as argument to equals invocation
+ * @return True if thisObj and obj are considered equal
+ * @throws «NPE.importedName» if {@code thisObj} is null
+ */
+ «IF augmentable»
+ static <T$$ extends «type.fullyQualifiedName» & «AUGMENTATION_HOLDER.importedName»<«type.fullyQualifiedName»>> boolean «BINDING_EQUALS_NAME»(final @«NONNULL.importedName» T$$ thisObj, final «Types.objectType().importedName» obj) {
+ «ELSE»
+ static boolean «BINDING_EQUALS_NAME»(final «type.fullyQualifiedName» thisObj, final «Types.objectType().importedName» obj) {
+ «ENDIF»
+ if (thisObj == obj) {
+ return true;
+ }
+ final «type.fullyQualifiedName» other = «CODEHELPERS.importedName».checkCast(«type.fullyQualifiedName».class, obj);
+ if (other == null) {
+ return false;
+ }
+ «FOR property : typeAnalysis.value»
+ if (!«property.importedUtilClass».equals(thisObj.«property.getterName»(), other.«property.getterName»())) {
+ return false;
+ }
+ «ENDFOR»
+ return «IF augmentable»«CODEHELPERS.importedName».equalsAugmentations(thisObj, other)«ELSE»true«ENDIF»;
+ }
+ «ENDIF»
+ '''
+
def generateBindingToString() '''
«val augmentable = analyzeType»
/**
* Default implementation of {@link «Object.importedName»#toString()} contract for this interface.
* Implementations of this interface are encouraged to defer to this method to get consistent string
- * representations across all implementation.
+ * representations across all implementations.
*
«IF augmentable»
- * <p>
* @param <T$$> implementation type, which has to also implement «AUGMENTATION_HOLDER.importedName» interface
* contract.
«ENDIF»
* @throws «NPE.importedName» if {@code obj} is null
*/
«IF augmentable»
- static <T$$ extends «type.fullyQualifiedName» & «AUGMENTATION_HOLDER.importedName»<«type.fullyQualifiedName»>> «STRING.importedName» «BINDING_TO_STRING_NAME»(final @«NONNULL.importedName» T$$ obj) {
+ static <T$$ extends «type.fullyQualifiedName» & «AUGMENTATION_HOLDER.importedName»<«type.fullyQualifiedName»>> «STRING.importedName» «BINDING_TO_STRING_NAME»(final @«NONNULL.importedName» T$$ obj) {
«ELSE»
- static «STRING.importedName» «BINDING_TO_STRING_NAME»(final «type.fullyQualifiedName» obj) {
+ static «STRING.importedName» «BINDING_TO_STRING_NAME»(final «type.fullyQualifiedName» obj) {
«ENDIF»
final «MoreObjects.importedName».ToStringHelper helper = «MoreObjects.importedName».toStringHelper("«type.name»");
«FOR property : typeAnalysis.value»
«formatDataForJavaDoc(method, "@return " + asCode(ret.fullyQualifiedName) + " " + asCode(propertyNameFromGetter(method)) + ", or an empty list if it is not present")»
«method.annotations.generateAnnotations»
default «ret.importedNonNull» «name»() {
- return «CODEHELPERS.importedName».nonnull(«getGetterMethodForNonnull(name)»());
+ return «CODEHELPERS.importedName».nonnull(«name.getGetterMethodForNonnull»());
}
'''
assertEquals("/**\n"
+ " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+ " * Implementations of this interface are encouraged to defer to this method to get consistent string"
- + "\n * representations across all implementation.\n"
+ + "\n * representations across all implementations.\n"
+ " *\n"
+ " * @param obj Object for which to generate toString() result.\n"
+ " * @return {@link String} value of data modeled by this interface.\n"
assertEquals("/**\n"
+ " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+ " * Implementations of this interface are encouraged to defer to this method to get consistent string"
- + "\n * representations across all implementation.\n"
+ + "\n * representations across all implementations.\n"
+ " *\n"
+ " * @param obj Object for which to generate toString() result.\n"
+ " * @return {@link String} value of data modeled by this interface.\n"
assertEquals("/**\n"
+ " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+ " * Implementations of this interface are encouraged to defer to this method to get consistent string"
- + "\n * representations across all implementation.\n"
+ + "\n * representations across all implementations.\n"
+ " *\n"
+ " * @param obj Object for which to generate toString() result.\n"
+ " * @return {@link String} value of data modeled by this interface.\n"
assertEquals("/**\n"
+ " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+ " * Implementations of this interface are encouraged to defer to this method to get consistent string"
- + "\n * representations across all implementation.\n"
+ + "\n * representations across all implementations.\n"
+ " *\n"
- + " * <p>\n"
+ " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
+ " * contract.\n"
+ " * @param obj Object for which to generate toString() result.\n"
assertEquals("/**\n"
+ " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+ " * Implementations of this interface are encouraged to defer to this method to get consistent string"
- + "\n * representations across all implementation.\n"
+ + "\n * representations across all implementations.\n"
+ " *\n"
- + " * <p>\n"
+ " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
+ " * contract.\n"
+ " * @param obj Object for which to generate toString() result.\n"
assertEquals("/**\n"
+ " * Default implementation of {@link Object#toString()} contract for this interface.\n"
+ " * Implementations of this interface are encouraged to defer to this method to get consistent string"
- + "\n * representations across all implementation.\n"
+ + "\n * representations across all implementations.\n"
+ " *\n"
- + " * <p>\n"
+ " * @param <T$$> implementation type, which has to also implement AugmentationHolder interface\n"
+ " * contract.\n"
+ " * @param obj Object for which to generate toString() result.\n"
*/
public static final @NonNull String BINDING_HASHCODE_NAME = "bindingHashCode";
+ /**
+ * Name of default {@link Object#equals(Object)} implementation for instantiated DataObjects. Each such generated
+ * interface contains this static method.
+ */
+ public static final @NonNull String BINDING_EQUALS_NAME = "bindingEquals";
+
/**
* Name of default {@link Object#toString()} implementation for instantiated DataObjects. Each such generated
* interface contains this static method.
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNull;
return value == null ? null : Uint64.valueOf(value);
}
+ /**
+ * Utility method for checking whether a target object is a compatible DataObject.
+ *
+ * @param requiredClass Required DataObject class
+ * @param obj Object to check, may be null
+ * @return Object cast to required class, if its implemented class matches requirement, null otherwise
+ * @throws NullPointerException if {@code requiredClass} is null
+ */
+ public static <T extends DataObject> @Nullable T checkCast(final @NonNull Class<T> requiredClass,
+ final @Nullable Object obj) {
+ return obj instanceof DataObject && requiredClass.equals(((DataObject) obj).implementedInterface())
+ ? requiredClass.cast(obj) : null;
+ }
+
+ /**
+ * Utility method for comparing two augmentable objects' augmentations.
+ *
+ * @param <T> Augmentable type
+ * @param thisObj The object representing 'this'
+ * @param other The object representing 'obj'
+ * @return True if both object's augmentations are equal
+ * @throws NullPointerException if any argument is null
+ */
+ public static <T extends Augmentable<T>> boolean equalsAugmentations(final @NonNull AugmentationHolder<T> thisObj,
+ final @NonNull Augmentable<T> other) {
+ if (other instanceof AugmentationHolder) {
+ // Simple case: other object is also an AugmentationHolder
+ return thisObj.augmentations().equals(((AugmentationHolder<?>) other).augmentations());
+ }
+
+ // Hard case: compare our augments with presence there...
+ for (Entry<Class<? extends Augmentation<T>>, Augmentation<T>> e : thisObj.augmentations().entrySet()) {
+ if (!e.getValue().equals(other.augmentation(e.getKey()))) {
+ return false;
+ }
+ }
+ // .. and give the other one the chance to do the same
+ return other.equals(thisObj);
+ }
+
/**
* Utility for extracting augmentations from an implementation of {@link AugmentationHolder} interface.
*