package org.opendaylight.mdsal.binding.model.api;
/**
- * Generated Property extends interface {@link MethodSignature} interface. <br>
- * The Generated Property interface is designed to store information of fields
- * (or members) declared in Java Transfer Objects (or any java classes) and
- * their access counterparts (getters and setters).
+ * Generated Property extends {@link TypeMember} interface with additional information about fields (and other members)
+ * declared in Java Transfer Objects (or any java classes) and their access counterparts (getters and setters).
*
- * @see MethodSignature
+ * @see TypeMember
*/
+// FIXME: 7.0.0: this interface (and others) need to be refactored:
+// - getValue() is pretty much unused and its semantics are undefined
+// - isReadOnly() is not related to getValue() and is not used together
+// - nullifyEmpty() is applicable only to collection types and implies non-read-only and without value
+// - this is misused by Builder spec :(
public interface GeneratedProperty extends TypeMember {
String getValue();
/**
- * Returns <code>true</code> if the property is declared as read-only. <br>
- * If the property has flag <code>isReadOnly == true</code> the property
- * SHOULD be generated as getter only.
+ * Returns <code>true</code> if the property is declared as read-only. If this {@code true} the property should be
+ * generated with only a getter.
*
- * @return <code>true</code> if the property is declared as read-only.
+ * @return {@code true<} if the property is declared as read-only.
*/
boolean isReadOnly();
+
+ /**
+ * Returns indication whether the value should be squashed from empty collection to a null. This property is valid
+ * only if {@link #getReturnType()} results in a well-known collection type: List or Map.
+ *
+ * @return True if empty collections should be turned to nulls
+ */
+ boolean nullifyEmpty();
}
*/
List<Parameter> getParameters();
+ /**
+ * Return the mechanics associated with this method.
+ *
+ * @return Associated mechanics
+ */
+ ValueMechanics getMechanics();
+
/**
* The Parameter interface is designed to hold the information of method
* Parameter(s). The parameter is defined by his Name which MUST be unique
*/
Type getType();
}
+
+ /**
+ * Method return type mechanics. This is a bit of an escape hatch for various behaviors which are supported by
+ * code generation.
+ */
+ enum ValueMechanics {
+ /**
+ * Usual mechanics, nothing special is going on.
+ */
+ NORMAL,
+ /**
+ * Mechanics signaling that the method should not be returning empty collections, but rather squash tham
+ * to null.
+ */
+ NULLIFY_EMPTY,
+ }
}
*/
package org.opendaylight.mdsal.binding.model.api.type.builder;
+import com.google.common.annotations.Beta;
import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
import org.opendaylight.mdsal.binding.model.api.Type;
*/
GeneratedPropertyBuilder setReadOnly(boolean isReadOnly);
+ @Beta
+ GeneratedPropertyBuilder setNullifyEmpty(boolean flag);
+
/**
* Returns <code>new</code> <i>immutable</i> instance of Generated Property. <br>
* The <code>definingType</code> param cannot be <code>null</code>. The
*/
package org.opendaylight.mdsal.binding.model.api.type.builder;
+import com.google.common.annotations.Beta;
import org.opendaylight.mdsal.binding.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics;
import org.opendaylight.mdsal.binding.model.api.Type;
/**
*/
MethodSignatureBuilder setDefault(boolean isDefault);
+ @Beta
+ MethodSignatureBuilder setMechanics(ValueMechanics mechanics);
+
/**
* Adds Parameter into the List of method parameters. Neither the Name or Type of parameter can be {@code null}.
*
import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics;
import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
import org.opendaylight.mdsal.binding.model.api.Restrictions;
import org.opendaylight.mdsal.binding.model.api.Type;
listType = listTypeFor(genType);
}
- constructGetter(parent, listType, node);
+ constructGetter(parent, listType, node).setMechanics(ValueMechanics.NULLIFY_EMPTY);
constructNonnull(parent, listType, node);
actionsToGenType(context, genType, node, keyTypeBuilder, inGrouping);
implements GeneratedPropertyBuilder {
private String value;
private boolean readOnly;
+ private boolean nullifyEmpty;
public GeneratedPropertyBuilderImpl(final String name) {
super(name);
this.readOnly = true;
+ this.nullifyEmpty = false;
}
@Override
return this;
}
+ @Override
+ public GeneratedPropertyBuilderImpl setNullifyEmpty(final boolean flag) {
+ this.nullifyEmpty = flag;
+ return this;
+ }
+
@Override
protected GeneratedPropertyBuilderImpl thisInstance() {
return this;
public GeneratedProperty toInstance(final Type definingType) {
final List<AnnotationType> annotations = toAnnotationTypes();
return new GeneratedPropertyImpl(definingType, getName(), annotations, getComment(), getAccessModifier(),
- getReturnType(), isFinal(), isStatic(), this.readOnly, this.value);
+ getReturnType(), isFinal(), isStatic(), this.readOnly, this.nullifyEmpty, this.value);
}
@Override
final class GeneratedPropertyImpl extends AbstractTypeMember implements GeneratedProperty {
private final String value;
private final boolean readOnly;
+ private final boolean nullifyEmpty;
GeneratedPropertyImpl(final Type definingType, final String name, final List<AnnotationType> annotations,
final String comment, final AccessModifier accessModifier, final Type returnType, final boolean isFinal,
- final boolean isStatic, final boolean isReadOnly, final String value) {
+ final boolean isStatic, final boolean isReadOnly, final boolean nullifyEmpty, final String value) {
super(definingType, name, annotations, comment, accessModifier, returnType, isFinal, isStatic);
this.value = value;
this.readOnly = isReadOnly;
+ this.nullifyEmpty = nullifyEmpty;
}
@Override
return this.readOnly;
}
+ @Override
+ public boolean nullifyEmpty() {
+ return this.nullifyEmpty;
+ }
+
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
*/
package org.opendaylight.mdsal.binding.model.util.generated.type.builder;
+import static java.util.Objects.requireNonNull;
+
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.opendaylight.mdsal.binding.model.api.AnnotationType;
import org.opendaylight.mdsal.binding.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics;
import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
import org.opendaylight.yangtools.util.LazyCollections;
private List<MethodSignature.Parameter> parameters = Collections.emptyList();
private List<MethodSignature.Parameter> unmodifiableParams = Collections.emptyList();
+ private ValueMechanics mechanics = ValueMechanics.NORMAL;
private boolean isAbstract;
private boolean isDefault;
return this;
}
+
+ @Override
+ public MethodSignatureBuilder setMechanics(final ValueMechanics newMechanics) {
+ this.mechanics = requireNonNull(newMechanics);
+ return this;
+ }
+
@Override
public MethodSignatureBuilder addParameter(final Type type, final String name) {
this.parameters = LazyCollections.lazyAdd(this.parameters, new MethodParameterImpl(name, type));
public MethodSignature toInstance(final Type definingType) {
final List<AnnotationType> annotations = toAnnotationTypes();
return new MethodSignatureImpl(definingType, getName(), annotations, getComment(), getAccessModifier(),
- getReturnType(), this.unmodifiableParams, isFinal(), this.isAbstract, isStatic(), isDefault);
+ getReturnType(), this.unmodifiableParams, isFinal(), this.isAbstract, isStatic(), isDefault, mechanics);
}
@Override
*/
package org.opendaylight.mdsal.binding.model.util.generated.type.builder;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.VisibleForTesting;
import java.util.List;
import java.util.Objects;
import org.opendaylight.mdsal.binding.model.api.AccessModifier;
class MethodSignatureImpl extends AbstractTypeMember implements MethodSignature {
private final List<Parameter> params;
+ private final ValueMechanics mechanics;
private final boolean isAbstract;
private final boolean isDefault;
+ @VisibleForTesting
MethodSignatureImpl(final Type definingType, final String name, final List<AnnotationType> annotations,
final String comment, final AccessModifier accessModifier, final Type returnType,
final List<Parameter> params, final boolean isFinal, final boolean isAbstract, final boolean isStatic) {
this(definingType, name, annotations, comment, accessModifier, returnType, params, isFinal, isAbstract,
- isStatic, false);
+ isStatic, false, ValueMechanics.NORMAL);
}
MethodSignatureImpl(final Type definingType, final String name, final List<AnnotationType> annotations,
final String comment, final AccessModifier accessModifier, final Type returnType,
final List<Parameter> params, final boolean isFinal, final boolean isAbstract, final boolean isStatic,
- final boolean isDefault) {
+ final boolean isDefault, final ValueMechanics mechanics) {
super(definingType, name, annotations, comment, accessModifier, returnType, isFinal, isStatic);
this.params = params;
this.isAbstract = isAbstract;
this.isDefault = isDefault;
+ this.mechanics = requireNonNull(mechanics);
}
@Override
return this.params;
}
+ @Override
+ public ValueMechanics getMechanics() {
+ return mechanics;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
@Test
public void testMethodsForGeneratedPropertyImpl() {
final GeneratedPropertyImpl propertyImpl = new GeneratedPropertyImpl(null, "Test", null, "test property",
- AccessModifier.PRIVATE, null, true, true, true, "test value");
+ AccessModifier.PRIVATE, null, true, true, true, true, "test value");
assertEquals("test value", propertyImpl.getValue());
assertTrue(propertyImpl.isReadOnly());
return generateDeprecatedAnnotation(found)
}
- def protected final CharSequence generateCopyNonKeys(Collection<GeneratedProperty> props) '''
- «FOR field : props»
- this.«field.fieldName» = base.«field.getterMethodName»();
- «ENDFOR»
- '''
-
def protected abstract CharSequence generateCopyKeys(List<GeneratedProperty> keyProps)
+ def protected abstract CharSequence generateCopyNonKeys(Collection<GeneratedProperty> props)
+
def protected abstract CharSequence generateCopyAugmentation(Type implType)
def protected abstract CharSequence generateDeprecatedAnnotation(AnnotationType ann)
import org.opendaylight.mdsal.binding.model.api.MethodSignature;
import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
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.api.type.builder.GeneratedTypeBuilder;
import org.opendaylight.mdsal.binding.model.util.Types;
final String fieldName = StringExtensions.toFirstLower(method.getName().substring(prefix.length()));
final GeneratedTOBuilder tmpGenTO = new CodegenGeneratedTOBuilder(JavaTypeName.create("foo", "foo"));
- tmpGenTO.addProperty(fieldName).setReturnType(method.getReturnType());
+ final GeneratedPropertyBuilder builder = tmpGenTO.addProperty(fieldName).setReturnType(method.getReturnType());
+ switch (method.getMechanics()) {
+ case NULLIFY_EMPTY:
+ builder.setNullifyEmpty(true);
+ break;
+ default:
+ break;
+ }
return tmpGenTO.build().getProperties().get(0);
}
}
«ENDFOR»
'''
+ override protected CharSequence generateCopyNonKeys(Collection<GeneratedProperty> props) '''
+ «FOR field : props»
+ «IF field.nullifyEmpty»
+ this.«field.fieldName» = «CODEHELPERS.importedName».emptyToNull(base.«field.getterMethodName»());
+ «ELSE»
+ this.«field.fieldName» = base.«field.getterMethodName»();
+ «ENDIF»
+ «ENDFOR»
+ '''
+
override protected generateCopyAugmentation(Type implType) '''
super(base.«AUGMENTATION_FIELD»);
'''
«generateCopyNonKeys(keyProps)»
'''
+
+ override protected CharSequence generateCopyNonKeys(Collection<GeneratedProperty> props) '''
+ «FOR field : props»
+ this.«field.fieldName» = base.«field.getterMethodName»();
+ «ENDFOR»
+ '''
+
override protected generateCopyAugmentation(Type implType) {
val augmentationHolderRef = AugmentationHolder.importedName
val typeRef = targetType.importedName
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
import org.opendaylight.mdsal.binding.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics;
import org.opendaylight.mdsal.binding.model.api.Type;
public class BuilderGeneratorTest {
final Type methType = mock(Type.class);
doReturn(TYPE_NAME).when(methType).getIdentifier();
doReturn(methType).when(methSign).getReturnType();
+ doReturn(ValueMechanics.NORMAL).when(methSign).getMechanics();
return methSign;
}
}