*/
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;
/**
* 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;
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() {
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();
}
// 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());
+ }
}