* 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.dom.adapter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.opendaylight.mdsal.binding.api.WriteTransaction;
import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataBrokerTest;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test._2.rev160111.MyDerivedImportedIdentity;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.BigIntContainer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.BigIntContainerBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.BigUintContainer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.EnumContainerBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.IdentityrefContainer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.IdentityrefContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.MyDerivedIdentity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.MyDerivedIdentity2;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.NormalIntContainer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.NormalIntContainerBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns._default.value.test.norev.NormalUintContainer;
IdentityrefContainer idrefCont = identityrefContainerNode.get();
assertNull(idrefCont.getIdentityrefLeaf());
- assertEquals("MyDerivedIdentity", idrefCont.getIdentityrefLeaf2().getSimpleName());
- assertEquals("MyDerivedIdentity", idrefCont.getIdentityrefLeaf3().getSimpleName());
- assertEquals("MyDerivedIdentity2", idrefCont.getIdentityrefLeaf4().getSimpleName());
- assertEquals("MyDerivedImportedIdentity", idrefCont.getIdentityrefLeaf5().getSimpleName());
- assertEquals("MyDerivedIdentity", idrefCont.getIdentityrefLeaf6().getSimpleName());
+ assertSame(MyDerivedIdentity.VALUE, idrefCont.getIdentityrefLeaf2());
+ assertSame(MyDerivedIdentity.VALUE, idrefCont.getIdentityrefLeaf3());
+ assertSame(MyDerivedIdentity2.VALUE, idrefCont.getIdentityrefLeaf4());
+ assertSame(MyDerivedImportedIdentity.VALUE, idrefCont.getIdentityrefLeaf5());
+ assertSame(MyDerivedIdentity.VALUE, idrefCont.getIdentityrefLeaf6());
assertNull(idrefCont.getIdentityrefLeaf7());
}
}
/**
* Convert a QNname to its corresponding Binding class.
*
+ * @param <T> Expected identity type
* @param qname Identity QName
- * @return A binding Class corresponding to the QName
+ * @return A binding value corresponding to the QName
* @throws IllegalArgumentException if the qname does not map to an identity
- * @throws NullPointerException if qname is null
+ * @throws NullPointerException if {@code qname} is null
*/
- @NonNull Class<? extends BaseIdentity> toBinding(@NonNull QName qname);
+ <T extends BaseIdentity> @NonNull T toBinding(@NonNull QName qname);
/**
- * Concert a Binding class to its QName equivalent.
+ * Convert a Binding value to its QName equivalent.
*
- * @param bindingClass Binding class to convert
- * @return QName corresponding to the binding class
+ * @param bindingValue Binding value to convert
+ * @return QName corresponding to the binding value
+ * @throws IllegalArgumentException if the supplied value does not map to a known identity
* @throws NullPointerException if bindingClass is null
*/
- @NonNull QName fromBinding(Class<? extends BaseIdentity> bindingClass);
+ @NonNull QName fromBinding(@NonNull BaseIdentity bindingValue);
}
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.binding.Action;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.BaseNotification;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
// FIXME: this is probably not right w.r.t. nulls
IllegalArgumentCodec<Object, Object> getCodec(final Class<?> valueType, final TypeDefinition<?> instantiatedType) {
- if (Class.class.equals(valueType)) {
+ if (BaseIdentity.class.isAssignableFrom(valueType)) {
@SuppressWarnings({ "unchecked", "rawtypes" })
final IllegalArgumentCodec<Object, Object> casted = (IllegalArgumentCodec) identityCodec;
return casted;
@Override
Object bindingToDom(final Object bindingValue) {
- checkArgument(bindingValue instanceof Class, "Unexpected Binding value %s", bindingValue);
- final Class<? extends BaseIdentity> identity;
- try {
- identity = ((Class<?>) bindingValue).asSubclass(BaseIdentity.class);
- } catch (ClassCastException e) {
- throw new IllegalArgumentException("Unexpected Binding value " + bindingValue, e);
- }
- return valueCodec.fromBinding(identity);
+ checkArgument(bindingValue instanceof BaseIdentity, "Unexpected Binding value %s", bindingValue);
+ return valueCodec.fromBinding((BaseIdentity) bindingValue);
}
@Override
*/
package org.opendaylight.mdsal.binding.dom.codec.impl;
-import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
+import com.google.common.base.Throwables;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.concurrent.ExecutionException;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingIdentityCodec;
import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
import org.opendaylight.yangtools.concepts.AbstractIllegalArgumentCodec;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.common.QName;
-final class IdentityCodec extends AbstractIllegalArgumentCodec<QName, Class<?>> implements BindingIdentityCodec {
+final class IdentityCodec extends AbstractIllegalArgumentCodec<QName, BaseIdentity> implements BindingIdentityCodec {
+ private final LoadingCache<@NonNull QName, @NonNull BaseIdentity> values = CacheBuilder.newBuilder()
+ .build(new CacheLoader<>() {
+ @Override
+ public BaseIdentity load(final QName key) {
+ final var clazz = context.getIdentityClass(key);
+ final Field field;
+ try {
+ field = clazz.getField(BindingMapping.VALUE_STATIC_FIELD_NAME);
+ } catch (NoSuchFieldException e) {
+ throw new LinkageError(clazz + " does not define required field "
+ + BindingMapping.VALUE_STATIC_FIELD_NAME, e);
+ }
+ if (!Modifier.isStatic(field.getModifiers())) {
+ throw new LinkageError(field + " is not static");
+ }
+
+ final Object value;
+ try {
+ value = clazz.cast(field.get(null));
+ } catch (IllegalAccessException e) {
+ throw new LinkageError(field + " is not accesssible", e);
+ }
+ if (value == null) {
+ throw new LinkageError(field + " is null");
+ }
+ try {
+ return clazz.cast(value);
+ } catch (ClassCastException e) {
+ throw new LinkageError(field + " value " + value + " has illegal type", e);
+ }
+ }
+ });
+
private final BindingRuntimeContext context;
IdentityCodec(final BindingRuntimeContext context) {
}
@Override
- protected Class<?> deserializeImpl(final QName input) {
- return context.getIdentityClass(input);
+ protected BaseIdentity deserializeImpl(final QName input) {
+ return toBinding(input);
}
@Override
- protected QName serializeImpl(final Class<?> input) {
- checkArgument(BaseIdentity.class.isAssignableFrom(input), "%s is not an identity", input);
- return BindingReflections.findQName(input);
+ protected QName serializeImpl(final BaseIdentity input) {
+ return fromBinding(input);
}
@Override
- public Class<? extends BaseIdentity> toBinding(final QName qname) {
- final Class<?> identity = context.getIdentityClass(requireNonNull(qname));
- checkArgument(BaseIdentity.class.isAssignableFrom(identity), "%s resolves to non-identity %s", qname, identity);
- return identity.asSubclass(BaseIdentity.class);
+ @SuppressWarnings("unchecked")
+ public <T extends BaseIdentity> T toBinding(final QName qname) {
+ try {
+ return (T) values.get(requireNonNull(qname));
+ } catch (ExecutionException e) {
+ Throwables.throwIfUnchecked(e.getCause());
+ throw new IllegalStateException("Unexpected error translating " + qname, e);
+ }
}
@Override
- public QName fromBinding(final Class<? extends BaseIdentity> bindingClass) {
- return BindingReflections.getQName(bindingClass);
+ public QName fromBinding(final BaseIdentity bindingValue) {
+ return BindingReflections.getQName(bindingValue.implementedInterface());
}
}
@Test
public void testCaseWithLeafReferencesType() {
final TreeComplexLeaves binding = new TreeComplexLeavesBuilder()
- .setIdentity(ThirdParty.class)
- .setIdentityRef(ThirdParty.class)
+ .setIdentity(ThirdParty.VALUE)
+ .setIdentityRef(ThirdParty.VALUE)
.setSimpleType(10)
.setSimpleTypeRef(10)
.setSchemaUnawareUnion(new Int32StringUnion("foo"))
private static MethodSignatureBuilder defineImplementedInterfaceMethod(final GeneratedTypeBuilder typeBuilder,
final Type classType) {
final MethodSignatureBuilder ret = typeBuilder
- .addMethod(BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME)
+ .addMethod(BindingMapping.BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME)
.setAccessModifier(AccessModifier.PUBLIC)
.setReturnType(classType(classType));
ret.addAnnotation(OVERRIDE_ANNOTATION);
import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
import org.opendaylight.mdsal.binding.runtime.api.IdentityRuntimeType;
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.model.api.stmt.BaseEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.IdentityEffectiveStatement;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
builder.addImplementsType(BASE_IDENTITY);
}
+ narrowImplementedInterface(builder);
+
final ModuleGenerator module = currentModule();
module.addQNameConstant(builder, localName());
+ // Constant implementation
+ builder.addConstant(Type.of(builder), BindingMapping.VALUE_STATIC_FIELD_NAME, BaseIdentity.class);
+
builderFactory.addCodegenInformation(module, statement(), builder);
builder.setModuleName(module.statement().argument().getLocalName());
// builder.setSchemaPath(identity.getPath());
import static java.util.Objects.requireNonNull;
import java.util.List;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.mdsal.binding.model.ri.Types;
private static final class Identityref extends TypeReference {
private final List<IdentityGenerator> referencedGenerators;
- private ParameterizedType returnType;
+ private Type returnType;
Identityref(final List<IdentityGenerator> referencedGenerators) {
this.referencedGenerators = requireNonNull(referencedGenerators);
@Override
Type methodReturnType(final TypeBuilderFactory builderFactory) {
if (returnType == null) {
- final List<GeneratedType> referencedTypes = referencedGenerators.stream()
- .map(gen -> gen.getGeneratedType(builderFactory))
- .collect(Collectors.toUnmodifiableList());
// FIXME: This deals only with RFC6020 semantics. In order to deal with full RFC7950 semantics, we need
// to analyze all the types and come up with the lowest-common denominator and use that as the
// return type. We also need to encode restrictions, so that builder generator ends up checking
// identities being passed -- because the identities may be completely unrelated, in which case
// we cannot generate type-safe code.
- returnType = Types.classType(Types.wildcardTypeFor(referencedTypes.get(0).getIdentifier()));
+ returnType = referencedGenerators.stream()
+ .map(gen -> gen.getGeneratedType(builderFactory))
+ .findFirst()
+ .orElseThrow();
}
return returnType;
}
@Test
public void generatedTypeForExtendedDefinitionTypeWithIdentityrefBaseTypeTest() {
- assertEquals(Types.parameterizedTypeFor(Types.CLASS, Type.of(JavaTypeName.create(TEST_TYPE_PROVIDER, "Aes"))),
+ assertEquals(Type.of(JavaTypeName.create(TEST_TYPE_PROVIDER, "Aes")),
assertGeneratedMethod(CONSTRUCTION_TYPE_TEST, "getAesIdentityrefType").getReturnType());
}
@Test
public void javaTypeForSchemaDefinitionIdentityrefExtTypeTest() {
- assertEquals(Types.parameterizedTypeFor(Types.CLASS,
- Types.wildcardTypeFor(JavaTypeName.create(TEST_TYPE_PROVIDER, "CryptoAlg"))),
+ assertEquals(Type.of(JavaTypeName.create(TEST_TYPE_PROVIDER, "CryptoAlg")),
assertGeneratedMethod(TEST_TYPE_PROVIDER_FOO, "getCrypto").getReturnType());
}
*/
package org.opendaylight.mdsal.binding.generator.impl;
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import java.io.File;
import org.junit.Test;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
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.ri.Types;
import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
public class IdentityrefTypeTest {
assertEquals("getLf", methodSignature.getName());
assertEquals("requireLf", methodSignatures.get(1).getName());
- Type returnType = methodSignature.getReturnType();
- assertThat(returnType, instanceOf(ParameterizedType.class));
- ParameterizedType parameterized = (ParameterizedType) returnType;
- assertEquals(Types.CLASS, parameterized.getRawType());
-
- Type[] actualTypes = parameterized.getActualTypeArguments();
- assertEquals("Incorrect number of type parameters", 1, actualTypes.length);
- assertEquals("Return type has incorrect actual parameter",
- "org.opendaylight.yang.gen.v1.urn.identityref.module.rev131109.SomeIdentity",
- actualTypes[0].getFullyQualifiedName());
+ assertEquals("org.opendaylight.yang.gen.v1.urn.identityref.module.rev131109.SomeIdentity",
+ methodSignature.getReturnType().getFullyQualifiedName());
}
}
general.getReturnType().getFullyQualifiedName());
assertEquals("mplsLabelSpecialPurpose", special.getName());
- assertEquals("java.lang.Class", special.getReturnType().getFullyQualifiedName());
+ assertEquals("org.opendaylight.yang.gen.v1.mdsal269.rev180130.MplsLabelSpecialPurposeValue",
+ special.getReturnType().getFullyQualifiedName());
}
}
package org.opendaylight.mdsal.binding.java.api.generator
import static extension org.opendaylight.mdsal.binding.generator.BindingGeneratorUtil.encodeAngleBrackets
+import static org.opendaylight.mdsal.binding.model.ri.Types.STRING;
+import static org.opendaylight.mdsal.binding.model.ri.Types.objectType;
import com.google.common.base.CharMatcher
import com.google.common.base.Splitter
import org.opendaylight.mdsal.binding.model.api.TypeMemberComment
import org.opendaylight.mdsal.binding.model.ri.TypeConstants
import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
@SuppressModernizer
abstract class BaseTemplate extends JavaFileTemplate {
«IF BindingMapping.QNAME_STATIC_FIELD_NAME.equals(c.name)»
«val entry = c.value as Entry<JavaTypeName, String>»
public static final «c.type.importedNonNull» «c.name» = «entry.key.importedName».«BindingMapping.MODULE_INFO_QNAMEOF_METHOD_NAME»("«entry.value»");
+ «ELSEIF BindingMapping.VALUE_STATIC_FIELD_NAME.equals(c.name) && BaseIdentity.equals(c.value)»
+ «val typeName = c.type.importedName»
+ «val override = OVERRIDE.importedName»
+ /**
+ * Singleton value representing the {@link «typeName»} identity.
+ */
+ public static final «c.type.importedNonNull» «c.name» = new «typeName»() {
+ @«override»
+ public «CLASS.importedName»<«typeName»> «BindingMapping.BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME»() {
+ return «typeName».class;
+ }
+
+ @«override»
+ public int hashCode() {
+ return «typeName».class.hashCode();
+ }
+
+ @«override»
+ public boolean equals(final «objectType.importedName» obj) {
+ return obj == this || obj instanceof «typeName»
+ && «typeName».class.equals(((«typeName») obj).«BindingMapping.BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME»());
+ }
+
+ @«override»
+ public «STRING.importedName» toString() {
+ return «MOREOBJECTS.importedName».toStringHelper("«c.type.name»").add("qname", QNAME).toString();
+ }
+ };
«ELSE»
public static final «c.type.importedName» «c.name» = «c.value»;
«ENDIF»
import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.DATA_OBJECT
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTABLE_AUGMENTATION_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTATION_FIELD
-import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableSet
if (ownGetterType instanceof ParameterizedType) {
val itemType = ownGetterType.actualTypeArguments.get(0)
if (Types.isListType(ownGetterType)) {
- val importedClass = importedClass(itemType)
- if (importedClass !== null) {
- return printPropertySetter(retrieveProperty, propertyName, "checkListFieldCastIdentity", importedClass)
- }
return printPropertySetter(retrieveProperty, propertyName, "checkListFieldCast", itemType.importedName)
}
if (Types.isSetType(ownGetterType)) {
- val importedClass = importedClass(itemType)
- if (importedClass !== null) {
- return printPropertySetter(retrieveProperty, propertyName, "checkSetFieldCastIdentity", importedClass)
- }
return printPropertySetter(retrieveProperty, propertyName, "checkSetFieldCast", itemType.importedName)
}
- if (Types.CLASS.equals(ownGetterType)) {
- return printPropertySetter(retrieveProperty, propertyName, "checkFieldCastIdentity", itemType.identifier.importedName)
- }
}
return printPropertySetter(retrieveProperty, propertyName, "checkFieldCast", ownGetterType.importedName)
}
def private printPropertySetter(String retrieveProperty, String propertyName, String checkerName, String className) '''
this._«propertyName» = «CODEHELPERS.importedName».«checkerName»(«className».class, "«propertyName»", «retrieveProperty»)'''
- private def importedClass(Type type) {
- if (type instanceof ParameterizedType) {
- if (Types.CLASS.equals(type.rawType)) {
- return type.actualTypeArguments.get(0).identifier.importedName
- }
- }
- return null
- }
-
private def List<Type> getBaseIfcs(GeneratedType type) {
val List<Type> baseIfcs = new ArrayList();
for (ifc : type.implements) {
* @throws NullPointerException if {@code augmentation} is null
*/
public «type.name» addAugmentation(«augmentTypeRef» augmentation) {
- «jlClassRef»<? extends «augmentTypeRef»> augmentationType = augmentation.«DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME»();
+ «jlClassRef»<? extends «augmentTypeRef»> augmentationType = augmentation.«BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME»();
if (!(this.«AUGMENTATION_FIELD» instanceof «hashMapRef»)) {
this.«AUGMENTATION_FIELD» = new «hashMapRef»<>();
}
BaseYangTypes.UINT32_TYPE,
BaseYangTypes.UINT64_TYPE,
BaseYangTypes.BOOLEAN_TYPE,
- BaseYangTypes.EMPTY_TYPE,
- Types.CLASS);
+ BaseYangTypes.EMPTY_TYPE);
/**
* Singleton instance.
}
private static int rankOf(final Type type) {
- if (FIXED_TYPES.contains(type)) {
+ if (FIXED_TYPES.contains(type) || BindingTypes.isIdentityType(type)) {
return RANK_FIXED_SIZE;
}
if (type.equals(BaseYangTypes.STRING_TYPE) || type.equals(Types.BYTE_ARRAY)) {
import static org.opendaylight.mdsal.binding.model.ri.Types.BOOLEAN
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 org.opendaylight.mdsal.binding.model.ri.TypeConstants
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.
«propertyMethods»
- «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)»
+ «IF genTO.isBitsType»
«generateGetValueForBitsTypeDef»
«ENDIF»
import static org.opendaylight.mdsal.binding.model.ri.Types.STRING
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.REQUIRE_PREFIX
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTATION_FIELD
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_EQUALS_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_HASHCODE_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_TO_STRING_NAME
-import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME
import com.google.common.annotations.VisibleForTesting;
import java.util.List
generateRequireMethod(method)
} else {
switch method.name {
- case DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME : generateDefaultImplementedInterface
+ case BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME : generateDefaultImplementedInterface
default :
if (VOID == method.returnType.identifier) {
generateNoopVoidInterfaceMethod(method)
def private generateDefaultImplementedInterface() '''
@«OVERRIDE.importedName»
- default «CLASS.importedName»<«type.fullyQualifiedName»> «DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME»() {
+ default «CLASS.importedName»<«type.fullyQualifiedName»> «BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME»() {
return «type.fullyQualifiedName».class;
}
'''
*/
package org.opendaylight.mdsal.binding.java.api.generator
-import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.BINARY_TYPE;
-import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.BOOLEAN_TYPE;
-import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.EMPTY_TYPE;
-import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.STRING_TYPE;
-import static org.opendaylight.mdsal.binding.model.ri.Types.STRING;
-import static org.opendaylight.mdsal.binding.model.ri.Types.getOuterClassName;
+import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.BINARY_TYPE
+import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.BOOLEAN_TYPE
+import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.EMPTY_TYPE
+import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.STRING_TYPE
+import static org.opendaylight.mdsal.binding.model.ri.Types.STRING
+import static org.opendaylight.mdsal.binding.model.ri.Types.getOuterClassName
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME
import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.BUILDER_SUFFIX
+import static extension org.opendaylight.mdsal.binding.model.ri.BindingTypes.isBitsType
+import static extension org.opendaylight.mdsal.binding.model.ri.BindingTypes.isIdentityType
import java.util.Base64;
import org.gaul.modernizer_maven_annotations.SuppressModernizer
-import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject
import org.opendaylight.mdsal.binding.model.api.Enumeration
+import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject
import org.opendaylight.mdsal.binding.model.api.Type
-import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
/**
* Template for generating JAVA class.
«ELSEIF propRet.isBitsType»
««« generated bits typedef
return «JU_ARRAYS.importedName».toString(«field».getValue());
+ «ELSEIF propRet.isIdentityType»
+ ««« generated identity
+ return «field».«BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME»().toString();
«ELSE»
««« generated type
return «field».getValue().toString();
}
'''
- private static def isBitsType(Type type) {
- if (type instanceof GeneratedTransferObject) {
- return type.typedef && type.baseType instanceof BitsTypeDefinition
- }
- return false
- }
-
private static def Type typedefReturnType(Type type) {
if (!(type instanceof GeneratedTransferObject)) {
return null
«ENDFOR»
}
'''
-
}
private static void testReturnTypeIdentityref(final Class<?> clazz, final String methodName,
final String returnTypeStr) throws NoSuchMethodException {
- Method method = clazz.getMethod(methodName);
- assertEquals(java.lang.Class.class, method.getReturnType());
- Type returnType = method.getGenericReturnType();
- assertTrue(returnType instanceof ParameterizedType);
- final ParameterizedType pt = (ParameterizedType) returnType;
- final Type[] parameters = pt.getActualTypeArguments();
- assertEquals(1, parameters.length);
- final Type parameter = parameters[0];
- assertTrue(parameter instanceof WildcardType);
- final WildcardType wildcardType = (WildcardType) parameter;
- assertEquals("? extends " + returnTypeStr, wildcardType.toString());
+ Class<?> returnType = clazz.getMethod(methodName).getReturnType();
+ assertTrue(returnType.isInterface());
+ assertEquals(returnTypeStr, returnType.getName());
}
private static void testReturnTypeInstanceIdentitifer(final ClassLoader loader, final Class<?> clazz,
final var content = Files.readString(xyzzyBuilder.toPath());
FileSearchUtil.assertFileContainsConsecutiveLines(xyzzyBuilder, content,
" public XyzzyBuilder(Grp arg) {",
- " this._foo = CodeHelpers.checkFieldCastIdentity(Foo.class, \"foo\", arg.getFoo());",
- " this._bar = CodeHelpers.checkSetFieldCastIdentity(Foo.class, \"bar\", arg.getBar());",
- " this._baz = CodeHelpers.checkListFieldCastIdentity(Foo.class, \"baz\", arg.getBaz());",
+ " this._foo = CodeHelpers.checkFieldCast(Foo.class, \"foo\", arg.getFoo());",
+ " this._bar = CodeHelpers.checkSetFieldCast(Foo.class, \"bar\", arg.getBar());",
+ " this._baz = CodeHelpers.checkListFieldCast(Foo.class, \"baz\", arg.getBaz());",
" }");
FileSearchUtil.assertFileContainsConsecutiveLines(xyzzyBuilder, content,
" public void fieldsFrom(DataObject arg) {",
" boolean isValidArg = false;",
" if (arg instanceof Grp) {",
- " this._foo = CodeHelpers.checkFieldCastIdentity(Foo.class, \"foo\", ((Grp)arg).getFoo());",
- " this._bar = CodeHelpers.checkSetFieldCastIdentity(Foo.class, \"bar\", ((Grp)arg).getBar());",
- " this._baz = CodeHelpers.checkListFieldCastIdentity(Foo.class, \"baz\", ((Grp)arg).getBaz());",
+ " this._foo = CodeHelpers.checkFieldCast(Foo.class, \"foo\", ((Grp)arg).getFoo());",
+ " this._bar = CodeHelpers.checkSetFieldCast(Foo.class, \"bar\", ((Grp)arg).getBar());",
+ " this._baz = CodeHelpers.checkListFieldCast(Foo.class, \"baz\", ((Grp)arg).getBaz());",
" isValidArg = true;",
" }",
" CodeHelpers.validValue(isValidArg, arg, \"[Grp]\");",
import java.net.URL;
import java.net.URLClassLoader;
import org.junit.Test;
+import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
/**
* Union constructor with indentityref. Previously identityref was ignored so that there is no constructor for
Class<?> unionTypeClass = Class.forName(CompilationTestUtils.BASE_PKG
+ ".urn.opendaylight.yang.union.test.rev160509.UnionType", true, loader);
+ Object identOneValue = identOneClass.getDeclaredField(BindingMapping.VALUE_STATIC_FIELD_NAME).get(null);
+
// test UnionType with IdentOne argument
Constructor<?> unionTypeIdentBaseConstructor = CompilationTestUtils.assertContainsConstructor(unionTypeClass,
- Class.class);
- Object unionType = unionTypeIdentBaseConstructor.newInstance(identOneClass);
+ identBaseClass);
+ Object unionType = unionTypeIdentBaseConstructor.newInstance(identOneValue);
Method getUint8 = unionTypeClass.getDeclaredMethod("getUint8");
Object actualUint8 = getUint8.invoke(unionType);
Method getIdentityref = unionTypeClass.getDeclaredMethod("getIdentityref");
Object actualIdentityref = getIdentityref.invoke(unionType);
- assertEquals(identOneClass, actualIdentityref);
+ assertEquals(identOneValue, actualIdentityref);
CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
}
import static org.opendaylight.mdsal.binding.model.ri.Types.parameterizedTypeFor;
import static org.opendaylight.mdsal.binding.model.ri.Types.typeForClass;
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.VALUE_STATIC_FIELD_NAME;
import com.google.common.annotations.VisibleForTesting;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.binding.model.api.ConcreteType;
+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.ParameterizedType;
import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
public final class BindingTypes {
public static ParameterizedType scalarTypeObject(final Type type) {
return parameterizedTypeFor(SCALAR_TYPE_OBJECT, type);
}
+
+ /**
+ * Check if specified type is generated for a {@code type bits}.
+ *
+ * @param type Type to examine
+ * @return {@code true} if the type is generated for a {@code type bits}
+ */
+ public static boolean isBitsType(final Type type) {
+ return type instanceof GeneratedTransferObject && isBitsType((GeneratedTransferObject) type);
+ }
+
+ /**
+ * Check if specified type is generated for a {@code type bits}.
+ *
+ * @param gto Type to examine
+ * @return {@code true} if the type is generated for a {@code type bits}
+ */
+ public static boolean isBitsType(final GeneratedTransferObject gto) {
+ return gto.isTypedef() && gto.getBaseType() instanceof BitsTypeDefinition;
+ }
+
+ /**
+ * Check if specified type is generated for an identity.
+ *
+ * @param type Type to examine
+ * @return {@code true} if the type is generated for an identity
+ */
+ public static boolean isIdentityType(final Type type) {
+ if (type instanceof GeneratedType) {
+ for (var constant : ((GeneratedType) type).getConstantDefinitions()) {
+ if (VALUE_STATIC_FIELD_NAME.equals(constant.getName())
+ && BaseIdentity.class.equals(constant.getValue())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
package org.opendaylight.mdsal.binding.runtime.api;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
+import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import java.util.concurrent.ExecutionException;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.Notification;
import org.opendaylight.yangtools.yang.binding.RpcInput;
import org.opendaylight.yangtools.yang.binding.RpcOutput;
*/
@Beta
public abstract class AbstractBindingRuntimeContext implements BindingRuntimeContext {
- private final LoadingCache<QName, Class<?>> identityClasses = CacheBuilder.newBuilder().weakValues().build(
- new CacheLoader<QName, Class<?>>() {
+ private final LoadingCache<@NonNull QName, @NonNull Class<? extends BaseIdentity>> identityClasses =
+ CacheBuilder.newBuilder().weakValues().build(new CacheLoader<>() {
@Override
- public Class<?> load(final QName key) {
+ public Class<? extends BaseIdentity> load(final QName key) {
final var type = getTypes().findIdentity(key).orElseThrow(
() -> new IllegalArgumentException("Supplied QName " + key + " is not a valid identity"));
try {
- return loadClass(type.getIdentifier());
- } catch (final ClassNotFoundException e) {
+ return loadClass(type.getIdentifier()).asSubclass(BaseIdentity.class);
+ } catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Required class " + type + " was not found.", e);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException(key + " resolves to a non-identity class", e);
}
}
});
}
@Override
- public final Class<?> getIdentityClass(final QName input) {
- return identityClasses.getUnchecked(input);
+ public final Class<? extends BaseIdentity> getIdentityClass(final QName input) {
+ try {
+ return identityClasses.get(requireNonNull(input));
+ } catch (ExecutionException e) {
+ Throwables.throwIfUnchecked(e.getCause());
+ throw new IllegalStateException("Unexpected error looking up " + input, e);
+ }
}
@Override
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.RpcInput;
import org.opendaylight.yangtools.yang.binding.RpcOutput;
import org.opendaylight.yangtools.yang.common.QName;
// FIXME: 9.0.0: this needs to accept an EffectiveStatementInference
@NonNull Class<?> getClassForSchema(Absolute schema);
- @NonNull Class<?> getIdentityClass(QName input);
+ @NonNull Class<? extends BaseIdentity> getIdentityClass(QName input);
}
import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.RpcInput;
import org.opendaylight.yangtools.yang.binding.RpcOutput;
import org.opendaylight.yangtools.yang.common.QName;
}
@Override
- public Class<?> getIdentityClass(final QName input) {
+ public Class<? extends BaseIdentity> getIdentityClass(final QName input) {
return delegate().getIdentityClass(input);
}
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.binding.Augmentable;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.BindingContract;
import org.opendaylight.yangtools.yang.binding.Identifiable;
import org.opendaylight.yangtools.yang.binding.ScalarTypeObject;
import org.opendaylight.yangtools.yang.common.QName;
public static final @NonNull String BUILDER_SUFFIX = "Builder";
public static final @NonNull String KEY_SUFFIX = "Key";
public static final @NonNull String QNAME_STATIC_FIELD_NAME = "QNAME";
+ public static final @NonNull String VALUE_STATIC_FIELD_NAME = "VALUE";
public static final @NonNull String PACKAGE_PREFIX = "org.opendaylight.yang.gen.v1";
public static final @NonNull String AUGMENTATION_FIELD = "augmentation";
public static final @NonNull String IDENTIFIABLE_KEY_NAME = "key";
/**
- * Name of {@link DataContainer#implementedInterface()}.
+ * Name of {@link BindingContract#implementedInterface()}.
*/
- public static final @NonNull String DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME = "implementedInterface";
+ public static final @NonNull String BINDING_CONTRACT_IMPLEMENTED_INTERFACE_NAME = "implementedInterface";
/**
* Name of default {@link Object#hashCode()} implementation for instantiated DataObjects. Each such generated
package org.opendaylight.yangtools.yang.binding;
/**
- * Base Identity.
+ * Base Identity. Interface generated for {@code identity} statements extend this interface.
*/
-public interface BaseIdentity {
+public interface BaseIdentity extends BindingObject, BindingContract<BaseIdentity> {
}
--- /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.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Base interface for all interfaces generated to capture a specific contract.
+ *
+ * @param <T> Type of the captured contract
+ */
+@Beta
+// FIXME: evaluate integrating with BindingObject
+public interface BindingContract<T extends BindingContract<T>> {
+ /**
+ * Return the interface implemented by this object. This method differs from {@link Object#getClass()} in that it
+ * returns the interface contract, not a concrete implementation class.
+ *
+ * @return Implemented contract
+ */
+ @NonNull Class<? extends T> implementedInterface();
+}
return wrapHashCode(Arrays.hashCode(obj));
}
+ /**
+ * The constant '31' is the result of folding this code:
+ * <pre>
+ * <code>
+ * final int prime = 31;
+ * int result = 1;
+ * result = result * prime + Objects.hashCode(obj);
+ * return result;
+ * </code>
+ * </pre>
+ * when hashCode is returned as 0, such as due to obj being null or its hashCode being 0.
+ *
+ * @param hash Wrapped object hash
+ * @return Wrapper object hash
+ */
+ private static int wrapHashCode(final int hash) {
+ return hash == 0 ? 31 : hash;
+ }
+
/**
* Utility method for checking whether a target object is a compatible DataObject.
*
}
}
- /**
- * Utility method for checking whether a target object is compatible with a particular identity class.
- *
- * @param requiredClass Required class
- * @param fieldName name of the field being filled
- * @param obj Object to check, may be null
- * @return Object cast to required class, if it class matches requirement, or null
- * @throws IllegalArgumentException if {@code obj} is not an Class representing {@code requiredClass}
- * @throws NullPointerException if {@code requiredClass} or {@code fieldName} is null
- */
- public static <T extends BaseIdentity> @Nullable Class<? extends T> checkFieldCastIdentity(
- final @NonNull Class<T> requiredClass, final @NonNull String fieldName, final @Nullable Object obj) {
- if (obj == null) {
- return null;
- }
- checkArgument(obj instanceof Class, "Invalid input value \"%s\" for property \"%s\"", obj, fieldName);
-
- try {
- return ((Class<?>) obj).asSubclass(requiredClass);
- } catch (ClassCastException e) {
- throw new IllegalArgumentException("Invalid input value \"" + obj + "\" for property \"" + fieldName + "\"",
- e);
- }
- }
-
/**
* Utility method for checking whether the items of target list is compatible.
*
return (List<T>) list;
}
- /**
- * Utility method for checking whether the items of a target list are compatible with a particular identity class.
- *
- * @param requiredClass Required class
- * @param fieldName name of the field being filled
- * @param list List, which items should be checked
- * @return Type-checked List
- * @throws IllegalArgumentException if a list item is not a Class representing {@code requiredClass}
- * @throws NullPointerException if {@code requiredClass} or {@code fieldName} is null
- */
- @SuppressWarnings("unchecked")
- public static <T extends BaseIdentity> @Nullable List<Class<? extends T>> checkListFieldCastIdentity(
- final @NonNull Class<T> requiredClass, final @NonNull String fieldName, final @Nullable List<?> list) {
- checkCollectionFieldIdentity(requiredClass, fieldName, list);
- return (List<Class<? extends T>>) list;
- }
-
/**
* Utility method for checking whether the items of target set is compatible.
*
return (Set<T>) set;
}
- /**
- * Utility method for checking whether the items of a target set are compatible with a particular identity class.
- *
- * @param requiredClass Required class
- * @param fieldName name of the field being filled
- * @param set Set, which items should be checked
- * @return Type-checked Set
- * @throws IllegalArgumentException if a set item is not a Class representing {@code requiredClass}
- * @throws NullPointerException if {@code requiredClass} or {@code fieldName} is null
- */
- @SuppressWarnings("unchecked")
- public static <T extends BaseIdentity> @Nullable Set<Class<? extends T>> checkSetFieldCastIdentity(
- final @NonNull Class<T> requiredClass, final @NonNull String fieldName, final @Nullable Set<?> set) {
- checkCollectionFieldIdentity(requiredClass, fieldName, set);
- return (Set<Class<? extends T>>) set;
- }
-
@SuppressFBWarnings(value = "DCN_NULLPOINTER_EXCEPTION",
justification = "Internal NPE->IAE conversion")
private static void checkCollectionField(final @NonNull Class<?> requiredClass,
}
}
}
-
- @SuppressFBWarnings(value = "DCN_NULLPOINTER_EXCEPTION",
- justification = "Internal NPE->IAE conversion")
- private static void checkCollectionFieldIdentity(final @NonNull Class<?> requiredClass,
- final @NonNull String fieldName, final @Nullable Collection<?> collection) {
- if (collection != null) {
- try {
- collection.forEach(item -> ((Class<?>) item).asSubclass(requiredClass));
- } catch (ClassCastException | NullPointerException e) {
- throw new IllegalArgumentException("Invalid input item for property \"" + requireNonNull(fieldName)
- + "\"", e);
- }
- }
- }
-
- /**
- * The constant '31' is the result of folding this code:
- * <pre>
- * <code>
- * final int prime = 31;
- * int result = 1;
- * result = result * prime + Objects.hashCode(obj);
- * return result;
- * </code>
- * </pre>
- * when hashCode is returned as 0, such as due to obj being null or its hashCode being 0.
- *
- * @param hash Wrapped object hash
- * @return Wrapper object hash
- */
- private static int wrapHashCode(final int hash) {
- return hash == 0 ? 31 : hash;
- }
}
*/
package org.opendaylight.yangtools.yang.binding;
-import org.eclipse.jdt.annotation.NonNull;
-
/**
* Data Container - object contains structured data. Marker interface which must be implemented by all interfaces
* generated for YANG:
* <ul>
- * <li>Rpc Input
- * <li>Output
- * <li>Notification
- * <li>Container
- * <li>List
- * <li>Case
+ * <li>Rpc Input</li>
+ * <li>Output</li>
+ * <li>Notification</li>
+ * <li>Container</li>
+ * <li>List</li>
+ * <li>Case</li>
* </ul>
*/
-public interface DataContainer {
- /**
- * Return the interface implemented by this object. This method differs from {@link Object#getClass()} in that it
- * returns the interface contract, not a concrete implementation class.
- *
- * @return Implemented contract
- */
- @NonNull Class<? extends DataContainer> implementedInterface();
+public interface DataContainer extends BindingContract<DataContainer> {
+
}
*/
package org.opendaylight.yangtools.yang.binding;
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
assertThat(iae.getCause(), instanceOf(ClassCastException.class));
}
- @Test
- public void testCheckedFieldCastIdentity() {
- assertNull(CodeHelpers.checkFieldCastIdentity(Identity.class, "foo", null));
- assertSame(Identity.class, CodeHelpers.checkFieldCastIdentity(Identity.class, "foo", Identity.class));
- assertSame(DerivedIdentity.class, CodeHelpers.checkFieldCastIdentity(Identity.class, "foo",
- DerivedIdentity.class));
-
- IllegalArgumentException iae = assertThrows(IllegalArgumentException.class,
- () -> CodeHelpers.checkFieldCastIdentity(Identity.class, "foo", new Object()));
- assertThat(iae.getMessage(), allOf(
- startsWith("Invalid input value \"java.lang.Object"),
- endsWith("\" for property \"foo\"")));
-
- iae = assertThrows(IllegalArgumentException.class,
- () -> CodeHelpers.checkFieldCastIdentity(Identity.class, "foo", BaseIdentity.class));
- assertThat(iae.getCause(), instanceOf(ClassCastException.class));
- }
-
@Test
public void testCheckListFieldCast() {
assertNull(CodeHelpers.checkListFieldCast(CodeHelpersTest.class, "foo", null));
assertThat(iae.getCause(), instanceOf(ClassCastException.class));
}
- @Test
- public void testCheckListFieldCastIdentity() {
- assertNull(CodeHelpers.checkListFieldCastIdentity(Identity.class, "foo", null));
- assertSame(List.of(), CodeHelpers.checkListFieldCastIdentity(Identity.class, "foo", List.of()));
-
- final var list = List.of(Identity.class);
- assertSame(list, CodeHelpers.checkListFieldCastIdentity(Identity.class, "foo", list));
- final var derivedList = List.of(DerivedIdentity.class);
- assertSame(derivedList, CodeHelpers.checkListFieldCastIdentity(Identity.class, "foo", derivedList));
-
- IllegalArgumentException iae = assertThrows(IllegalArgumentException.class,
- () -> CodeHelpers.checkListFieldCastIdentity(Identity.class, "foo", Collections.singletonList(null)));
- assertThat(iae.getCause(), instanceOf(NullPointerException.class));
-
- iae = assertThrows(IllegalArgumentException.class,
- () -> CodeHelpers.checkListFieldCastIdentity(Identity.class, "foo", List.of(new Object())));
- assertThat(iae.getCause(), instanceOf(ClassCastException.class));
-
- iae = assertThrows(IllegalArgumentException.class,
- () -> CodeHelpers.checkListFieldCastIdentity(Identity.class, "foo", List.of(BaseIdentity.class)));
- assertThat(iae.getCause(), instanceOf(ClassCastException.class));
- }
-
@Test
public void testCheckSetFieldCast() {
assertNull(CodeHelpers.checkSetFieldCast(CodeHelpersTest.class, "foo", null));
() -> CodeHelpers.checkSetFieldCast(CodeHelpersTest.class, "foo", Set.of(new Object())));
assertThat(iae.getCause(), instanceOf(ClassCastException.class));
}
-
- @Test
- public void testCheckSetFieldCastIdentity() {
- assertNull(CodeHelpers.checkSetFieldCastIdentity(Identity.class, "foo", null));
- assertSame(Set.of(), CodeHelpers.checkSetFieldCastIdentity(Identity.class, "foo", Set.of()));
-
- final var set = Set.of(Identity.class);
- assertSame(set, CodeHelpers.checkSetFieldCastIdentity(Identity.class, "foo", set));
- final var derivedSet = Set.of(DerivedIdentity.class);
- assertSame(derivedSet, CodeHelpers.checkSetFieldCastIdentity(Identity.class, "foo", derivedSet));
-
- IllegalArgumentException iae = assertThrows(IllegalArgumentException.class,
- () -> CodeHelpers.checkSetFieldCastIdentity(Identity.class, "foo", Collections.singleton(null)));
- assertThat(iae.getCause(), instanceOf(NullPointerException.class));
-
- iae = assertThrows(IllegalArgumentException.class,
- () -> CodeHelpers.checkSetFieldCastIdentity(Identity.class, "foo", Set.of(new Object())));
- assertThat(iae.getCause(), instanceOf(ClassCastException.class));
-
- iae = assertThrows(IllegalArgumentException.class,
- () -> CodeHelpers.checkSetFieldCastIdentity(Identity.class, "foo", Set.of(BaseIdentity.class)));
- assertThat(iae.getCause(), instanceOf(ClassCastException.class));
- }
-
- private interface Identity extends BaseIdentity {
-
- }
-
- private interface DerivedIdentity extends Identity {
-
- }
}