Improved generation of hashCode and equals.
authorMartin Vitez <mvitez@cisco.com>
Thu, 10 Oct 2013 10:59:17 +0000 (12:59 +0200)
committerMartin Vitez <mvitez@cisco.com>
Thu, 10 Oct 2013 10:59:17 +0000 (12:59 +0200)
Fix for Bug 103.
Fixed generation of hashCode and equals for array variables using Arrays.hashCode and Arrays.equals.

Signed-off-by: Martin Vitez <mvitez@cisco.com>
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/ClassTemplate.xtend
code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/CompilationTest.java
code-generator/binding-java-api-generator/src/test/resources/compilation/leaf-return-types/test.yang [new file with mode: 0644]

index 18d6730bd10dd0953ec60d6ddfc3e83ca485ffb1..6857ed2be940f5e8ece8b0a0c9ccad73f4e3e53d 100644 (file)
@@ -321,7 +321,11 @@ class BuilderTemplate extends BaseTemplate {
                 final int prime = 31;\r
                 int result = 1;\r
                 «FOR property : properties»\r
+                    «IF property.returnType.name.contains("[")»\r
+                    result = prime * result + ((«property.fieldName» == null) ? 0 : java.util.Arrays.hashCode(«property.fieldName»));\r
+                    «ELSE»\r
                     result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());\r
+                    «ENDIF»\r
                 «ENDFOR»\r
                 «IF augmentField != null»\r
                     result = prime * result + ((«augmentField.name» == null) ? 0 : «augmentField.name».hashCode());\r
@@ -356,7 +360,11 @@ class BuilderTemplate extends BaseTemplate {
                         if (other.«fieldName» != null) {\r
                             return false;\r
                         }\r
+                    «IF property.returnType.name.contains("[")»\r
+                    } else if(!java.util.Arrays.equals(«fieldName», other.«fieldName»)) {\r
+                    «ELSE»\r
                     } else if(!«fieldName».equals(other.«fieldName»)) {\r
+                    «ENDIF»\r
                         return false;\r
                     }\r
                 «ENDFOR»\r
index 700e6f87b1253f0e80594476c13012a237c19bb0..56bb2b3163bf2cfdd6a6406697e9745006d52cd2 100644 (file)
@@ -230,13 +230,13 @@ class ClassTemplate extends BaseTemplate {
                     «IF cValue instanceof List<?>»\r
                         «val cValues = cValue as List<?>»\r
                         private static final List<Pattern> «Constants.MEMBER_PATTERN_LIST» = new ArrayList<Pattern>();\r
-                        public static final List<String> «TypeConstants.PATTERN_CONSTANT_NAME» = Arrays.asList(«\r
+                        public static final List<String> «TypeConstants.PATTERN_CONSTANT_NAME» = java.util.Arrays.asList(«\r
                         FOR v : cValues SEPARATOR ", "»«\r
                             IF v instanceof String»"«\r
                                 v as String»"«\r
                             ENDIF»«\r
                         ENDFOR»);\r
-                        \r
+\r
                         «generateStaticInicializationBlock»\r
                     «ENDIF»\r
                 «ELSE»\r
@@ -245,10 +245,10 @@ class ClassTemplate extends BaseTemplate {
             «ENDFOR»\r
         «ENDIF»\r
     '''\r
-    \r
+\r
     /**\r
      * Template method which generates JAVA static initialization block.\r
-     * \r
+     *\r
      * @return string with static initialization block in JAVA format\r
      */\r
     def protected generateStaticInicializationBlock() '''\r
@@ -258,10 +258,10 @@ class ClassTemplate extends BaseTemplate {
             }\r
         }\r
     '''\r
-    \r
+\r
     /**\r
      * Template method which generates JAVA class attributes.\r
-     * \r
+     *\r
      * @return string with the class attributes in JAVA format\r
      */\r
     def protected generateFields() '''\r
@@ -271,11 +271,11 @@ class ClassTemplate extends BaseTemplate {
             «ENDFOR»\r
         «ENDIF»\r
     '''\r
-    \r
+\r
 \r
     /**\r
      * Template method which generates the method <code>hashCode()</code>.\r
-     * \r
+     *\r
      * @return string with the <code>hashCode()</code> method definition in JAVA format\r
      */\r
     def protected generateHashCode() '''\r
@@ -285,17 +285,21 @@ class ClassTemplate extends BaseTemplate {
                 final int prime = 31;\r
                 int result = 1;\r
                 «FOR property : genTO.hashCodeIdentifiers»\r
+                    «IF property.returnType.name.contains("[")»\r
+                    result = prime * result + ((«property.fieldName» == null) ? 0 : java.util.Arrays.hashCode(«property.fieldName»));\r
+                    «ELSE»\r
                     result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());\r
+                    «ENDIF»\r
                 «ENDFOR»\r
                 return result;\r
             }\r
         «ENDIF»\r
     '''\r
-    \r
+\r
     /**\r
      * Template method which generates the method <code>equals()</code>.\r
-     * \r
-     * @return string with the <code>equals()</code> method definition in JAVA format     \r
+     *\r
+     * @return string with the <code>equals()</code> method definition in JAVA format\r
      */\r
     def protected generateEquals() '''\r
         «IF !genTO.equalsIdentifiers.empty»\r
@@ -317,7 +321,11 @@ class ClassTemplate extends BaseTemplate {
                         if (other.«fieldName» != null) {\r
                             return false;\r
                         }\r
+                    «IF property.returnType.name.contains("[")»\r
+                    } else if(!java.util.Arrays.equals(«fieldName», other.«fieldName»)) {\r
+                    «ELSE»\r
                     } else if(!«fieldName».equals(other.«fieldName»)) {\r
+                    «ENDIF»\r
                         return false;\r
                     }\r
                 «ENDFOR»\r
@@ -325,11 +333,11 @@ class ClassTemplate extends BaseTemplate {
             }\r
         «ENDIF»\r
     '''\r
-    \r
+\r
     /**\r
      * Template method which generates the method <code>toString()</code>.\r
-     * \r
-     * @return string with the <code>toString()</code> method definition in JAVA format     \r
+     *\r
+     * @return string with the <code>toString()</code> method definition in JAVA format\r
      */\r
     def protected generateToString() '''\r
         «IF !genTO.toStringIdentifiers.empty»\r
index 06d09b18738e79d3dbad46167f936738f347627d..512c499cda8c111e9203afc5fc43de320f767907 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.sal.java.api.generator.test;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
@@ -40,6 +41,9 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
  */
 public class CompilationTest {
     private static final String FS = File.separator;
+    private static final String NS_STRING = "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1" + FS
+            + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008";
+
     private static final String TEST_PATH = "target" + FS + "test";
     private static final File TEST_DIR = new File(TEST_PATH);
 
@@ -93,8 +97,8 @@ public class CompilationTest {
         final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
         generator.generateToFile(sourcesOutputDir);
 
-        File parent = new File(sourcesOutputDir, "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1"
-                + FS + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008");
+        // Test if all sources are generated
+        File parent = new File(sourcesOutputDir, NS_STRING);
         File linksKeyFile = new File(parent, "LinksKey.java");
         assertTrue(new File(parent, "KeyArgs.java").exists());
         assertTrue(new File(parent, "Links.java").exists());
@@ -109,9 +113,9 @@ public class CompilationTest {
         assertTrue(new File(parent, "links" + FS + "NodeListBuilder.java").exists());
         assertTrue(linksKeyFile.exists());
 
+        // Test if sources are compilable
         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
         StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
-
         List<File> filesList = getJavaFiles(sourcesOutputDir);
         Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
         Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
@@ -122,7 +126,7 @@ public class CompilationTest {
         Class<?> linksKeyClass = Class.forName("org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.LinksKey",
                 true, loader);
 
-        // test list key constructor arguments ordering
+        // Test list key constructor arguments ordering
         try {
             linksKeyClass.getConstructor(Byte.class, String.class, Integer.class);
         } catch (NoSuchMethodException e) {
@@ -146,8 +150,8 @@ public class CompilationTest {
         final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
         generator.generateToFile(sourcesOutputDir);
 
-        File parent = new File(sourcesOutputDir + FS + "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS
-                + "v1" + FS + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008");
+        // Test if all sources are generated
+        File parent = new File(sourcesOutputDir, NS_STRING);
         assertTrue(new File(parent, "Object.java").exists());
         assertTrue(new File(parent, "OpenObject.java").exists());
         assertTrue(new File(parent, "object" + FS + "Nodes.java").exists());
@@ -157,6 +161,40 @@ public class CompilationTest {
         assertTrue(new File(parent, "open" + FS + "object" + FS + "nodes" + FS + "Links.java").exists());
         assertTrue(new File(parent, "open" + FS + "object" + FS + "nodes" + FS + "LinksBuilder.java").exists());
 
+        // Test if sources are compilable
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
+
+        List<File> filesList = getJavaFiles(sourcesOutputDir);
+        Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
+        Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
+        boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
+        assertTrue(compiled);
+
+        cleanUp(sourcesOutputDir, compiledOutputDir);
+    }
+
+    // TODO: add test for return types, equals and hashcode
+    @Test
+    public void testLeafReturnTypes() throws Exception {
+        final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "leaf-return-types");
+        assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
+        final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "leaf-return-types");
+        assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
+
+        final List<File> sourceFiles = getSourceFiles("/compilation/leaf-return-types");
+        final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
+        final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
+        final List<Type> types = bindingGenerator.generateTypes(context);
+        final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
+        generator.generateToFile(sourcesOutputDir);
+
+        File parent = new File(sourcesOutputDir, NS_STRING);
+        assertTrue(new File(parent, "TestData.java").exists());
+        assertTrue(new File(parent, "Nodes.java").exists());
+        assertTrue(new File(parent, "NodesBuilder.java").exists());
+        assertTrue(new File(parent, "Alg.java").exists());
+
         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
         StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
 
@@ -191,21 +229,33 @@ public class CompilationTest {
         Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
         boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
         assertTrue(compiled);
+
+        cleanUp(sourcesOutputDir, compiledOutputDir);
     }
 
-    private List<File> getSourceFiles(String path) {
+    private List<File> getSourceFiles(String path) throws FileNotFoundException {
         final String resPath = getClass().getResource(path).getPath();
         final File sourcesDir = new File(resPath);
-        final List<File> sourceFiles = new ArrayList<>();
-        final File[] fileArray = sourcesDir.listFiles();
-        sourceFiles.addAll(Arrays.asList(fileArray));
-        return sourceFiles;
+        if (sourcesDir.exists()) {
+            final List<File> sourceFiles = new ArrayList<>();
+            final File[] fileArray = sourcesDir.listFiles();
+            if (fileArray == null) {
+                throw new IllegalArgumentException("Unable to locate files in " + sourcesDir);
+            }
+            sourceFiles.addAll(Arrays.asList(fileArray));
+            return sourceFiles;
+        } else {
+            throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")");
+        }
     }
 
     private static void deleteTestDir(File file) {
         if (file.isDirectory()) {
-            for (File f : file.listFiles()) {
-                deleteTestDir(f);
+            File[] filesToDelete = file.listFiles();
+            if (filesToDelete != null) {
+                for (File f : filesToDelete) {
+                    deleteTestDir(f);
+                }
             }
         }
         if (!file.delete()) {
@@ -221,14 +271,17 @@ public class CompilationTest {
      * @return List of java files found
      */
     private List<File> getJavaFiles(File directory) {
-        List<File> result = new ArrayList<File>();
-        for (File file : directory.listFiles()) {
-            if (file.isDirectory()) {
-                result.addAll(getJavaFiles(file));
-            } else {
-                String absPath = file.getAbsolutePath();
-                if (absPath.endsWith(".java")) {
-                    result.add(file);
+        List<File> result = new ArrayList<>();
+        File[] filesToRead = directory.listFiles();
+        if (filesToRead != null) {
+            for (File file : filesToRead) {
+                if (file.isDirectory()) {
+                    result.addAll(getJavaFiles(file));
+                } else {
+                    String absPath = file.getAbsolutePath();
+                    if (absPath.endsWith(".java")) {
+                        result.add(file);
+                    }
                 }
             }
         }
diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/leaf-return-types/test.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/leaf-return-types/test.yang
new file mode 100644 (file)
index 0000000..e55d253
--- /dev/null
@@ -0,0 +1,93 @@
+module test {
+    yang-version 1;
+    namespace "urn:opendaylight:test";
+    prefix "t";
+
+    revision "2013-10-08" {
+    }
+
+    container nodes {
+        leaf id-binary {
+            type binary;
+        }
+        leaf id-bits {
+            type bits {
+                bit ctrl;
+                bit alt {
+                    position 5;
+                }
+                bit delete;
+            }
+        }
+        leaf id-boolean {
+            type boolean;
+        }
+        leaf id-decimal64 {
+            type decimal64 {
+                fraction-digits 4;
+            }
+        }
+        leaf id-empty {
+            type empty;
+        }
+        leaf id-enumeration {
+            type enumeration {
+                enum zero;
+                enum one;
+                enum seven {
+                    value 7;
+                }
+            }
+        }
+        leaf id-identityref {
+            type identityref {
+                base alg;
+            }
+        }
+        leaf id-instance-identifier {
+            type instance-identifier;
+        }
+        leaf id-8 {
+            type int8;
+        }
+        leaf id-16 {
+            type int16;
+        }
+        leaf id-32 {
+            type int32;
+        }
+        leaf id-64 {
+            type int64;
+        }
+        leaf id-leafref {
+            type leafref {
+                path "/nodes/id-64";
+            }
+        }
+        leaf id-string {
+            type string;
+        }
+        leaf id-u8 {
+            type uint8;
+        }
+        leaf id-u16 {
+            type uint16;
+        }
+        leaf id-u32 {
+            type uint32;
+        }
+        leaf id-u64 {
+            type uint64;
+        }
+        leaf id-union {
+            type union {
+                type string;
+                type binary;
+            }
+        }
+    }
+
+    identity alg {
+    }
+
+}