import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader;
import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader.Customizer;
import org.opendaylight.mdsal.binding.dom.codec.loader.StaticClassPool;
* Private support for generating AbstractDataObject specializations.
*/
final class CodecDataObjectCustomizer implements Customizer {
+ static final int KEY_OFFSET = -1;
+
private static final Logger LOG = LoggerFactory.getLogger(CodecDataObjectCustomizer.class);
private static final CtClass CT_ARFU = StaticClassPool.findClass(AtomicReferenceFieldUpdater.class);
private static final CtClass CT_BOOLEAN = StaticClassPool.findClass(boolean.class);
private static final CtClass[] TOSTRING_ARGS = new CtClass[] { CT_HELPER };
private final List<Method> properties;
- private final List<Method> methods;
+ private final Method keyMethod;
- CodecDataObjectCustomizer(final List<Method> properties, final List<Method> methods) {
+ CodecDataObjectCustomizer(final List<Method> properties, final @Nullable Method keyMethod) {
this.properties = requireNonNull(properties);
- this.methods = requireNonNull(methods);
+ this.keyMethod = keyMethod;
}
@Override
public List<Class<?>> customize(final CodecClassLoader loader, final CtClass bindingClass, final CtClass generated)
throws NotFoundException, CannotCompileException {
- final String classFqn = generated.getName();
+ // Generate members for all methods ...
+ LOG.trace("Generating class {}", generated.getName());
generated.addInterface(bindingClass);
- // Generate members for all methods ...
- LOG.trace("Generating class {}", classFqn);
- for (Method method : methods) {
- LOG.trace("Generating for method {}", method);
- final String methodName = method.getName();
- final String methodArfu = methodName + "$$$ARFU";
-
- // AtomicReferenceFieldUpdater ...
- final CtField arfuField = new CtField(CT_ARFU, methodArfu, generated);
- arfuField.setModifiers(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL);
- generated.addField(arfuField, new StringBuilder().append(CT_ARFU.getName()).append(".newUpdater(")
- .append(generated.getName()).append(".class, java.lang.Object.class, \"").append(methodName)
- .append("\")").toString());
-
- // ... corresponding volatile field ...
- final CtField field = new CtField(CT_OBJECT, methodName, generated);
- field.setModifiers(Modifier.PRIVATE | Modifier.VOLATILE);
- generated.addField(field);
-
- // ... and the getter
- final Class<?> retType = method.getReturnType();
- final CtMethod getter = new CtMethod(loader.findClass(retType), methodName, EMPTY_ARGS, generated);
- final String retName = retType.isArray() ? retType.getSimpleName() : retType.getName();
-
- getter.setBody(new StringBuilder()
- .append("{\n")
- .append("return (").append(retName).append(") codecMember(").append(methodArfu).append(", \"")
- .append(methodName).append("\");\n")
- .append('}').toString());
- getter.setModifiers(Modifier.PUBLIC | Modifier.FINAL);
- generated.addMethod(getter);
+ int offset = 0;
+ for (Method method : properties) {
+ generateMethod(loader, generated, method, offset++);
+ }
+ if (keyMethod != null) {
+ generateMethod(loader, generated, keyMethod, KEY_OFFSET);
}
// Final bits: codecHashCode() ...
.append('}').toString();
}
+ private static void generateMethod(final CodecClassLoader loader, final CtClass generated, final Method method,
+ final int offset) throws CannotCompileException, NotFoundException {
+ LOG.trace("Generating for method {}", method);
+ final String methodName = method.getName();
+ final String methodArfu = methodName + "$$$ARFU";
+
+ // AtomicReferenceFieldUpdater ...
+ final CtField arfuField = new CtField(CT_ARFU, methodArfu, generated);
+ arfuField.setModifiers(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL);
+ generated.addField(arfuField, new StringBuilder().append(CT_ARFU.getName()).append(".newUpdater(")
+ .append(generated.getName()).append(".class, java.lang.Object.class, \"").append(methodName)
+ .append("\")").toString());
+
+ // ... corresponding volatile field ...
+ final CtField field = new CtField(CT_OBJECT, methodName, generated);
+ field.setModifiers(Modifier.PRIVATE | Modifier.VOLATILE);
+ generated.addField(field);
+
+ // ... and the getter
+ final Class<?> retType = method.getReturnType();
+ final CtMethod getter = new CtMethod(loader.findClass(retType), methodName, EMPTY_ARGS, generated);
+ final String retName = retType.isArray() ? retType.getSimpleName() : retType.getName();
+
+ getter.setBody(new StringBuilder()
+ .append("{\n")
+ .append("return (").append(retName).append(") codecMember(").append(methodArfu).append(", ").append(offset)
+ .append(");\n")
+ .append('}').toString());
+ getter.setModifiers(Modifier.PUBLIC | Modifier.FINAL);
+ generated.addMethod(getter);
+ }
+
private static String utilClass(final Method method) {
// We can either have objects or byte[], we cannot have Object[]
return method.getReturnType().isArray() ? "Arrays" : "Objects";
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
private static final CtClass SUPERCLASS = StaticClassPool.findClass(CodecDataObject.class);
private static final CtClass AUGMENTABLE_SUPERCLASS = StaticClassPool.findClass(
AugmentableCodecDataObject.class);
+ private static final NodeContextSupplier[] EMPTY_METHODS = new NodeContextSupplier[0];
private final ImmutableMap<String, ValueNodeCodecContext> leafChild;
private final ImmutableMap<YangInstanceIdentifier.PathArgument, NodeContextSupplier> byYang;
- private final ImmutableMap<String, NodeContextSupplier> byMethod;
private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byStreamClass;
private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byBindingArgClass;
private final ImmutableMap<AugmentationIdentifier, Type> possibleAugmentations;
+ private final NodeContextSupplier[] byMethod;
private final MethodHandle proxyConstructor;
@SuppressWarnings("rawtypes")
private volatile ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> mismatchedAugmented = ImmutableMap.of();
- DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype, final Method... additionalMethods) {
+ DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype) {
+ this(prototype, null);
+ }
+
+ DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype, final @Nullable Method keyMethod) {
super(prototype);
final Class<D> bindingClass = getBindingClass();
}
}
- final int methodCount = tmpMethodToSupplier.size();
- final Builder<String, NodeContextSupplier> byMethodBuilder = ImmutableMap.builderWithExpectedSize(methodCount);
-
-
- final List<Method> properties = new ArrayList<>(methodCount);
- for (Entry<Method, NodeContextSupplier> entry : tmpMethodToSupplier.entrySet()) {
- final Method method = entry.getKey();
- properties.add(method);
- byMethodBuilder.put(method.getName(), entry.getValue());
- }
-
// Make sure properties are alpha-sorted
+ final List<Method> properties = new ArrayList<>(tmpMethodToSupplier.keySet());
properties.sort(METHOD_BY_ALPHABET);
+ if (!properties.isEmpty()) {
+ byMethod = new NodeContextSupplier[properties.size()];
+ int offset = 0;
+ for (Method prop : properties) {
+ byMethod[offset++] = verifyNotNull(tmpMethodToSupplier.get(prop));
+ }
+ } else {
+ byMethod = EMPTY_METHODS;
+ }
- this.byMethod = byMethodBuilder.build();
this.byYang = ImmutableMap.copyOf(byYangBuilder);
this.byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder);
byBindingArgClassBuilder.putAll(byStreamClass);
}
reloadAllAugmentations();
- final List<Method> methods;
- if (additionalMethods.length != 0) {
- methods = new ArrayList<>(properties.size() + 1);
- methods.addAll(properties);
- methods.addAll(Arrays.asList(additionalMethods));
- } else {
- methods = properties;
- }
-
final Class<?> generatedClass;
try {
generatedClass = prototype.getFactory().getLoader().generateSubclass(superClass, bindingClass, "codecImpl",
- new CodecDataObjectCustomizer(properties, methods));
+ new CodecDataObjectCustomizer(properties, keyMethod));
} catch (CannotCompileException | IOException | NotFoundException e) {
throw new LinkageError("Failed to generated class for " + bindingClass, e);
}
}
@SuppressWarnings("rawtypes")
- @Nullable Object getBindingChildValue(final String method, final NormalizedNodeContainer domData) {
- final NodeCodecContext childContext = verifyNotNull(byMethod.get(method),
- "Cannot find data handler for method %s", method).get();
+ @Nullable Object getBindingChildValue(final NormalizedNodeContainer domData, final int offset) {
+ final NodeCodecContext childContext = byMethod[offset].get();
@SuppressWarnings("unchecked")
final Optional<NormalizedNode<?, ?>> domChild = domData.getChild(childContext.getDomPathArgument());