if (ownGetterType instanceof ParameterizedType) {
val itemType = ownGetterType.actualTypeArguments.get(0)
if (Types.isListType(ownGetterType)) {
- return '''
- this._«propertyName» = «CODEHELPERS.importedName».checkListFieldCast(«itemType.importedName».class, "«propertyName»", «retrieveProperty»)'''
+ val importedClass = importedClass(itemType)
+ if (importedClass !== null) {
+ return printPropertySetter(retrieveProperty, propertyName, "checkListFieldCastIdentity", importedClass)
+ }
+ return printPropertySetter(retrieveProperty, propertyName, "checkListFieldCast", itemType.importedName)
}
if (Types.isSetType(ownGetterType)) {
- return '''
- this._«propertyName» = «CODEHELPERS.importedName».checkSetFieldCast(«itemType.importedName».class, "«propertyName»", «retrieveProperty»)'''
+ 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 '''
- this._«propertyName» = «CODEHELPERS.importedName».checkFieldCast(«ownGetterType.importedName».class, "«propertyName»", «retrieveProperty»)'''
+ 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) {
--- /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.mdsal.binding.java.api.generator;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class Mdsal732Test extends BaseCompilationTest {
+ private File sourcesOutputDir;
+ private File compiledOutputDir;
+
+ @Before
+ public void before() throws IOException, URISyntaxException {
+ sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal732");
+ compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal732");
+ }
+
+ @After
+ public void after() {
+ CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
+ }
+
+ @Test
+ public void testIdentityrefLeafrefSpecialization() throws IOException, URISyntaxException {
+ generateTestSources("/compilation/mdsal732", sourcesOutputDir);
+ final var xyzzyBuilder = FileSearchUtil.getFiles(sourcesOutputDir).get("XyzzyBuilder.java");
+ assertNotNull(xyzzyBuilder);
+
+ 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());",
+ " }");
+ 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());",
+ " isValidArg = true;",
+ " }",
+ " CodeHelpers.validValue(isValidArg, arg, \"[Grp]\");",
+ " }");
+
+ CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
+ }
+}
--- /dev/null
+module mdsal732 {
+ namespace mdsal732;
+ prefix mdsal732;
+
+ grouping grp {
+ leaf foo {
+ type leafref {
+ path ../xyzzy;
+ }
+ }
+
+ leaf-list bar {
+ type leafref {
+ path ../xyzzy;
+ }
+ }
+
+ leaf-list baz {
+ type leafref {
+ path ../xyzzy;
+ }
+ ordered-by user;
+ }
+ }
+
+ identity foo;
+
+ container xyzzy {
+ leaf xyzzy {
+ type identityref {
+ base foo;
+ }
+ }
+
+ uses grp;
+ }
+}
+
}
}
+ /**
+ * 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.
*
}
/**
- * Utility method for checking whether the items of target list is compatible.
+ * 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.
*
* @param requiredClass Required item class
* @param fieldName name of the field being filled
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>
*/
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 {
+
+ }
}