Fix a minor typo
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / AbstractJavaGeneratedType.java
index 607451b650161a17fec4a0c6b2989a6704f9071c..63ecbd0dd1a809f2e870bdb9a30586fed5e14906 100644 (file)
@@ -7,18 +7,17 @@
  */
 package org.opendaylight.mdsal.binding.java.api.generator;
 
-import static com.google.common.collect.ImmutableSet.toImmutableSet;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Streams;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import javax.annotation.concurrent.NotThreadSafe;
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.model.api.Enumeration;
@@ -31,16 +30,15 @@ import org.opendaylight.mdsal.binding.model.api.WildcardType;
 
 /**
  * Abstract class representing a generated type, either top-level or nested. It takes care of tracking references
- * to other Java types and resolving them as best as possible.
+ * to other Java types and resolving them as best as possible. This class is NOT thread-safe.
  *
  * @author Robert Varga
  */
 @NonNullByDefault
-@NotThreadSafe
 abstract class AbstractJavaGeneratedType {
     private final Map<JavaTypeName, @Nullable String> nameCache = new HashMap<>();
-    private final Map<String, NestedJavaGeneratedType> enclosedTypes;
-    private final Set<String> conflictingNames;
+    private final ImmutableMap<String, NestedJavaGeneratedType> enclosedTypes;
+    private final ImmutableSet<String> conflictingNames;
 
     private final JavaTypeName name;
 
@@ -51,20 +49,27 @@ abstract class AbstractJavaGeneratedType {
             b.put(type.getIdentifier().simpleName(), new NestedJavaGeneratedType(this, type));
         }
         enclosedTypes = b.build();
-        conflictingNames = genType instanceof Enumeration
-                ? ((Enumeration) genType).getValues().stream().map(Pair::getMappedName).collect(toImmutableSet())
-                        : ImmutableSet.of();
-    }
 
-    AbstractJavaGeneratedType(final JavaTypeName name, final GeneratedType genType) {
-        this.name = requireNonNull(name);
-        enclosedTypes = ImmutableMap.of();
+        final Set<String> cb = new HashSet<>();
+        if (genType instanceof Enumeration) {
+            ((Enumeration) genType).getValues().stream().map(Pair::getMappedName).forEach(cb::add);
+        }
+        // TODO: perhaps we can do something smarter to actually access the types
+        collectAccessibleTypes(cb, genType);
+
+        conflictingNames = ImmutableSet.copyOf(cb);
+    }
 
-        // This is a workaround for BuilderTemplate, which does not model itself correctly -- it should generate
-        // a GeneratedType for the Builder with a nested type for the implementation, which really should be
-        // a different template which gets generated as an inner type.
-        conflictingNames = Streams.concat(genType.getEnclosedTypes().stream(), genType.getEnumerations().stream())
-        .map(type -> type.getIdentifier().simpleName()).collect(toImmutableSet());
+    private void collectAccessibleTypes(final Set<String> set, final GeneratedType type) {
+        for (Type impl : type.getImplements()) {
+            if (impl instanceof GeneratedType) {
+                final GeneratedType genType = (GeneratedType) impl;
+                for (GeneratedType inner : Iterables.concat(genType.getEnclosedTypes(), genType.getEnumerations())) {
+                    set.add(inner.getIdentifier().simpleName());
+                }
+                collectAccessibleTypes(set, genType);
+            }
+        }
     }
 
     final JavaTypeName getName() {
@@ -75,29 +80,48 @@ abstract class AbstractJavaGeneratedType {
         return name.simpleName();
     }
 
-    final String getReferenceString(final Type type) {
-        if (!(type instanceof ParameterizedType)) {
-            return getReferenceString(type.getIdentifier());
+    private String annotateReference(final String ref, final Type type, final String annotation) {
+        if (type instanceof ParameterizedType) {
+            return getReferenceString(annotate(ref, annotation), type,
+                ((ParameterizedType) type).getActualTypeArguments());
         }
+        return "byte[]".equals(ref) ? "byte @" + annotation + "[]" : annotate(ref, annotation).toString();
+    }
 
-        final StringBuilder sb = new StringBuilder();
-        sb.append(getReferenceString(type.getIdentifier())).append('<');
-        final Type[] types = ((ParameterizedType) type).getActualTypeArguments();
-        if (types.length == 0) {
-            return sb.append("?>").toString();
+    final String getFullyQualifiedReference(final Type type, final String annotation) {
+        return annotateReference(type.getFullyQualifiedName(), type ,annotation);
+    }
+
+    final String getReferenceString(final Type type) {
+        final String ref = getReferenceString(type.getIdentifier());
+        return type instanceof ParameterizedType ? getReferenceString(new StringBuilder(ref), type,
+            ((ParameterizedType) type).getActualTypeArguments())
+                : ref;
+    }
+
+    final String getReferenceString(final Type type, final String annotation) {
+        // Package-private method, all callers who would be passing an empty array are bound to the more special
+        // case above, hence we know annotations.length >= 1
+        final String ref = getReferenceString(type.getIdentifier());
+        return annotateReference(ref, type, annotation);
+    }
+
+    private String getReferenceString(final StringBuilder sb, final Type type, final @NonNull Type[] arguments) {
+        if (arguments.length == 0) {
+            return sb.append("<?>").toString();
         }
 
-        for (int i = 0; i < types.length; i++) {
-            final Type t = types[i];
-            if (t instanceof WildcardType) {
+        sb.append('<');
+        for (int i = 0; i < arguments.length; i++) {
+            final Type arg = arguments[i];
+            if (arg instanceof WildcardType) {
                 sb.append("? extends ");
             }
-            sb.append(getReferenceString(t));
-            if (i != types.length - 1) {
+            sb.append(getReferenceString(arg));
+            if (i != arguments.length - 1) {
                 sb.append(", ");
             }
         }
-
         return sb.append('>').toString();
     }
 
@@ -155,4 +179,13 @@ abstract class AbstractJavaGeneratedType {
         // Try to anchor the top-level type and use a local reference
         return checkAndImportType(type.topLevelClass()) ? type.localName() : type.toString();
     }
+
+    private static StringBuilder annotate(final String ref, final String annotation) {
+        final StringBuilder sb = new StringBuilder();
+        final int dot = ref.lastIndexOf('.');
+        if (dot != -1) {
+            sb.append(ref, 0, dot + 1);
+        }
+        return sb.append('@').append(annotation).append(' ').append(ref, dot + 1, ref.length());
+    }
 }