import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
+ simpleName);
}
+ @Override
+ public String localName() {
+ return simpleName();
+ }
+
+ @Override
+ public List<String> localNameComponents() {
+ return ImmutableList.of(simpleName());
+ }
+
@Override
public JavaTypeName createSibling(final String simpleName) {
return new Primitive(simpleName);
}
+ @Override
+ public JavaTypeName topLevelClass() {
+ return this;
+ }
+
@Override
public String toString() {
return simpleName();
return Optional.empty();
}
+ @Override
+ public String localName() {
+ return simpleName();
+ }
+
+ @Override
+ public List<String> localNameComponents() {
+ final List<String> ret = new ArrayList<>();
+ ret.add(simpleName());
+ return ret;
+ }
+
+ @Override
+ public JavaTypeName topLevelClass() {
+ return this;
+ }
+
@Override
StringBuilder appendClass(final StringBuilder sb) {
return sb.append(packageName).append('.').append(simpleName());
public boolean canCreateEnclosed(final String simpleName) {
return super.canCreateEnclosed(simpleName) && immediatelyEnclosingClass.canCreateEnclosed(simpleName);
}
+
+ @Override
+ public String localName() {
+ return immediatelyEnclosingClass.localName() + "." + simpleName();
+ }
+
+ @Override
+ public List<String> localNameComponents() {
+ final List<String> ret = immediatelyEnclosingClass.localNameComponents();
+ ret.add(simpleName());
+ return ret;
+ }
+
+ @Override
+ public JavaTypeName topLevelClass() {
+ return immediatelyEnclosingClass.topLevelClass();
+ }
}
private static final long serialVersionUID = 1L;
public abstract String packageName();
/**
- * Return the enclosing class TypeName, if present.
+ * Return the enclosing class JavaTypeName, if present.
*
- * @return Enclosing class TypeName.
+ * @return Enclosing class JavaTypeName.
*/
public abstract Optional<JavaTypeName> immediatelyEnclosingClass();
+ /**
+ * Return the top-level class JavaTypeName which is containing this type, or self if this type is a top-level
+ * one.
+ *
+ * @return Top-level JavaTypeName
+ */
+ public abstract JavaTypeName topLevelClass();
+
+ /**
+ * Return the package-local name by which this type can be referenced by classes living in the same package.
+ *
+ * @return Local name.
+ */
+ public abstract String localName();
+
+ /**
+ * Return broken-down package-local name components.
+ *
+ * @return List of package-local components.
+ */
+ public abstract List<String> localNameComponents();
+
@Override
public final int hashCode() {
return Objects.hash(simpleName, packageName(), immediatelyEnclosingClass());
*/
package org.opendaylight.mdsal.binding.model.api;
+import static com.google.common.collect.ImmutableList.of;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Optional;
assertEquals("byte", byteName.simpleName());
assertEquals("byte", byteName.toString());
assertEquals(Optional.empty(), byteName.immediatelyEnclosingClass());
+ assertSame(byteName, byteName.topLevelClass());
+ assertEquals(of("byte"), byteName.localNameComponents());
+ assertEquals("byte", byteName.localName());
final JavaTypeName charName = byteName.createSibling("char");
assertEquals("", charName.packageName());
assertEquals("char", charName.simpleName());
assertEquals("char", charName.toString());
assertEquals(Optional.empty(), charName.immediatelyEnclosingClass());
+ assertSame(charName, charName.topLevelClass());
+ assertEquals(of("char"), charName.localNameComponents());
+ assertEquals("char", charName.localName());
final JavaTypeName threadName = JavaTypeName.create(Thread.class);
assertEquals("java.lang", threadName.packageName());
assertTrue(threadName.canCreateEnclosed("Foo"));
assertFalse(threadName.canCreateEnclosed("Thread"));
assertEquals(threadName, JavaTypeName.create("java.lang", "Thread"));
+ assertSame(threadName, threadName.topLevelClass());
+ assertEquals(of("Thread"), threadName.localNameComponents());
+ assertEquals("Thread", threadName.localName());
final JavaTypeName stringName = threadName.createSibling("String");
assertEquals("java.lang", stringName.packageName());
assertEquals("Foo", enclosedName.simpleName());
assertEquals("java.lang.Thread.Foo", enclosedName.toString());
assertEquals(Optional.of(threadName), enclosedName.immediatelyEnclosingClass());
+ assertSame(threadName, enclosedName.topLevelClass());
+ assertEquals(of("Thread", "Foo"), enclosedName.localNameComponents());
+ assertEquals("Thread.Foo", enclosedName.localName());
final JavaTypeName uehName = JavaTypeName.create(Thread.UncaughtExceptionHandler.class);
assertEquals("java.lang", uehName.packageName());
assertTrue(siblingName.canCreateEnclosed("UncaughtExceptionHandler"));
assertFalse(siblingName.canCreateEnclosed("Thread"));
assertFalse(siblingName.canCreateEnclosed("Foo"));
+
+ assertTrue(threadName.equals(JavaTypeName.create(Thread.class)));
+ assertTrue(threadName.equals(threadName));
+ assertFalse(threadName.equals(null));
+ assertFalse(threadName.equals("foo"));
}
@Test(expected = IllegalArgumentException.class)
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
-import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
-import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
private GeneratedTOBuilder createUnionBuilder(final GeneratedTOBuilder genTOBuilder,
final GeneratedTypeBuilder typeBuilder) {
- final StringBuilder sb = new StringBuilder();
-
// Append enclosing path hierarchy without dots
- // TODO: JavaTypeName could be giving us a Stream<String> or similar, but there is no sense in generalizing
- // unless there is another caller.
- Optional<JavaTypeName> outerClass = genTOBuilder.getIdentifier().immediatelyEnclosingClass();
- if (outerClass.isPresent()) {
- final Deque<String> enclosingPath = new ArrayDeque<>();
- do {
- final JavaTypeName outerName = outerClass.get();
- enclosingPath.push(outerName.simpleName());
- outerClass = outerName.immediatelyEnclosingClass();
- } while (outerClass.isPresent());
-
- while (!enclosingPath.isEmpty()) {
- sb.append(enclosingPath.pop());
- }
- }
-
- sb.append(genTOBuilder.getName()).append("Builder");
+ final StringBuilder sb = new StringBuilder();
+ genTOBuilder.getIdentifier().localNameComponents().forEach(sb::append);
final GeneratedTOBuilder unionBuilder = typeProvider.newGeneratedTOBuilder(
- JavaTypeName.create(typeBuilder.getPackageName(), sb.toString()));
+ JavaTypeName.create(typeBuilder.getPackageName(), sb.append("Builder").toString()));
unionBuilder.setIsUnionBuilder(true);
return unionBuilder;
}
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.java.api.generator;
+
+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.Map;
+import java.util.Set;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
+import org.opendaylight.mdsal.binding.model.api.Type;
+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.
+ *
+ * @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 JavaTypeName name;
+
+ AbstractJavaGeneratedType(final GeneratedType genType) {
+ name = genType.getIdentifier();
+ final Builder<String, NestedJavaGeneratedType> b = ImmutableMap.builder();
+ for (GeneratedType type : Iterables.concat(genType.getEnclosedTypes(), genType.getEnumerations())) {
+ b.put(type.getIdentifier().simpleName(), new NestedJavaGeneratedType(this, type));
+ }
+ enclosedTypes = b.build();
+ conflictingNames = ImmutableSet.of();
+ }
+
+ AbstractJavaGeneratedType(final JavaTypeName name, final GeneratedType genType) {
+ this.name = requireNonNull(name);
+ enclosedTypes = ImmutableMap.of();
+
+ // 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(ImmutableSet.toImmutableSet());
+ }
+
+ final JavaTypeName getName() {
+ return name;
+ }
+
+ final String getSimpleName() {
+ return name.simpleName();
+ }
+
+ final String getReferenceString(final Type type) {
+ if (!(type instanceof ParameterizedType)) {
+ return getReferenceString(type.getIdentifier());
+ }
+
+ 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();
+ }
+
+ for (int i = 0; i < types.length; i++) {
+ final Type t = types[i];
+ if (t instanceof WildcardType) {
+ sb.append("? extends ");
+ }
+ sb.append(getReferenceString(t));
+ if (i != types.length - 1) {
+ sb.append(", ");
+ }
+ }
+
+ return sb.append('>').toString();
+ }
+
+ final String getReferenceString(final JavaTypeName type) {
+ if (type.packageName().isEmpty()) {
+ // This is a packageless primitive type, refer to it directly
+ return type.simpleName();
+ }
+
+ // Self-reference, return simple name
+ if (name.equals(type)) {
+ return name.simpleName();
+ }
+
+ // Fast path: we have already resolved how to refer to this type
+ final String existing = nameCache.get(type);
+ if (existing != null) {
+ return existing;
+ }
+
+ // Fork based on whether the class is in this compilation unit, package or neither
+ final String result;
+ if (name.topLevelClass().equals(type.topLevelClass())) {
+ result = localTypeName(type);
+ } else if (name.packageName().equals(type.packageName())) {
+ result = packageTypeName(type);
+ } else {
+ result = foreignTypeName(type);
+ }
+
+ nameCache.put(type, result);
+ return result;
+ }
+
+ final NestedJavaGeneratedType getEnclosedType(final JavaTypeName type) {
+ return requireNonNull(enclosedTypes.get(type.simpleName()));
+ }
+
+ final boolean checkAndImportType(final JavaTypeName type) {
+ // We can import the type only if it does not conflict with us or our immediately-enclosed types
+ final String simpleName = type.simpleName();
+ return !simpleName.equals(getSimpleName()) && !enclosedTypes.containsKey(simpleName)
+ && !conflictingNames.contains(simpleName) && importCheckedType(type);
+ }
+
+ abstract boolean importCheckedType(JavaTypeName type);
+
+ abstract String localTypeName(JavaTypeName type);
+
+ private String foreignTypeName(final JavaTypeName type) {
+ return checkAndImportType(type) ? type.simpleName() : type.toString();
+ }
+
+ private String packageTypeName(final JavaTypeName type) {
+ // Try to anchor the top-level type and use a local reference
+ return checkAndImportType(type.topLevelClass()) ? type.localName() : type.toString();
+ }
+}
super(type)
}
+ new(AbstractJavaGeneratedType javaType, GeneratedType type) {
+ super(javaType, type)
+ }
+
final public def generate() {
val _body = body()
'''
* @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>
*/
new(GeneratedType genType) {
- super(genType)
+ super(new TopLevelJavaGeneratedType(builderName(genType), genType), genType)
this.properties = propertiesFromMethods(createMethods)
addImport(Builder)
}
+ def static builderName(GeneratedType genType) {
+ val name = genType.identifier
+ name.createSibling(name.simpleName + "Builder")
+ }
+
/**
* Returns set of method signature instances which contains all the methods of the <code>genType</code>
* and all the methods of the implemented interfaces.
package org.opendaylight.mdsal.binding.java.api.generator
import static java.util.Objects.requireNonNull
-import static extension org.apache.commons.text.StringEscapeUtils.escapeJava;
+import static extension org.apache.commons.text.StringEscapeUtils.escapeJava
import com.google.common.collect.ImmutableList
import com.google.common.collect.Lists
import org.opendaylight.mdsal.binding.model.api.Enumeration
import org.opendaylight.mdsal.binding.model.api.GeneratedProperty
import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject
-import org.opendaylight.mdsal.binding.model.api.GeneratedType
import org.opendaylight.mdsal.binding.model.api.Restrictions
import org.opendaylight.mdsal.binding.model.api.Type
import org.opendaylight.mdsal.binding.model.util.TypeConstants
*/
protected val List<Constant> consts
- /**
- * List of generated types which are enclosed inside <code>genType</code>
- */
- protected val List<GeneratedType> enclosedGeneratedTypes;
-
protected val GeneratedTransferObject genTO;
private val AbstractRangeGenerator<?> rangeGenerator
* @param genType generated transfer object which will be transformed to JAVA class source code
*/
new(GeneratedTransferObject genType) {
- super(genType)
+ this(new TopLevelJavaGeneratedType(genType), genType)
+ }
+
+ /**
+ * Creates instance of this class with concrete <code>genType</code>.
+ *
+ * @param genType generated transfer object which will be transformed to JAVA class source code
+ */
+ new(AbstractJavaGeneratedType javaType, GeneratedTransferObject genType) {
+ super(javaType, genType)
this.genTO = genType
this.properties = genType.properties
this.finalProperties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)
this.allProperties = sorted
this.enums = genType.enumerations
this.consts = genType.constantDefinitions
- this.enclosedGeneratedTypes = genType.enclosedTypes
if (restrictions !== null && restrictions.rangeConstraint.present) {
rangeGenerator = requireNonNull(AbstractRangeGenerator.forType(findProperty(genType, "value").returnType))
* @return string with the source code for inner classes in JAVA format
*/
def protected innerClassesDeclarations() '''
- «IF !enclosedGeneratedTypes.empty»
- «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»
+ «IF !type.enclosedTypes.empty»
+ «FOR innerClass : type.enclosedTypes SEPARATOR "\n"»
«IF (innerClass instanceof GeneratedTransferObject)»
- «val classTemplate = new ClassTemplate(innerClass)»
- «classTemplate.generateAsInnerClass»
-
+ «new ClassTemplate(javaType.getEnclosedType(innerClass.identifier), innerClass).generateAsInnerClass»
«ENDIF»
«ENDFOR»
«ENDIF»
def protected enumDeclarations() '''
«IF !enums.empty»
«FOR e : enums SEPARATOR "\n"»
- «val enumTemplate = new EnumTemplate(e)»
- «enumTemplate.generateAsInnerClass»
+ «new EnumTemplate(javaType.getEnclosedType(e.identifier), e).generateAsInnerClass»
«ENDFOR»
«ENDIF»
'''
*/
val Enumeration enums
+ /**
+ * Constructs instance of this class with concrete <code>enums</code>.
+ *
+ * @param enums enumeration which will be transformed to JAVA source code
+ */
+ new(AbstractJavaGeneratedType javaType, Enumeration enums) {
+ super(javaType, enums as GeneratedType)
+ this.enums = enums
+ }
+
/**
* Constructs instance of this class with concrete <code>enums</code>.
*
«IF !enclosedGeneratedTypes.empty»
«FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»
«IF (innerClass instanceof GeneratedTransferObject)»
+ «val innerJavaType = javaType.getEnclosedType(innerClass.identifier)»
«IF innerClass.unionType»
- «val unionTemplate = new UnionTemplate(innerClass)»
+ «val unionTemplate = new UnionTemplate(innerJavaType, innerClass)»
«unionTemplate.generateAsInnerClass»
- «addImports(unionTemplate)»
«ELSE»
- «val classTemplate = new ClassTemplate(innerClass)»
+ «val classTemplate = new ClassTemplate(innerJavaType, innerClass)»
«classTemplate.generateAsInnerClass»
- «addImports(classTemplate)»
«ENDIF»
«ENDIF»
def private generateEnums() '''
«IF !enums.empty»
«FOR e : enums SEPARATOR "\n"»
- «val enumTemplate = new EnumTemplate(e)»
+ «val enumTemplate = new EnumTemplate(javaType.getEnclosedType(e.identifier), e)»
«enumTemplate.generateAsInnerClass»
«ENDFOR»
«ENDIF»
*/
package org.opendaylight.mdsal.binding.java.api.generator;
+import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
* Base Java file template. Contains a non-null type and imports which the generated code refers to.
*/
class JavaFileTemplate {
- // Hidden to well-define operations
- private final Map<String, JavaTypeName> importMap = new HashMap<>();
-
- protected final GeneratedType type;
+ private final AbstractJavaGeneratedType javaType;
+ private final GeneratedType type;
JavaFileTemplate(final GeneratedType type) {
+ this(new TopLevelJavaGeneratedType(type), type);
+ }
+
+ JavaFileTemplate(final AbstractJavaGeneratedType javaType, final GeneratedType type) {
+ this.javaType = requireNonNull(javaType);
this.type = requireNonNull(type);
}
+ final AbstractJavaGeneratedType javaType() {
+ return javaType;
+ }
+
+ final GeneratedType type() {
+ return type;
+ }
+
final GeneratedProperty findProperty(final GeneratedTransferObject gto, final String name) {
final Optional<GeneratedProperty> optProp = gto.getProperties().stream()
.filter(prop -> prop.getName().equals(name)).findFirst();
}
final String generateImportBlock() {
- return importMap.entrySet().stream()
- .filter(e -> isDefaultVisible(e.getValue()))
- .sorted((e1, e2) -> {
- return e1.getValue().toString().compareTo(e2.getValue().toString());
- })
- .map(e -> "import " + e.getValue() + ";\n")
+ verify(javaType instanceof TopLevelJavaGeneratedType);
+ return ((TopLevelJavaGeneratedType) javaType).imports().map(name -> "import " + name + ";\n")
.collect(Collectors.joining());
}
final String importedName(final Type intype) {
- GeneratorUtil.putTypeIntoImports(type, intype, importMap);
- return GeneratorUtil.getExplicitType(type, intype, importMap);
+ return javaType.getReferenceString(intype);
}
final String importedName(final Class<?> cls) {
}
final void addImport(final Class<?> cls) {
- final JavaTypeName name = JavaTypeName.create(cls);
- importMap.put(name.simpleName(), name);
- }
-
- final void addImports(final JavaFileTemplate from) {
- importMap.putAll(from.importMap);
+ javaType.getReferenceString(JavaTypeName.create(cls));
}
// Exposed for BuilderTemplate
final Optional<JavaTypeName> optEnc = name.immediatelyEnclosingClass();
return optEnc.isPresent() && type.getIdentifier().equals(optEnc.get());
}
-
- private boolean isDefaultVisible(final JavaTypeName name) {
- return !hasSamePackage(name) || !isLocalInnerClass(name);
- }
-
- /**
- * Checks if packages of generated type and imported type is the same
- *
- * @param importedTypePackageName the package name of imported type
- * @return true if the packages are the same false otherwise
- */
- private boolean hasSamePackage(final JavaTypeName name) {
- return type.getPackageName().equals(name.packageName());
- }
}
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.java.api.generator;
+
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+
+/**
+ * A type which is nested inside some other type. It defers import decisions to its enclosing type, eventually arriving
+ * at a {@link TopLevelJavaGeneratedType}.
+ *
+ * @author Robert Varga
+ */
+@NonNullByDefault
+final class NestedJavaGeneratedType extends AbstractJavaGeneratedType {
+ private final AbstractJavaGeneratedType enclosingType;
+
+ NestedJavaGeneratedType(final AbstractJavaGeneratedType enclosingType, final GeneratedType genType) {
+ super(genType);
+ this.enclosingType = requireNonNull(enclosingType);
+ }
+
+ @Override
+ boolean importCheckedType(final JavaTypeName type) {
+ // Defer to enclosing type, which needs to re-run its checks
+ return enclosingType.checkAndImportType(type);
+ }
+
+ @Override
+ String localTypeName(final JavaTypeName type) {
+ // Check if the type is a reference to our immediately-enclosing type
+ if (enclosingType.getName().equals(type)) {
+ return enclosingType.getSimpleName();
+ }
+
+ final @Nullable List<String> descendant = findDescandantPath(type);
+ if (descendant == null) {
+ // The type is not present in our hierarchy, defer to our immediately-enclosing type, which may be able
+ // to find the target.
+ return enclosingType.localTypeName(type);
+ }
+
+ // Target type is a declared as a enclosed type of us and we have the path where it lurks.
+ final Iterator<String> it = descendant.iterator();
+ final StringBuilder sb = new StringBuilder().append(it.next());
+ while (it.hasNext()) {
+ sb.append('.').append(it.next());
+ }
+ return sb.toString();
+ }
+
+ private @Nullable List<String> findDescandantPath(final JavaTypeName type) {
+ Optional<JavaTypeName> optEnclosing = type.immediatelyEnclosingClass();
+ verify(optEnclosing.isPresent());
+
+ final Deque<String> queue = new ArrayDeque<>();
+ queue.addFirst(type.simpleName());
+ while (optEnclosing.isPresent()) {
+ final JavaTypeName enclosing = optEnclosing.get();
+ if (enclosing.equals(getName())) {
+ return ImmutableList.copyOf(queue);
+ }
+
+ queue.addFirst(enclosing.simpleName());
+ optEnclosing = enclosing.immediatelyEnclosingClass();
+ }
+
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.java.api.generator;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.stream.Stream;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+
+/**
+ * This class tracks types generated into a single Java compilation unit (file) and manages imports of that compilation
+ * unit. Since we are generating only public classes, this is synonymous to a top-level Java type.
+ */
+@NonNullByDefault
+final class TopLevelJavaGeneratedType extends AbstractJavaGeneratedType {
+ private final BiMap<JavaTypeName, String> importedTypes = HashBiMap.create();
+
+ TopLevelJavaGeneratedType(final GeneratedType genType) {
+ super(genType);
+ }
+
+ TopLevelJavaGeneratedType(final JavaTypeName name, final GeneratedType genType) {
+ super(name, genType);
+ }
+
+ @Override
+ String localTypeName(@NonNull final JavaTypeName type) {
+ // Locally-anchored type, this is simple: just strip the first local name component and concat the others
+ final Iterator<String> it = type.localNameComponents().iterator();
+ it.next();
+
+ final StringBuilder sb = new StringBuilder().append(it.next());
+ while (it.hasNext()) {
+ sb.append('.').append(it.next());
+ }
+ return sb.toString();
+ }
+
+ @Override
+ boolean importCheckedType(final JavaTypeName type) {
+ if (importedTypes.containsKey(type)) {
+ return true;
+ }
+ final String simpleName = type.simpleName();
+ if (importedTypes.containsValue(simpleName)) {
+ return false;
+ }
+ importedTypes.put(type, simpleName);
+ return true;
+ }
+
+ Stream<JavaTypeName> imports() {
+ return importedTypes.entrySet().stream().filter(this::needsExplicitImport).map(Entry::getKey)
+ .sorted(Comparator.comparing(JavaTypeName::toString));
+ }
+
+ private boolean needsExplicitImport(final Entry<JavaTypeName, String> entry) {
+ final JavaTypeName name = entry.getKey();
+
+ if (!getName().packageName().equals(name.packageName())) {
+ // Different package: need to import it
+ return true;
+ }
+
+ if (!name.immediatelyEnclosingClass().isPresent()) {
+ // This a top-level class import, we can skip it
+ return false;
+ }
+
+ // This is a nested class, we need to spell it out if the import entry points to the simple name
+ return entry.getValue().equals(name.simpleName());
+ }
+}
*/
class UnionTemplate extends ClassTemplate {
+ /**
+ * Creates instance of this class with concrete <code>genType</code>.
+ *
+ * @param genType generated transfer object which will be transformed to JAVA class source code
+ */
+ new(NestedJavaGeneratedType javaType, GeneratedTransferObject genType) {
+ super(javaType, genType)
+ if (isBaseEncodingImportRequired) {
+ addImport(BaseEncoding)
+ }
+ }
+
/**
* Creates instance of this class with concrete <code>genType</code>.
*
final GeneratedType genType = mockGenType("get" + TEST);
assertEquals("@Override\n" +
- "public java.lang.String toString() {\n" +
+ "public String toString() {\n" +
" final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
" CodeHelpers.appendValue(helper, \"_test\", _test);\n" +
" return helper.toString();\n" +
@Test
public void builderTemplateGenerateToStringWithoutAnyPropertyTest() throws Exception {
assertEquals("@Override\n" +
- "public java.lang.String toString() {\n" +
+ "public String toString() {\n" +
" final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
" return helper.toString();\n" +
"}\n", genToString(mockGenType(TEST)).toString());
@Test
public void builderTemplateGenerateToStringWithMorePropertiesTest() throws Exception {
assertEquals("@Override\n" +
- "public java.lang.String toString() {\n" +
+ "public String toString() {\n" +
" final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
" CodeHelpers.appendValue(helper, \"_test1\", _test1);\n" +
" CodeHelpers.appendValue(helper, \"_test2\", _test2);\n" +
@Test
public void builderTemplateGenerateToStringWithoutPropertyWithAugmentTest() throws Exception {
assertEquals("@Override\n" +
- "public java.lang.String toString() {\n" +
+ "public String toString() {\n" +
" final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
" CodeHelpers.appendValue(helper, \"augmentation\", augmentation.values());\n" +
" return helper.toString();\n" +
@Test
public void builderTemplateGenerateToStringWithPropertyWithAugmentTest() throws Exception {
assertEquals("@Override\n" +
- "public java.lang.String toString() {\n" +
+ "public String toString() {\n" +
" final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
" CodeHelpers.appendValue(helper, \"_test\", _test);\n" +
" CodeHelpers.appendValue(helper, \"augmentation\", augmentation.values());\n" +
@Test
public void builderTemplateGenerateToStringWithMorePropertiesWithAugmentTest() throws Exception {
assertEquals("@Override\n" +
- "public java.lang.String toString() {\n" +
+ "public String toString() {\n" +
" final MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(\"test\");\n" +
" CodeHelpers.appendValue(helper, \"_test1\", _test1);\n" +
" CodeHelpers.appendValue(helper, \"_test2\", _test2);\n" +
import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedPropertyBuilder;
import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
import org.opendaylight.mdsal.binding.model.util.Types;
final String outputStr = clsGen.generate(genTO);
assertNotNull(outputStr);
- assertTrue(outputStr.contains(
- "public CompositeKeyListKey(java.lang.Byte _key1, java.lang.String _key2)"));
+ assertTrue(outputStr.contains("public CompositeKeyListKey(Byte _key1, String _key2)"));
assertEquals(2, propertyCount);
genTOsCount++;
CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
}
+ @Test
+ public void testMdsal327() throws Exception {
+ final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal327");
+ final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal327");
+ generateTestSources("/compilation/mdsal327", sourcesOutputDir);
+ CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
+ CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
+ }
+
@Test
public void classNamesColisionTest() throws Exception {
final File sourcesOutputDir = CompilationTestUtils.generatorOutput("class-name-collision");
--- /dev/null
+module test-imports {
+ yang-version 1;
+ namespace "urn:test:imports";
+ prefix "tet";
+
+ revision "2018-04-12" {
+ }
+
+ container map {
+ list class {
+ key "name";
+ leaf name {
+ type string;
+ }
+
+ leaf string {
+ type union {
+ type string;
+ type enumeration {
+ enum string;
+ enum int8;
+ }
+ }
+ }
+ }
+ }
+}