X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-dom-codec%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fdom%2Fcodec%2Fimpl%2FIdentifiableItemCodec.java;h=0b89bff24fda6e2ea4e277388b5c999d72c8c9a2;hb=984dfcd854a006724cbf0b20efc8bac6094bad48;hp=2f420ebe318975e21de53bdbc538ad9ccd88c756;hpb=64eed22a5dc986640d756d2b153af33638635921;p=mdsal.git diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/IdentifiableItemCodec.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/IdentifiableItemCodec.java index 2f420ebe31..0b89bff24f 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/IdentifiableItemCodec.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/IdentifiableItemCodec.java @@ -20,49 +20,49 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.binding.spec.naming.BindingMapping; -import org.opendaylight.yangtools.concepts.Codec; import org.opendaylight.yangtools.util.ImmutableOffsetMap; import org.opendaylight.yangtools.util.ImmutableOffsetMapTemplate; -import org.opendaylight.yangtools.util.SharedSingletonMapTemplate; import org.opendaylight.yangtools.yang.binding.Identifiable; import org.opendaylight.yangtools.yang.binding.Identifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.stmt.KeyEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Codec support for extracting the {@link Identifiable#key()} method return from a MapEntryNode. */ -abstract class IdentifiableItemCodec implements Codec> { +// FIXME: sealed class when we have JDK17+ +abstract class IdentifiableItemCodec { private static final class SingleKey extends IdentifiableItemCodec { private static final MethodType CTOR_TYPE = MethodType.methodType(Identifier.class, Object.class); - private final SharedSingletonMapTemplate predicateTemplate; private final ValueContext keyContext; private final MethodHandle ctor; private final QName keyName; - SingleKey(final ListSchemaNode schema, final Class> keyClass, + SingleKey(final ListEffectiveStatement schema, final Class> keyClass, final Class identifiable, final QName keyName, final ValueContext keyContext) { super(schema, keyClass, identifiable); this.keyContext = requireNonNull(keyContext); this.keyName = requireNonNull(keyName); - predicateTemplate = SharedSingletonMapTemplate.ordered(keyName); - ctor = getConstructor(keyClass).asType(CTOR_TYPE); + ctor = getConstructor(keyClass, 1).asType(CTOR_TYPE); } @Override - Identifier deserializeIdentifier(final Map keyValues) throws Throwable { - return (Identifier) ctor.invokeExact(keyContext.deserialize(keyValues.get(keyName))); + Identifier deserializeIdentifierImpl(final NodeIdentifierWithPredicates nip) throws Throwable { + return (Identifier) ctor.invokeExact(keyContext.deserialize(nip.getValue(keyName))); } @Override NodeIdentifierWithPredicates serializeIdentifier(final QName qname, final Identifier key) { - return NodeIdentifierWithPredicates.of(qname, predicateTemplate.instantiateWithValue( - keyContext.getAndSerialize(key))); + return NodeIdentifierWithPredicates.of(qname, keyName, keyContext.getAndSerialize(key)); } } @@ -72,19 +72,20 @@ abstract class IdentifiableItemCodec implements Codec keysInBindingOrder; private final MethodHandle ctor; - MultiKey(final ListSchemaNode schema, final Class> keyClass, + MultiKey(final ListEffectiveStatement schema, final Class> keyClass, final Class identifiable, final Map keyValueContexts) { super(schema, keyClass, identifiable); - final MethodHandle tmpCtor = getConstructor(keyClass); + final MethodHandle tmpCtor = getConstructor(keyClass, keyValueContexts.size()); final MethodHandle inv = MethodHandles.spreadInvoker(tmpCtor.type(), 0); - this.ctor = inv.asType(inv.type().changeReturnType(Identifier.class)).bindTo(tmpCtor); + ctor = inv.asType(inv.type().changeReturnType(Identifier.class)).bindTo(tmpCtor); /* * We need to re-index to make sure we instantiate nodes in the order in which they are defined. We will * also need to instantiate values in the same order. */ - final List keyDef = schema.getKeyDefinition(); + final Set keyDef = schema.findFirstEffectiveSubstatementArgument(KeyEffectiveStatement.class) + .orElseThrow(); predicateTemplate = ImmutableOffsetMapTemplate.ordered(keyDef); this.keyValueContexts = predicateTemplate.instantiateTransformed(keyValueContexts, (key, value) -> value); @@ -97,15 +98,15 @@ abstract class IdentifiableItemCodec implements Codec tmp = new ArrayList<>(keyDef); // This is not terribly efficient but gets the job done tmp.sort(Comparator.comparing(qname -> BindingMapping.getPropertyName(qname.getLocalName()))); - this.keysInBindingOrder = ImmutableList.copyOf(tmp.equals(keyDef) ? keyDef : tmp); + keysInBindingOrder = ImmutableList.copyOf(tmp.equals(List.copyOf(keyDef)) ? keyDef : tmp); } @Override - Identifier deserializeIdentifier(final Map keyValues) throws Throwable { + Identifier deserializeIdentifierImpl(final NodeIdentifierWithPredicates nip) throws Throwable { final Object[] bindingValues = new Object[keysInBindingOrder.size()]; int offset = 0; for (final QName key : keysInBindingOrder) { - bindingValues[offset++] = keyValueContexts.get(key).deserialize(keyValues.get(key)); + bindingValues[offset++] = keyValueContexts.get(key).deserialize(nip.getValue(key)); } return (Identifier) ctor.invokeExact(bindingValues); @@ -123,16 +124,18 @@ abstract class IdentifiableItemCodec implements Codec identifiable; private final QName qname; - IdentifiableItemCodec(final ListSchemaNode schema, final Class> keyClass, + IdentifiableItemCodec(final ListEffectiveStatement schema, final Class> keyClass, final Class identifiable) { this.identifiable = requireNonNull(identifiable); - this.qname = schema.getQName(); + qname = schema.argument(); } - static IdentifiableItemCodec of(final ListSchemaNode schema, + static IdentifiableItemCodec of(final ListEffectiveStatement schema, final Class> keyClass, final Class identifiable, final Map keyValueContexts) { switch (keyValueContexts.size()) { @@ -146,22 +149,19 @@ abstract class IdentifiableItemCodec implements Codec deserialize(final NodeIdentifierWithPredicates input) { - final Identifier identifier = deserializeIdentifier(input); - return IdentifiableItem.of((Class) identifiable, (Identifier) identifier); + @SuppressWarnings({ "rawtypes", "unchecked" }) + final @NonNull IdentifiableItem domToBinding(final NodeIdentifierWithPredicates input) { + return IdentifiableItem.of((Class) identifiable, (Identifier) deserializeIdentifier(requireNonNull(input))); } - @Override - public final NodeIdentifierWithPredicates serialize(final IdentifiableItem input) { + final @NonNull NodeIdentifierWithPredicates bindingToDom(final IdentifiableItem input) { return serializeIdentifier(qname, input.getKey()); } @SuppressWarnings("checkstyle:illegalCatch") - final @NonNull Identifier deserializeIdentifier(final NodeIdentifierWithPredicates input) { + final @NonNull Identifier deserializeIdentifier(final @NonNull NodeIdentifierWithPredicates input) { try { - return deserializeIdentifier(input.getKeyValues()); + return deserializeIdentifierImpl(input); } catch (Throwable e) { Throwables.throwIfUnchecked(e); throw new IllegalStateException("Failed to deserialize " + input, e); @@ -169,22 +169,42 @@ abstract class IdentifiableItemCodec implements Codec deserializeIdentifier(Map keyValues) throws Throwable; + abstract @NonNull Identifier deserializeIdentifierImpl(@NonNull NodeIdentifierWithPredicates nip) + throws Throwable; abstract @NonNull NodeIdentifierWithPredicates serializeIdentifier(QName qname, Identifier key); - static MethodHandle getConstructor(final Class> clazz) { - for (@SuppressWarnings("rawtypes") final Constructor constr : clazz.getConstructors()) { - final Class[] parameters = constr.getParameterTypes(); - if (!clazz.equals(parameters[0])) { - // It is not copy constructor; - try { - return MethodHandles.publicLookup().unreflectConstructor(constr); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Cannot access constructor " + constr + " in class " + clazz, e); - } + static MethodHandle getConstructor(final Class> clazz, final int nrArgs) { + for (final Constructor ctor : clazz.getConstructors()) { + // Check argument count + if (ctor.getParameterCount() != nrArgs) { + LOG.debug("Skipping {} due to argument count mismatch", ctor); + continue; + } + + // Do not consider deprecated constructors + if (isDeprecated(ctor)) { + LOG.debug("Skipping deprecated constructor {}", ctor); + continue; + } + + // Do not consider copy constructors + if (clazz.equals(ctor.getParameterTypes()[0])) { + LOG.debug("Skipping copy constructor {}", ctor); + continue; + } + + try { + return MethodHandles.publicLookup().unreflectConstructor(ctor); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Cannot access constructor " + ctor + " in class " + clazz, e); } } - throw new IllegalArgumentException("Supplied class " + clazz + "does not have required constructor."); + throw new IllegalArgumentException("Supplied class " + clazz + " does not have required constructor."); + } + + // This could be inlined, but then it throws off Eclipse analysis, which thinks the return is always non-null + private static boolean isDeprecated(final Constructor ctor) { + return ctor.getAnnotation(Deprecated.class) != null; } }