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=f7ef432da873185892d7d356afd62fe11fc75d5d;hb=refs%2Fchanges%2F45%2F98245%2F100;hp=a7b03eedc529891ea8ac27d6cd466df0071037a8;hpb=2d845e74fe1f478c3ccc0aa63f8a3c9a15c4f75c;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 a7b03eedc5..f7ef432da8 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,6 +20,7 @@ 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.AbstractIllegalArgumentCodec; @@ -30,7 +31,10 @@ 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. @@ -44,17 +48,17 @@ abstract class IdentifiableItemCodec 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); - 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 @@ -69,19 +73,20 @@ abstract class IdentifiableItemCodec private final ImmutableList 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); @@ -94,15 +99,15 @@ abstract class IdentifiableItemCodec final List 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); @@ -120,16 +125,18 @@ abstract class IdentifiableItemCodec } } + private static final Logger LOG = LoggerFactory.getLogger(IdentifiableItemCodec.class); + private final Class 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()) { @@ -158,7 +165,7 @@ abstract class IdentifiableItemCodec @SuppressWarnings("checkstyle:illegalCatch") final @NonNull Identifier deserializeIdentifier(final NodeIdentifierWithPredicates input) { try { - return deserializeIdentifier(input.asMap()); + return deserializeIdentifierImpl(input); } catch (Throwable e) { Throwables.throwIfUnchecked(e); throw new IllegalStateException("Failed to deserialize " + input, e); @@ -166,22 +173,42 @@ abstract class IdentifiableItemCodec } @SuppressWarnings("checkstyle:illegalThrows") - abstract @NonNull Identifier 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; } }