Optimize range/length generators 17/68917/22
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 28 Feb 2018 22:05:47 +0000 (23:05 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 11 Mar 2018 18:31:52 +0000 (19:31 +0100)
This patch improves range/length generators so that share common utility
methods from CodeHelper, eliminating common literals in generated code.

It also adds the ability for generators to import classes, leading to much
more readable code.

Change-Id: I98f103e9c05a1d68f0f4bc4c6c33146cb654e5bb
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractBigRangeGenerator.java
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractPrimitiveRangeGenerator.java
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/AbstractRangeGenerator.java
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderTemplate.xtend
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/main/java/org/opendaylight/mdsal/binding/java/api/generator/LengthGenerator.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/CodeHelpers.java

index fec0148623cd3ee88bc3fe40218b8572e01d23e0..c55694048cf994841f2db0a47cd4a7ebd8686a42 100644 (file)
@@ -8,8 +8,11 @@
 package org.opendaylight.mdsal.binding.java.api.generator;
 
 import com.google.common.collect.Range;
+import java.lang.reflect.Array;
 import java.util.Set;
+import java.util.function.Function;
 import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.CodeHelpers;
 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
 
 /**
@@ -21,41 +24,46 @@ import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
  * @param <T> type of the class
  */
 abstract class AbstractBigRangeGenerator<T extends Number & Comparable<T>> extends AbstractRangeGenerator<T> {
-    private static final String RANGE = Range.class.getName();
-
     protected AbstractBigRangeGenerator(final Class<T> typeClass) {
         super(typeClass);
     }
 
-    private StringBuilder itemType() {
-        return new StringBuilder(RANGE).append('<').append(getTypeName()).append('>');
+    private static String range(final Function<Class<?>, String> classImporter) {
+        return classImporter.apply(Range.class);
+    }
+
+    private String itemType(final Function<Class<?>, String> classImporter) {
+        return range(classImporter) + '<' + getTypeName() + '>';
     }
 
-    private StringBuilder arrayType() {
-        return new StringBuilder(itemType()).append("[]");
+    private String arrayType(final Function<Class<?>, String> classImporter) {
+        return itemType(classImporter) + "[]";
     }
 
     @Override
-    protected final String generateRangeCheckerImplementation(final String checkerName, @Nonnull final RangeConstraint<?> constraint) {
+    protected final String generateRangeCheckerImplementation(final String checkerName,
+            @Nonnull final RangeConstraint<?> constraint, final Function<Class<?>, String> classImporter) {
         final Set<? extends Range<? extends Number>> constraints = constraint.getAllowedRanges().asRanges();
         final String fieldName = checkerName.toUpperCase() + "_RANGES";
         final StringBuilder sb = new StringBuilder();
 
         // Field to hold the Range objects in an array
-        sb.append("private static final ").append(arrayType()).append(' ').append(fieldName).append(";\n");
+        sb.append("private static final ").append(arrayType(classImporter)).append(' ').append(fieldName).append(";\n");
 
         // Static initializer block for the array
         sb.append("static {\n");
         sb.append("    @SuppressWarnings(\"unchecked\")\n");
-        sb.append("    final ").append(arrayType()).append(" a = (").append(arrayType())
-        .append(") java.lang.reflect.Array.newInstance(").append(RANGE).append(".class, ").append(constraints.size()).append(");\n");
+        sb.append("    final ").append(arrayType(classImporter)).append(" a = (").append(arrayType(classImporter)).append(") ")
+        .append(classImporter.apply(Array.class)).append(".newInstance(").append(range(classImporter)).append(".class, ")
+        .append(constraints.size()).append(");\n");
 
         int i = 0;
         for (Range<? extends Number> r : constraints) {
             final String min = format(getValue(r.lowerEndpoint()));
             final String max = format(getValue(r.upperEndpoint()));
 
-            sb.append("    a[").append(i++).append("] = ").append(RANGE).append(".closed(").append(min).append(", ").append(max).append(");\n");
+            sb.append("    a[").append(i++).append("] = ").append(range(classImporter)).append(".closed(").append(min).append(", ")
+            .append(max).append(");\n");
         }
 
         sb.append("    ").append(fieldName).append(" = a;\n");
@@ -63,12 +71,13 @@ abstract class AbstractBigRangeGenerator<T extends Number & Comparable<T>> exten
 
         // Static enforcement method
         sb.append("private static void ").append(checkerName).append("(final ").append(getTypeName()).append(" value) {\n");
-        sb.append("    for (").append(itemType()).append(" r : ").append(fieldName).append(") {\n");
+        sb.append("    for (").append(itemType(classImporter)).append(" r : ").append(fieldName).append(") {\n");
         sb.append("        if (r.contains(value)) {\n");
         sb.append("            return;\n");
         sb.append("        }\n");
         sb.append("    }\n");
-        sb.append("    throw new IllegalArgumentException(String.format(\"Invalid range: %s, expected: %s.\", value, java.util.Arrays.asList(").append(fieldName).append(")));\n");
+
+        sb.append("    ").append(classImporter.apply(CodeHelpers.class)).append(".throwInvalidRange(").append(fieldName).append(", value);\n");
         sb.append("}\n");
 
         return sb.toString();
index 549a75fe60210ba55f90d907f413b4a61a756779..d57f00daaee50cbe7d131a9b0ccfc8e1ba84a86f 100644 (file)
@@ -13,7 +13,9 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Function;
 import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.CodeHelpers;
 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -94,7 +96,7 @@ abstract class AbstractPrimitiveRangeGenerator<T extends Number & Comparable<T>>
 
     @Override
     protected final String generateRangeCheckerImplementation(final String checkerName,
-            final RangeConstraint<?> constraints) {
+            final RangeConstraint<?> constraints, final Function<Class<?>, String> classImporter) {
         final StringBuilder sb = new StringBuilder();
         final Collection<String> expressions = createExpressions(constraints);
 
@@ -107,8 +109,8 @@ abstract class AbstractPrimitiveRangeGenerator<T extends Number & Comparable<T>>
                 sb.append("    }\n");
             }
 
-            sb.append("    throw new IllegalArgumentException(String.format(\"Invalid range: %s, expected: ")
-              .append(createRangeString(constraints)).append(".\", value));\n");
+            sb.append("    ").append(classImporter.apply(CodeHelpers.class)).append(".throwInvalidRange(\"")
+            .append(createRangeString(constraints)).append("\", value);\n");
         }
 
         sb.append("}\n");
index 47aaa728d2a1e07c7b8812d0dc64f25d3c902d57..e5c09346be472e1a2f7b610ef588130fc83d15ac 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import java.util.Map;
+import java.util.function.Function;
 import javax.annotation.Nonnull;
 import org.opendaylight.mdsal.binding.model.api.ConcreteType;
 import org.opendaylight.mdsal.binding.model.api.Type;
@@ -93,7 +94,7 @@ abstract class AbstractRangeGenerator<T extends Number & Comparable<T>> {
 
     // FIXME: Once BUG-3399 is fixed, we should never need this
     @Deprecated
-    protected abstract T convert(final Number value);
+    protected abstract T convert(Number value);
 
     /**
      * Format a value into a Java-compilable expression which results in the appropriate
@@ -102,7 +103,7 @@ abstract class AbstractRangeGenerator<T extends Number & Comparable<T>> {
      * @param value Number value
      * @return Java language string representation
      */
-    @Nonnull protected abstract String format(final T value);
+    @Nonnull protected abstract String format(T value);
 
     /**
      * Generate the checker method source code.
@@ -110,15 +111,16 @@ abstract class AbstractRangeGenerator<T extends Number & Comparable<T>> {
      * @param constraints Restrictions which need to be applied.
      * @return Method source code.
      */
-    @Nonnull protected abstract String generateRangeCheckerImplementation(@Nonnull final String checkerName,
-            @Nonnull final RangeConstraint<?> constraints);
+    @Nonnull protected abstract String generateRangeCheckerImplementation(@Nonnull String checkerName,
+            @Nonnull RangeConstraint<?> constraints, Function<Class<?>, String> classImporter);
 
     private static String rangeCheckerName(final String member) {
         return "check" + member + "Range";
     }
 
-    String generateRangeChecker(@Nonnull final String member, @Nonnull final RangeConstraint<?> constraints) {
-        return generateRangeCheckerImplementation(rangeCheckerName(member), constraints);
+    String generateRangeChecker(@Nonnull final String member, @Nonnull final RangeConstraint<?> constraints,
+            final JavaFileTemplate template) {
+        return generateRangeCheckerImplementation(rangeCheckerName(member), constraints, template::importedName);
     }
 
     String generateRangeCheckerCall(@Nonnull final String member, @Nonnull final String valueReference) {
index 16cf52c02430afebe72257cfac4e6cb8531ffe36..a9cabecd83214bb3a0710b98ba0b4609e482afbd 100644 (file)
@@ -439,11 +439,11 @@ class BuilderTemplate extends BaseTemplate {
              «IF !(field.returnType instanceof GeneratedType) && restrictions !== null»
                     «IF restrictions.rangeConstraint.present»
                         «val rangeGenerator = AbstractRangeGenerator.forType(field.returnType)»
-                        «rangeGenerator.generateRangeChecker(field.name.toFirstUpper, restrictions.rangeConstraint.get)»
+                        «rangeGenerator.generateRangeChecker(field.name.toFirstUpper, restrictions.rangeConstraint.get, this
 
                     «ENDIF»
                     «IF restrictions.lengthConstraint.present»
-                    «LengthGenerator.generateLengthChecker(field.fieldName.toString, field.returnType, restrictions.lengthConstraint.get)»
+                    «LengthGenerator.generateLengthChecker(field.fieldName.toString, field.returnType, restrictions.lengthConstraint.get, this
 
                     «ENDIF»
             «ENDIF»
index 3810644051373fbb09c58af64019c691fd358359..f79213bb53f441d51cf0d0aa32eb7a449819d2f3 100644 (file)
@@ -126,10 +126,10 @@ class ClassTemplate extends BaseTemplate {
 
             «IF restrictions !== null»
                 «IF restrictions.lengthConstraint.present»
-                    «LengthGenerator.generateLengthChecker("_value", findProperty(genTO, "value").returnType, restrictions.lengthConstraint.get)»
+                    «LengthGenerator.generateLengthChecker("_value", findProperty(genTO, "value").returnType, restrictions.lengthConstraint.get, this
                 «ENDIF»
                 «IF restrictions.rangeConstraint.present»
-                    «rangeGenerator.generateRangeChecker("_value", restrictions.rangeConstraint.get)»
+                    «rangeGenerator.generateRangeChecker("_value", restrictions.rangeConstraint.get, this
                 «ENDIF»
             «ENDIF»
 
index 177f2e75c85ded99b1c1cfae3422033b71ee6fa5..240e3b623c8fa37125bd403dd913e7ecb15cdf8b 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.CodeHelpers;
 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -63,7 +64,8 @@ final class LengthGenerator {
         return new ArrayList<>(constraint.getAllowedRanges().asRanges()).toString();
     }
 
-    private static String generateArrayLengthChecker(final String member, final LengthConstraint constraint) {
+    private static String generateArrayLengthChecker(final String member, final LengthConstraint constraint,
+            final JavaFileTemplate template) {
         final StringBuilder sb = new StringBuilder();
         final Collection<String> expressions = createExpressions(constraint);
 
@@ -78,16 +80,15 @@ final class LengthGenerator {
                 sb.append("    }\n");
             }
 
-            sb.append("    throw new IllegalArgumentException(String.format(\"Invalid length: %s, expected: ")
-              .append(createLengthString(constraint)).append(".\", java.util.Arrays.toString(value)));\n");
+            sb.append("    ").append(template.importedName(CodeHelpers.class)).append(".throwInvalidLength(\"")
+            .append(createLengthString(constraint)).append("\", value);\n");
         }
 
-        sb.append("}\n");
-
-        return sb.toString();
+        return sb.append("}\n").toString();
     }
 
-    private static String generateStringLengthChecker(final String member, final LengthConstraint constraint) {
+    private static String generateStringLengthChecker(final String member, final LengthConstraint constraint,
+            final JavaFileTemplate template) {
         final StringBuilder sb = new StringBuilder();
         final Collection<String> expressions = createExpressions(constraint);
 
@@ -102,19 +103,18 @@ final class LengthGenerator {
                 sb.append("    }\n");
             }
 
-            sb.append("    throw new IllegalArgumentException(String.format(\"Invalid length: %s, expected: ")
-              .append(createLengthString(constraint)).append(".\", value));\n");
+            sb.append("    ").append(template.importedName(CodeHelpers.class)).append(".throwInvalidLength(\"")
+            .append(createLengthString(constraint)).append("\", value);\n");
         }
 
-        sb.append("}\n");
-
-        return sb.toString();
+        return sb.append("}\n").toString();
     }
 
     static String generateLengthChecker(final String member, final Type type,
-            final LengthConstraint constraint) {
+            final LengthConstraint constraint, final JavaFileTemplate template) {
         return TypeUtils.getBaseYangType(type).getName().indexOf('[') != -1
-                ? generateArrayLengthChecker(member, constraint) : generateStringLengthChecker(member, constraint);
+                ? generateArrayLengthChecker(member, constraint, template)
+                        : generateStringLengthChecker(member, constraint, template);
     }
 
     static String generateLengthCheckerCall(@Nullable final String member, @Nonnull final String valueReference) {
index fd96883182bcb2055a1f34a5adac1eaeafd1d0f7..068de8a91eee686a9e6eca242dc3d0edb35e291d 100644 (file)
@@ -12,6 +12,7 @@ import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.base.VerifyException;
+import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Pattern;
 import org.eclipse.jdt.annotation.NonNull;
@@ -118,4 +119,48 @@ public final class CodeHelpers {
             checkPattern(value, patterns[i], regexes[i]);
         }
     }
+
+    /**
+     * Throw an IllegalArgument exception describing a length violation.
+     *
+     * @param expected String describing expected lengths
+     * @param actual Actual observed object
+     * @throws IllegalArgumentException always
+     */
+    public static void throwInvalidLength(final String expected, final Object actual) {
+        throw new IllegalArgumentException("Invalid length: " + actual + ", expected: " + expected + ".");
+    }
+
+    /**
+     * Throw an IllegalArgument exception describing a length violation.
+     *
+     * @param expected String describing expected lengths
+     * @param actual Actual observed byte array
+     * @throws IllegalArgumentException always
+     */
+    public static void throwInvalidLength(final String expected, final byte[] actual) {
+        throwInvalidLength(expected, Arrays.toString(actual));
+    }
+
+    /**
+     * Throw an IllegalArgument exception describing a range violation.
+     *
+     * @param expected String describing expected ranges
+     * @param actual Actual observed object
+     * @throws IllegalArgumentException always
+     */
+    public static void throwInvalidRange(final String expected, final Object actual) {
+        throw new IllegalArgumentException("Invalid range: " + actual + ", expected: " + expected + ".");
+    }
+
+    /**
+     * Throw an IllegalArgument exception describing a range violation.
+     *
+     * @param expected Objects describing expected ranges
+     * @param actual Actual observed byte array
+     * @throws IllegalArgumentException always
+     */
+    public static void throwInvalidRange(final Object[] expected, final Object actual) {
+        throwInvalidRange(Arrays.toString(expected), actual);
+    }
 }