final boolean isTypedef = this instanceof TypedefGenerator;
final QName arg = type.argument();
if (TypeDefinitions.BITS.equals(arg)) {
- return createBits(builderFactory, statement(), typeName(), currentModule(), extractTypeDefinition(),
- isTypedef);
+ return createBits(builderFactory, statement(), typeName(), currentModule(),
+ (BitsTypeDefinition) extractTypeDefinition(), isTypedef);
} else if (TypeDefinitions.ENUMERATION.equals(arg)) {
return createEnumeration(builderFactory, statement(), typeName(), currentModule(),
(EnumTypeDefinition) extractTypeDefinition());
private static @NonNull GeneratedTransferObject createBits(final TypeBuilderFactory builderFactory,
final EffectiveStatement<?, ?> definingStatement, final JavaTypeName typeName, final ModuleGenerator module,
- final TypeDefinition<?> typedef, final boolean isTypedef) {
+ final BitsTypeDefinition typedef, final boolean isTypedef) {
final GeneratedTOBuilder builder = builderFactory.newGeneratedTOBuilder(typeName);
builder.setTypedef(isTypedef);
- builder.addImplementsType(BindingTypes.TYPE_OBJECT);
+ builder.addImplementsType(BindingTypes.BITS_TYPE_OBJECT);
builder.setBaseType(typedef);
YangSourceDefinition.of(module.statement(), definingStatement).ifPresent(builder::setYangSourceDefinition);
- for (Bit bit : ((BitsTypeDefinition) typedef).getBits()) {
+ for (Bit bit : typedef.getBits()) {
final String name = bit.getName();
GeneratedPropertyBuilder genPropertyBuilder = builder.addProperty(BindingMapping.getPropertyName(name));
genPropertyBuilder.setReadOnly(true);
builder.addHashIdentity(genPropertyBuilder);
builder.addToStringProperty(genPropertyBuilder);
}
+ builder.addConstant(Types.immutableSetTypeFor(Types.STRING), TypeConstants.VALID_NAMES_NAME, typedef);
// builder.setSchemaPath(typedef.getPath());
builder.setModuleName(module.statement().argument().getLocalName());
} else if (TypeDefinitions.BITS.equals(subName)) {
final GeneratedTransferObject subBits = createBits(builderFactory, definingStatement,
typeName.createEnclosed(BindingMapping.getClassName(localName), "$"), module,
- subType.getTypeDefinition(), isTypedef);
+ (BitsTypeDefinition) subType.getTypeDefinition(), isTypedef);
builder.addEnclosingTransferObject(subBits);
generatedType = subBits;
} else if (TypeDefinitions.IDENTITYREF.equals(subName)) {
package org.opendaylight.mdsal.binding.generator.impl.reactor;
import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
import java.util.ArrayList;
import org.opendaylight.mdsal.binding.model.api.YangSourceDefinition;
import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
+import org.opendaylight.mdsal.binding.model.ri.TypeConstants;
+import org.opendaylight.mdsal.binding.model.ri.Types;
import org.opendaylight.mdsal.binding.runtime.api.TypedefRuntimeType;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
/**
addStringRegExAsConstant(builder, resolveRegExpressions(typedef));
addUnits(builder, typedef);
+ if (typedef instanceof BitsTypeDefinition bits) {
+ addValidBits(builder, bits, baseType);
+ }
+
makeSerializable(builder);
return builder.build();
}
+ private static void addValidBits(final GeneratedTOBuilder builder, final BitsTypeDefinition typedef,
+ final GeneratedTransferObject baseType) {
+ final var baseDef = verifyNotNull(baseBitsDefinition(baseType), "Could not find definition in %s", baseType);
+ final var myBits = typedef.getBits();
+ if (myBits.size() != baseDef.getBits().size()) {
+ builder.addConstant(Types.immutableSetTypeFor(Types.STRING), TypeConstants.VALID_NAMES_NAME, typedef);
+ }
+ }
+
+ private static BitsTypeDefinition baseBitsDefinition(final GeneratedTransferObject gto) {
+ var wlk = gto;
+ while (wlk != null) {
+ for (var constant : wlk.getConstantDefinitions()) {
+ if (TypeConstants.VALID_NAMES_NAME.equals(constant.getName())) {
+ return (BitsTypeDefinition) constant.getValue();
+ }
+ }
+
+ wlk = wlk.getSuperType();
+ }
+ return null;
+ }
+
@Override
TypedefRuntimeType createExternalRuntimeType(final Type type) {
verify(type instanceof GeneratedType, "Unexpected type %s", type);
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.BITS_TYPE_OBJECT;
import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.TYPE_OBJECT;
import java.util.List;
}
@Test
- public void typeObjectForBitsTypedefTest() {
+ public void bitsTypeObjectForBitsTypedefTest() {
final List<GeneratedType> generateTypes = DefaultBindingGenerator.generateFor(CONTEXT);
assertNotNull(generateTypes);
assertNotNull(typedefType.getImplements());
Type objectType = typedefType.getImplements().stream()
.filter(type -> type.getFullyQualifiedName()
- .equals("org.opendaylight.yangtools.yang.binding.TypeObject")).findAny().get();
- assertEquals(TYPE_OBJECT, objectType);
+ .equals("org.opendaylight.yangtools.yang.binding.BitsTypeObject")).findAny().get();
+ assertEquals(BITS_TYPE_OBJECT, objectType);
}
@Test
'''
final protected def getterMethodName(GeneratedProperty field) {
- return '''«BindingMapping.GETTER_PREFIX»«field.name.toFirstUpper»'''
+ return field.name.getterMethodName
+ }
+
+ final protected def getterMethodName(String propName) {
+ return '''«BindingMapping.GETTER_PREFIX»«propName.toFirstUpper»'''
}
/**
import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT64_TYPE
import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT8_TYPE
import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.SCALAR_TYPE_OBJECT
+import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.BITS_TYPE_OBJECT
import static org.opendaylight.mdsal.binding.model.ri.Types.STRING;
import static extension org.apache.commons.text.StringEscapeUtils.escapeJava
-import static extension org.opendaylight.mdsal.binding.model.ri.BindingTypes.isBitsType
import com.google.common.base.Preconditions
import com.google.common.collect.ImmutableList
+import com.google.common.collect.ImmutableSet
import com.google.common.collect.Lists
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import java.util.ArrayList
import org.opendaylight.mdsal.binding.model.ri.Types
import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
import org.opendaylight.yangtools.yang.common.Empty
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
/**
* Template for generating JAVA class.
*/
static val BOOLEAN = JavaTypeName.create(Boolean)
+ /**
+ * {@code com.google.common.collect.ImmutableSet} as a JavaTypeName.
+ */
+ static val IMMUTABLE_SET = JavaTypeName.create(ImmutableSet)
+
protected val List<GeneratedProperty> properties
protected val List<GeneratedProperty> finalProperties
protected val List<GeneratedProperty> parentProperties
«propertyMethods»
- «IF genTO.isBitsType»
- «generateGetValueForBitsTypeDef»
+ «IF isBitsTypeObject»
+ «validNamesAndValues»
«ENDIF»
«generateHashCode»
return false
}
+ def private isBitsTypeObject() {
+ var wlk = genTO
+ while (wlk !== null) {
+ for (impl : wlk.implements) {
+ if (BITS_TYPE_OBJECT.identifier.equals(impl.identifier)) {
+ return true
+ }
+ }
+ wlk = wlk.superType
+ }
+ return false
+ }
+
def private defaultProperties() '''
«FOR field : properties SEPARATOR "\n"»
«field.getterMethod»
}
'''
- /**
- * Template method which generates the method <code>getValue()</code> for typedef,
- * which base type is BitsDefinition.
- *
- * @return string with the <code>getValue()</code> method definition in JAVA format
- */
- def protected generateGetValueForBitsTypeDef() '''
+ def private validNamesAndValues() {
+ for (c : consts) {
+ if (TypeConstants.VALID_NAMES_NAME.equals(c.name)) {
+ return validNamesAndValues(c.value as BitsTypeDefinition)
+ }
+ }
+ return ""
+ }
- public boolean[] getValue() {
- return new boolean[]{
- «FOR property: genTO.properties SEPARATOR ','»
- «property.fieldName»
- «ENDFOR»
- };
+ def private validNamesAndValues(BitsTypeDefinition typedef) '''
+
+ @«OVERRIDE.importedName»
+ public «IMMUTABLE_SET.importedName»<«STRING.importedName»> validNames() {
+ return «TypeConstants.VALID_NAMES_NAME»;
+ }
+
+ @«OVERRIDE.importedName»
+ public boolean[] values() {
+ return new boolean[] {
+ «FOR bit : typedef.bits SEPARATOR ','»
+ «BindingMapping.getPropertyName(bit.name).getterMethodName»()
+ «ENDFOR»
+ };
}
'''
private static final String[] «Constants.MEMBER_REGEX_LIST» = { «
FOR v : cValue.values SEPARATOR ", "»"«v.escapeJava»"«ENDFOR» };
«ENDIF»
+ «ELSEIF TypeConstants.VALID_NAMES_NAME.equals(c.name)»
+ «val cValue = c.value as BitsTypeDefinition»
+ «val immutableSet = IMMUTABLE_SET.importedName»
+ protected static final «immutableSet»<«STRING.importedName»> «TypeConstants.VALID_NAMES_NAME» = «immutableSet».of(«
+ FOR bit : cValue.bits SEPARATOR ", "»"«bit.name»"«ENDFOR»);
«ELSE»
«emitConstant(c)»
«ENDIF»
CompilationTestUtils.assertContainsField(bitsExtClass, "_sfmof", boolean.class);
CompilationTestUtils.assertContainsField(bitsExtClass, "_sfapc", boolean.class);
CompilationTestUtils.assertContainsFieldWithValue(bitsExtClass, "serialVersionUID", Long.TYPE,
- -2922917845344851623L, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class,
+ 7934653360983102096L, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class,
boolean.class, boolean.class);
- assertEquals(8, bitsExtClass.getDeclaredFields().length);
+ assertEquals(9, bitsExtClass.getDeclaredFields().length);
CompilationTestUtils.assertContainsConstructor(bitsExtClass, bitsExtClass);
assertEquals(2, bitsExtClass.getConstructors().length);
Method defInst = CompilationTestUtils.assertContainsMethod(bitsExtClass, bitsExtClass, "getDefaultInstance",
String.class);
CompilationTestUtils.assertContainsDefaultMethods(bitsExtClass);
- assertEquals(12, bitsExtClass.getDeclaredMethods().length);
+ assertEquals(13, bitsExtClass.getDeclaredMethods().length);
Constructor<?> expectedConstructor = CompilationTestUtils.assertContainsConstructor(bitsExtClass, boolean.class,
boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class);
import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BitsTypeObject;
import org.opendaylight.yangtools.yang.binding.ChildOf;
import org.opendaylight.yangtools.yang.binding.ChoiceIn;
import org.opendaylight.yangtools.yang.binding.DataContainer;
public static final ConcreteType RPC_OUTPUT = typeForClass(RpcOutput.class);
public static final ConcreteType RPC_SERVICE = typeForClass(RpcService.class);
public static final ConcreteType SCALAR_TYPE_OBJECT = typeForClass(ScalarTypeObject.class);
+ public static final ConcreteType BITS_TYPE_OBJECT = typeForClass(BitsTypeObject.class);
public static final ConcreteType INSTANCE_IDENTIFIER = typeForClass(InstanceIdentifier.class);
public static final ConcreteType KEYED_INSTANCE_IDENTIFIER = typeForClass(KeyedInstanceIdentifier.class);
package org.opendaylight.mdsal.binding.model.ri;
import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.binding.BitsTypeObject;
import org.opendaylight.yangtools.yang.binding.ScalarTypeObject;
/**
* Contains constants used in relations with <code>Type</code>.
*/
public final class TypeConstants {
-
/**
- * Name or prefix (multiple patterns in builder class as composed with '_'
- * and upper case of the field name) of the class constant which holds the map
- * of regular expressions that need to be enforced on the string value.
- * The map is keyed by Pattern-compatible string and values are XSD-compatible
- * strings.
+ * Name or prefix (multiple patterns in builder class as composed with '_' and upper case of the field name) of the
+ * class constant which holds the map of regular expressions that need to be enforced on the string value. The map
+ * is keyed by Pattern-compatible string and values are XSD-compatible strings.
*/
public static final @NonNull String PATTERN_CONSTANT_NAME = "PATTERN_CONSTANTS";
public static final @NonNull String VALUE_PROP = "value";
/**
- * Creation of new instance is prohibited.
+ * Name of the constant holding the names of valid {@code bit}s in a {@link BitsTypeObject}. This constant is
+ * protected and made accessible via {@link BitsTypeObject#validNames()} and its type matches the return type
+ * exactly.
*/
+ public static final @NonNull String VALID_NAMES_NAME = "VALID_NAMES";
+
private TypeConstants() {
+ // Hidden on purpose
}
}
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.Serializable;
import java.util.Arrays;
private static final @NonNull ConcreteType PRIMITIVE_VOID = typeForClass(void.class);
private static final @NonNull ConcreteType SERIALIZABLE = typeForClass(Serializable.class);
private static final @NonNull ConcreteType SET_TYPE = typeForClass(Set.class);
+ private static final @NonNull ConcreteType IMMUTABLE_SET_TYPE = typeForClass(ImmutableSet.class);
private static final @NonNull ParameterizedType LIST_TYPE_WILDCARD = parameterizedTypeFor(LIST_TYPE);
private static final @NonNull ParameterizedType SET_TYPE_WILDCARD = parameterizedTypeFor(SET_TYPE);
return parameterizedTypeFor(SET_TYPE, valueType);
}
+ /**
+ * Returns an instance of {@link ParameterizedType} describing the typed {@link ImmutableSet}<V> with concrete
+ * type of value.
+ *
+ * @param valueType Value Type
+ * @return Description of generic type instance of ImmutableSet
+ */
+ public static @NonNull ParameterizedType immutableSetTypeFor(final Type valueType) {
+ return parameterizedTypeFor(IMMUTABLE_SET_TYPE, valueType);
+ }
+
/**
* Returns an instance of {@link ParameterizedType} describing the typed {@link Set}<?>.
*
module opendaylight-of-migration-test-model {
-
+ yang-version 1.1;
namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:of-migration-test-model";
prefix of-migration-test;
}
}
+ typedef derived-bit-flags {
+ type bit-flags;
+ }
+
+ typedef restricted-bit-flags {
+ type derived-bit-flags {
+ bit FLAG_ONE;
+ bit FLAG_THREE;
+ bit FLAG_FIVE;
+ }
+ }
+
typedef custom-enum {
type enumeration {
enum type1;
--- /dev/null
+/*
+ * Copyright (c) 2022 PANTHEON.tech, 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.yangtools.yang.binding;
+
+import com.google.common.collect.ImmutableSet;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Interface implemented by all {@link TypeObject}s generated for {@code type bits}.
+ */
+public interface BitsTypeObject extends TypeObject {
+ /**
+ * Return the set of strings which are valid {@code bit} names for this type. The iteration order of the returned
+ * set is required to match effective bit {@code position} assignment.
+ *
+ * @return The names of valid bits for this type.
+ */
+ @NonNull ImmutableSet<String> validNames();
+
+ /**
+ * Return the bit values. Returned array contains all bits from {@link #validNames()} in the interation order of
+ * that set. Note that the array is packed, e.g. unassigned positions are skipped over.
+ *
+ * @return Array of values.
+ */
+ boolean @NonNull [] values();
+}