import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Optional;
}
@Override
- @SuppressFBWarnings(value = "EQ_UNUSUAL", justification = "State is examined indirectly enough to confuse SpotBugs")
public final boolean equals(final Object obj) {
- if (obj == this) {
- return true;
- }
- final Class<? extends DataObject> iface = implementedInterface();
- if (!iface.isInstance(obj)) {
- return false;
- }
- @SuppressWarnings("unchecked")
- final T other = (T) iface.cast(obj);
- // Note: we do not want to compare NormalizedNode data here, as we may be looking at different instantiations
- // of the same grouping -- in which case normalized node will not compare as equal.
- return codecAugmentedEquals(other);
+ // Indirection to keep checkstyle happy
+ return codecEquals(obj);
}
@Override
protected abstract int codecHashCode();
- protected abstract boolean codecEquals(T other);
+ protected abstract boolean codecEquals(Object obj);
final @NonNull DataObjectCodecContext<T, ?> codecContext() {
return context;
return data;
}
- // Non-final to allow specialization in AugmentableCodecDataObject
- boolean codecAugmentedEquals(final T other) {
- return codecEquals(other);
- }
-
// Helper split out of codecMember to aid its inlining
private Object loadMember(final VarHandle handle, final NodeCodecContext childCtx) {
@SuppressWarnings("unchecked")
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;
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;
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);
MethodReturn.INTEGER);
}
+ private static Implementation codecEquals(final Class<?> bindingInterface) {
+ return new Implementation.Simple(
+ // return Foo.bindingEquals(this, obj);
+ THIS,
+ 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);