import static com.google.common.base.Verify.verify;
import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
-import static org.opendaylight.mdsal.binding.dom.codec.impl.ByteBuddyUtils.THIS;
+import static net.bytebuddy.implementation.bytecode.member.MethodVariableAccess.loadThis;
import static org.opendaylight.mdsal.binding.dom.codec.impl.ByteBuddyUtils.getField;
import static org.opendaylight.mdsal.binding.dom.codec.impl.ByteBuddyUtils.invokeMethod;
import static org.opendaylight.mdsal.binding.dom.codec.impl.ByteBuddyUtils.putField;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Objects;
import java.util.Optional;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
import net.bytebuddy.implementation.bytecode.constant.ClassConstant;
-import net.bytebuddy.implementation.bytecode.constant.IntegerConstant;
import net.bytebuddy.implementation.bytecode.constant.TextConstant;
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
-import net.bytebuddy.jar.asm.Label;
import net.bytebuddy.jar.asm.Opcodes;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.binding.dom.codec.impl.ClassGeneratorBridge.LocalNameProvider;
import org.opendaylight.mdsal.binding.dom.codec.impl.ClassGeneratorBridge.NodeContextSupplierProvider;
-import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader;
-import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader.ClassGenerator;
-import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader.GeneratorResult;
+import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader;
+import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.ClassGenerator;
+import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.GeneratorResult;
import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.slf4j.Logger;
* private static final VarHandle getBar$$$V;
* private volatile Object getBar;
*
- * public Foo$$$codecImpl(NormalizedNodeContainer data) {
+ * public Foo$$$codecImpl(DistinctNodeContainer data) {
* super(data);
* }
*
*/
abstract class CodecDataObjectGenerator<T extends CodecDataObject<?>> implements ClassGenerator<T> {
// Not reusable definition: we can inline NodeContextSuppliers without a problem
- // FIXME: 6.0.0: wire this implementation, which requires that BindingRuntimeTypes provides information about types
- // being generated from within a grouping
+ // FIXME: MDSAL-443: wire this implementation, which requires that BindingRuntimeTypes provides information about
+ // types being generated from within a grouping
private static final class Fixed<T extends CodecDataObject<?>> extends CodecDataObjectGenerator<T>
implements NodeContextSupplierProvider<T> {
private final ImmutableMap<Method, NodeContextSupplier> properties;
return tmp;
}
- @Override
- ArrayList<Method> getterMethods() {
- return new ArrayList<>(properties.keySet());
- }
-
@Override
public NodeContextSupplier resolveNodeContextSupplier(final String methodName) {
final Optional<Entry<Method, NodeContextSupplier>> found = properties.entrySet().stream()
return tmp;
}
- @Override
- ArrayList<Method> getterMethods() {
- final ArrayList<Method> ret = new ArrayList<>(simpleProperties.size() + daoProperties.size());
- ret.addAll(simpleProperties.keySet());
- ret.addAll(daoProperties.keySet());
- return ret;
- }
-
@Override
public String resolveLocalName(final String methodName) {
final Optional<Entry<Method, ValueNodeCodecContext>> found = simpleProperties.entrySet().stream()
private static final Logger LOG = LoggerFactory.getLogger(CodecDataObjectGenerator.class);
private static final Generic BB_BOOLEAN = TypeDefinition.Sort.describe(boolean.class);
- private static final Generic BB_DATAOBJECT = TypeDefinition.Sort.describe(DataObject.class);
+ private static final Generic BB_OBJECT = TypeDefinition.Sort.describe(Object.class);
private static final Generic BB_INT = TypeDefinition.Sort.describe(int.class);
private static final Generic BB_STRING = TypeDefinition.Sort.describe(String.class);
private static final TypeDescription BB_CDO = ForLoadedType.of(CodecDataObject.class);
private static final TypeDescription BB_ACDO = ForLoadedType.of(AugmentableCodecDataObject.class);
- private static final Comparator<Method> METHOD_BY_ALPHABET = Comparator.comparing(Method::getName);
- private static final StackManipulation ARRAYS_EQUALS = invokeMethod(Arrays.class, "equals",
- byte[].class, byte[].class);
- private static final StackManipulation OBJECTS_EQUALS = invokeMethod(Objects.class, "equals",
- Object.class, Object.class);
private static final StackManipulation FIRST_ARG_REF = MethodVariableAccess.REFERENCE.loadFrom(1);
private static final int PROT_FINAL = Opcodes.ACC_PROTECTED | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC;
final Generic bindingDef = TypeDefinition.Sort.describe(bindingInterface);
@SuppressWarnings("unchecked")
Builder<T> builder = (Builder<T>) BB.subclass(Generic.Builder.parameterizedType(superClass, bindingDef).build())
- .visit(ByteBuddyUtils.computeFrames()).name(fqcn).implement(bindingDef);
+ .name(fqcn).implement(bindingDef);
builder = generateGetters(builder);
new KeyMethodImplementation(methodName, retType));
}
- // Index all property methods, turning them into "getFoo()" invocations, retaining order. We will be using
- // those invocations in each of the three methods. Note that we do not glue the invocations to 'this', as we
- // will be invoking them on 'other' in codecEquals()
- final ArrayList<Method> properties = getterMethods();
- // Make sure properties are alpha-sorted
- properties.sort(METHOD_BY_ALPHABET);
- final ImmutableMap<StackManipulation, Method> methods = Maps.uniqueIndex(properties,
- ByteBuddyUtils::invokeMethod);
-
// Final bits:
return GeneratorResult.of(builder
// codecHashCode() ...
.defineMethod("codecHashCode", BB_INT, PROT_FINAL)
.intercept(codecHashCode(bindingInterface))
- // ... codecEquals() ...
- .defineMethod("codecEquals", BB_BOOLEAN, PROT_FINAL).withParameter(BB_DATAOBJECT)
- .intercept(codecEquals(methods))
+ // ... equals(Object) ...
+ .defineMethod("codecEquals", BB_BOOLEAN, PROT_FINAL).withParameter(BB_OBJECT)
+ .intercept(codecEquals(bindingInterface))
// ... toString() ...
.defineMethod("toString", BB_STRING, PUB_FINAL)
.intercept(toString(bindingInterface))
abstract Builder<T> generateGetters(Builder<T> builder);
- abstract ArrayList<Method> getterMethods();
-
- private static Implementation codecEquals(final ImmutableMap<StackManipulation, Method> properties) {
- // Label for 'return false;'
- final Label falseLabel = new Label();
- // Condition for 'if (!...)'
- final StackManipulation ifFalse = ByteBuddyUtils.ifEq(falseLabel);
-
- final List<StackManipulation> manipulations = new ArrayList<>(properties.size() * 6 + 5);
- for (Entry<StackManipulation, Method> entry : properties.entrySet()) {
- // if (!java.util.(Objects|Arrays).equals(getFoo(), other.getFoo())) {
- // return false;
- // }
- manipulations.add(THIS);
- manipulations.add(entry.getKey());
- manipulations.add(FIRST_ARG_REF);
- manipulations.add(entry.getKey());
- manipulations.add(entry.getValue().getReturnType().isArray() ? ARRAYS_EQUALS : OBJECTS_EQUALS);
- manipulations.add(ifFalse);
- }
-
- // return true;
- manipulations.add(IntegerConstant.ONE);
- manipulations.add(MethodReturn.INTEGER);
- // L0: return false;
- manipulations.add(ByteBuddyUtils.markLabel(falseLabel));
- manipulations.add(IntegerConstant.ZERO);
- manipulations.add(MethodReturn.INTEGER);
-
- return new Implementation.Simple(manipulations.toArray(new StackManipulation[0]));
- }
-
private static Implementation codecHashCode(final Class<?> bindingInterface) {
return new Implementation.Simple(
// return Foo.bindingHashCode(this);
- THIS,
+ loadThis(),
invokeMethod(bindingInterface, BindingMapping.BINDING_HASHCODE_NAME, bindingInterface),
MethodReturn.INTEGER);
}
+ private static Implementation codecEquals(final Class<?> bindingInterface) {
+ return new Implementation.Simple(
+ // return Foo.bindingEquals(this, obj);
+ loadThis(),
+ FIRST_ARG_REF,
+ invokeMethod(bindingInterface, BindingMapping.BINDING_EQUALS_NAME, bindingInterface, Object.class),
+ MethodReturn.INTEGER);
+ }
+
private static Implementation toString(final Class<?> bindingInterface) {
return new Implementation.Simple(
// return Foo.bindingToString(this);
- THIS,
+ loadThis(),
invokeMethod(bindingInterface, BindingMapping.BINDING_TO_STRING_NAME, bindingInterface),
MethodReturn.REFERENCE);
}
public ByteCodeAppender appender(final Target implementationTarget) {
return new ByteCodeAppender.Simple(
// return (FooType) codecKey(getFoo$$$V);
- THIS,
+ loadThis(),
getField(implementationTarget.getInstrumentedType(), handleName),
CODEC_KEY,
TypeCasting.to(retType),
final TypeDescription instrumentedType = implementationTarget.getInstrumentedType();
return new ByteCodeAppender.Simple(
// return (FooType) codecMember(getFoo$$$V, getFoo$$$S);
- THIS,
+ loadThis(),
getField(instrumentedType, handleName),
getField(instrumentedType, stringName),
CODEC_MEMBER,
public ByteCodeAppender appender(final Target implementationTarget) {
return new ByteCodeAppender.Simple(
// return (FooType) codecMember(getFoo$$$V, FooType.class);
- THIS,
+ loadThis(),
getField(implementationTarget.getInstrumentedType(), handleName),
ClassConstant.of(TypeDefinition.Sort.describe(bindingClass).asErasure()),
CODEC_MEMBER,
final TypeDescription instrumentedType = implementationTarget.getInstrumentedType();
return new ByteCodeAppender.Simple(
// return (FooType) codecMember(getFoo$$$V, getFoo$$$C);
- THIS,
+ loadThis(),
getField(instrumentedType, handleName),
getField(instrumentedType, contextName),
CODEC_MEMBER,