Tag TypeObjects which wrap a value with ScalarTypeObject 51/88651/13
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 24 Mar 2020 15:58:29 +0000 (16:58 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 19 Apr 2020 15:28:13 +0000 (17:28 +0200)
Capturing this type of objects has a nice side-effect of being
able to specialize code generation. It is furthermore useful
for providing a common definition of getValue() method.

This is an unfortunate side-effect of changing the API
mapping for boolean typedefs: the accessor changes from isValue()
to getValue().

JIRA: MDSAL-530
Change-Id: Ie40e50bbe566a747d0a5d3e9ff84e428c2960a94
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/EncapsulatedValueCodec.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/AbstractTypeProvider.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal406TypeObjectTest.java
binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/BindingGeneratorUtil.java
binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/BindingTypes.java
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend
binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/test/TypedefCompilationTest.java
binding/mdsal-binding-test-utils/src/test/java/org/opendaylight/mdsal/binding/testutils/UnionTest.java

index 3452e2ac65bd1fe575da2b0f16feca4092f35e1b..97ee81ff51fef8df9d943d165494e06f04518ab7 100644 (file)
@@ -17,8 +17,8 @@ import java.lang.invoke.MethodType;
 import java.lang.reflect.Method;
 import java.util.concurrent.Callable;
 import org.opendaylight.mdsal.binding.dom.codec.impl.ValueTypeCodec.SchemaUnawareCodec;
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
 
 /**
  * Derived YANG types are just immutable value holders for simple value
@@ -41,15 +41,9 @@ final class EncapsulatedValueCodec extends ReflectionBasedCodec implements Schem
 
     static Callable<EncapsulatedValueCodec> loader(final Class<?> typeClz, final TypeDefinition<?> typeDef) {
         return () -> {
-            final Method m;
-            if (typeDef instanceof BooleanTypeDefinition) {
-                m = typeClz.getMethod("isValue");
-            } else {
-                m = typeClz.getMethod("getValue");
-            }
+            final Method m = typeClz.getMethod(BindingMapping.SCALAR_TYPE_OBJECT_GET_VALUE_NAME);
             final MethodHandle getter = LOOKUP.unreflect(m).asType(OBJ_METHOD);
             final Class<?> valueType = m.getReturnType();
-
             final MethodHandle constructor = LOOKUP.findConstructor(typeClz,
                 MethodType.methodType(void.class, valueType)).asType(OBJ_METHOD);
             return new EncapsulatedValueCodec(typeClz, constructor, getter, valueType);
index 67c8aa6ef9c6e9cb4a1f3086ed43e72d91349d60..34a57700e1d3043a7a2b49827375bb38e67930d9 100644 (file)
@@ -50,6 +50,7 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilde
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
 import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
 import org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil;
+import org.opendaylight.mdsal.binding.model.util.BindingTypes;
 import org.opendaylight.mdsal.binding.model.util.TypeConstants;
 import org.opendaylight.mdsal.binding.model.util.Types;
 import org.opendaylight.mdsal.binding.model.util.generated.type.builder.AbstractEnumerationBuilder;
@@ -864,10 +865,11 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
         final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(TypeConstants.VALUE_PROP);
         genPropBuilder.setReturnType(javaType);
+
         genTOBuilder.addEqualsIdentity(genPropBuilder);
         genTOBuilder.addHashIdentity(genPropBuilder);
         genTOBuilder.addToStringProperty(genPropBuilder);
-        genTOBuilder.addImplementsType(TYPE_OBJECT);
+        genTOBuilder.addImplementsType(BindingTypes.scalarTypeObject(javaType));
         if (typedef.getStatus() == Status.DEPRECATED) {
             genTOBuilder.addAnnotation("java.lang", "Deprecated");
         }
index fa0edee85a512190721f00eee1cfdcb230f45435..074b7cdc9e1d222a75bc4b17658e65b4f4bb5840 100644 (file)
@@ -16,6 +16,8 @@ import java.util.List;
 import org.junit.Test;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.mdsal.binding.model.util.BindingTypes;
+import org.opendaylight.mdsal.binding.model.util.Types;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 
@@ -35,8 +37,8 @@ public class Mdsal406TypeObjectTest {
         assertNotNull(((GeneratedType)  typedefType).getImplements());
         Type objectType = ((GeneratedType)  typedefType).getImplements().stream()
                 .filter(type -> type.getFullyQualifiedName()
-                .equals("org.opendaylight.yangtools.yang.binding.TypeObject")).findAny().get();
-        assertEquals(TYPE_OBJECT, objectType);
+                .equals("org.opendaylight.yangtools.yang.binding.ScalarTypeObject")).findAny().get();
+        assertEquals(BindingTypes.scalarTypeObject(Types.BYTE_ARRAY), objectType);
     }
 
     @Test
index 23613d539727d981fef4f6ddea152b109e8b5e01..6b5656291ae16ecbad2ea6f38f7daebc403da873 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.base.CharMatcher;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
@@ -94,6 +95,9 @@ public final class BindingGeneratorUtil {
 
     private static final Comparator<Type> SUID_NAME_COMPARATOR = Comparator.comparing(Type::getFullyQualifiedName);
 
+    private static final ImmutableSet<?> IGNORED_INTERFACES =
+            ImmutableSet.of(BindingTypes.TYPE_OBJECT, BindingTypes.SCALAR_TYPE_OBJECT);
+
     /**
      * Converts <code>parameterName</code> to valid JAVA parameter name. If the <code>parameterName</code> is one
      * of the JAVA reserved words then it is prefixed with underscore character.
@@ -215,7 +219,7 @@ public final class BindingGeneratorUtil {
     }
 
     private static Collection<Type> filteredImplementsTypes(final GeneratedTypeBuilderBase<?> to) {
-        return Collections2.filter(to.getImplementsTypes(), item -> !BindingTypes.TYPE_OBJECT.equals(item));
+        return Collections2.filter(to.getImplementsTypes(), item -> !IGNORED_INTERFACES.contains(item));
     }
 
     private static <T extends Optional<?>> T currentOrEmpty(final T current, final T base) {
index b1d3fee913e14031081b191983c92b023ff61e09..591f4f35fc2980800f063687a205e0ed2227c8b5 100644 (file)
@@ -57,6 +57,7 @@ public final class BindingTypes {
     public static final ConcreteType RPC_INPUT = typeForClass(RpcInput.class);
     public static final ConcreteType RPC_OUTPUT = typeForClass(RpcOutput.class);
     public static final ConcreteType RPC_SERVICE = typeForClass(RpcService.class);
+    public static final ConcreteType SCALAR_TYPE_OBJECT = typeForClass(ScalarTypeObject.class);
 
     // This is an annotation, we are current just referencing the type
     public static final JavaTypeName ROUTING_CONTEXT = JavaTypeName.create(RoutingContext.class);
@@ -81,7 +82,6 @@ public final class BindingTypes {
     private static final ConcreteType KEYED_LIST_NOTIFICATION = typeForClass(KeyedListNotification.class);
     private static final ConcreteType OPAQUE_OBJECT = typeForClass(OpaqueObject.class);
     private static final ConcreteType RPC_RESULT = typeForClass(RpcResult.class);
-    private static final ConcreteType SCALAR_TYPE_OBJECT = typeForClass(ScalarTypeObject.class);
 
     private BindingTypes() {
 
index ca39faad6e4b4bdeb42ed655bb7b252d2fa332f8..a41bd27edd9805e9b9f122ec53ac7e7b2242d7b6 100644 (file)
@@ -39,6 +39,8 @@ import org.opendaylight.yangtools.yang.common.Uint32
 import org.opendaylight.yangtools.yang.common.Uint64
 import org.opendaylight.yangtools.yang.common.Uint8
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
+import org.opendaylight.mdsal.binding.model.util.BindingTypes
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
 
 /**
  * Template for generating JAVA class.
@@ -148,12 +150,7 @@ class ClassTemplate extends BaseTemplate {
 
             «defaultInstance»
 
-            «FOR field : properties SEPARATOR "\n"»
-                «field.getterMethod»
-                «IF !field.readOnly»
-                    «field.setterMethod»
-                «ENDIF»
-            «ENDFOR»
+            «propertyMethods»
 
             «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)»
                 «generateGetValueForBitsTypeDef»
@@ -168,6 +165,38 @@ class ClassTemplate extends BaseTemplate {
 
     '''
 
+    def private propertyMethods() {
+        if (properties.empty) {
+            return ""
+        }
+        isScalarTypeObject ? scalarTypeObjectValue(properties.get(0)) : defaultProperties
+    }
+
+    def private isScalarTypeObject() {
+        for (impl : genTO.implements) {
+            if (BindingTypes.SCALAR_TYPE_OBJECT.identifier.equals(impl.identifier)) {
+                return true
+            }
+        }
+        return false
+    }
+
+    def private defaultProperties() '''
+        «FOR field : properties SEPARATOR "\n"»
+            «field.getterMethod»
+            «IF !field.readOnly»
+                «field.setterMethod»
+            «ENDIF»
+        «ENDFOR»
+    '''
+
+    def private scalarTypeObjectValue(GeneratedProperty field) '''
+        @«OVERRIDE.importedName»
+        public «field.returnType.importedName» «BindingMapping.SCALAR_TYPE_OBJECT_GET_VALUE_NAME»() {
+            return «field.fieldName»«IF field.returnType.name.endsWith("[]")».clone()«ENDIF»;
+        }
+    '''
+
     /**
      * Template method which generates the method <code>getValue()</code> for typedef,
      * which base type is BitsDefinition.
index 38636e060021296ad63be95057943d4f0ba06152..dd932fba0fe18003a7475f4ce623d46d134026df 100644 (file)
@@ -124,7 +124,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         CompilationTestUtils.assertContainsMethod(int32Ext1Class, Integer.class, GET_VAL);
         defInst = CompilationTestUtils.assertContainsMethod(int32Ext1Class, int32Ext1Class, "getDefaultInstance",
             String.class);
-        assertEquals(6, int32Ext1Class.getDeclaredMethods().length);
+        assertEquals(7, int32Ext1Class.getDeclaredMethods().length);
 
         List<Range<Integer>> rangeConstraints = new ArrayList<>();
         rangeConstraints.add(Range.closed(2, 2147483647));
@@ -173,7 +173,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         defInst = CompilationTestUtils.assertContainsMethod(stringExt1Class, stringExt1Class, "getDefaultInstance",
             String.class);
         CompilationTestUtils.assertContainsDefaultMethods(stringExt1Class);
-        assertEquals(6, stringExt1Class.getDeclaredMethods().length);
+        assertEquals(7, stringExt1Class.getDeclaredMethods().length);
 
         List<Range<Integer>> lengthConstraints = new ArrayList<>();
         lengthConstraints.add(Range.closed(5, 11));
@@ -235,7 +235,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         CompilationTestUtils.assertContainsDefaultMethods(myDecimalTypeClass);
         defInst = CompilationTestUtils.assertContainsMethod(myDecimalTypeClass, myDecimalTypeClass,
             "getDefaultInstance", String.class);
-        assertEquals(6, myDecimalTypeClass.getDeclaredMethods().length);
+        assertEquals(7, myDecimalTypeClass.getDeclaredMethods().length);
 
         List<Range<BigDecimal>> decimalRangeConstraints = new ArrayList<>();
         decimalRangeConstraints.add(Range.closed(new BigDecimal("1.5"), new BigDecimal("5.5")));
@@ -259,7 +259,7 @@ public class TypedefCompilationTest extends BaseCompilationTest {
         CompilationTestUtils.assertContainsDefaultMethods(myDecimalType2Class);
         defInst = CompilationTestUtils.assertContainsMethod(myDecimalType2Class, myDecimalType2Class,
             "getDefaultInstance", String.class);
-        assertEquals(6, myDecimalType2Class.getDeclaredMethods().length);
+        assertEquals(7, myDecimalType2Class.getDeclaredMethods().length);
 
         List<Range<BigDecimal>> decimal2RangeConstraints = new ArrayList<>();
         decimal2RangeConstraints.add(Range.closed(new BigDecimal("0"), new BigDecimal("1")));
index def91b161ce344d356379dd2fba2e0f2ea7ac488..867952da28a7184b4513f26601c956bac66d334d 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.mdsal.binding.testutils;
 
 import ch.vorburger.xtendbeans.AssertBeans;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.union.rev150121.LowestLevel2;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.union.rev150121.UnionTestType;
@@ -21,6 +22,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtool
  */
 public class UnionTest {
 
+    // Has random failures based on method order due to https://github.com/vorburger/xtendbeans/pull/33
+    @Ignore
     @Test
     public void testUnionType() {
         AssertBeans.assertEqualByText(