--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecPrototype;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.TreeNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentation;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+
+/**
+ * Context for prototype of augmentation node.
+ */
+@Beta
+public final class AugmentationNodeContext<D extends TreeNode & Augmentation<?>>
+ extends TreeNodeCodecContext<D, AugmentationSchema> {
+
+ /**
+ * Prepare context for augmentation node from prototype.
+ *
+ * @param prototype
+ * - codec prototype of augmentation node
+ */
+ public AugmentationNodeContext(final DataContainerCodecPrototype<AugmentationSchema> prototype) {
+ super(prototype);
+ }
+
+ @Nonnull
+ @Override
+ public D deserialize(@Nonnull final NormalizedNode<?, ?> normalizedNode) {
+ Preconditions.checkArgument(normalizedNode instanceof AugmentationNode);
+ return createBindingProxy((AugmentationNode) normalizedNode);
+ }
+
+ @Override
+ protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
+ return deserialize(normalizedNode);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecContext;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecPrototype;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.NodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Instantiable;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Context for prototype of choice node codec.
+ *
+ * @param <D>
+ * - type of tree node
+ */
+@Beta
+public class ChoiceNodeCodecContext<D extends TreeNode> extends DataContainerCodecContext<D, ChoiceSchemaNode> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ChoiceNodeCodecContext.class);
+
+ private final ImmutableMap<YangInstanceIdentifier.PathArgument, DataContainerCodecPrototype<?>> byYangCaseChild;
+ private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byClass;
+ private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClass;
+
+ /**
+ * Prepare context for choice node from prototype and all case children of choice class.
+ *
+ * @param prototype
+ * - codec prototype of choice node
+ */
+ public ChoiceNodeCodecContext(final DataContainerCodecPrototype<ChoiceSchemaNode> prototype) {
+ super(prototype);
+ final Map<YangInstanceIdentifier.PathArgument, DataContainerCodecPrototype<?>> byYangCaseChildBuilder =
+ new HashMap<>();
+ final Map<Class<?>, DataContainerCodecPrototype<?>> byClassBuilder = new HashMap<>();
+ final Map<Class<?>, DataContainerCodecPrototype<?>> byCaseChildClassBuilder = new HashMap<>();
+ final Set<Class<?>> potentialSubstitutions = new HashSet<>();
+ // Walks all cases for supplied choice in current runtime context
+ for (final Class<?> caze : factory().getRuntimeContext().getCases(getBindingClass())) {
+ // We try to load case using exact match thus name
+ // and original schema must equals
+ final DataContainerCodecPrototype<ChoiceCaseNode> cazeDef = loadCase(caze);
+ // If we have case definition, this case is instantiated
+ // at current location and thus is valid in context of parent choice
+ if (cazeDef != null) {
+ byClassBuilder.put(cazeDef.getBindingClass(), cazeDef);
+ // Updates collection of case children
+ @SuppressWarnings("unchecked")
+ final Class<? extends Instantiable<?>> cazeCls = (Class<? extends Instantiable<?>>) caze;
+ for (final Class<? extends TreeNode> cazeChild : BindingReflections.getChildrenClasses(cazeCls)) {
+ byCaseChildClassBuilder.put(cazeChild, cazeDef);
+ }
+ // Updates collection of YANG instance identifier to case
+ for (final DataSchemaNode cazeChild : cazeDef.getSchema().getChildNodes()) {
+ if (cazeChild.isAugmenting()) {
+ final AugmentationSchema augment =
+ SchemaUtils.findCorrespondingAugment(cazeDef.getSchema(), cazeChild);
+ if (augment != null) {
+ byYangCaseChildBuilder.put(SchemaUtils.getNodeIdentifierForAugmentation(augment), cazeDef);
+ continue;
+ }
+ }
+ byYangCaseChildBuilder.put(NodeIdentifier.create(cazeChild.getQName()), cazeDef);
+ }
+ } else {
+ /*
+ * If case definition is not available, we store it for later check if it could be used as
+ * substitution of existing one.
+ */
+ potentialSubstitutions.add(caze);
+ }
+ }
+
+ final Map<Class<?>, DataContainerCodecPrototype<?>> bySubstitutionBuilder = new HashMap<>();
+ /*
+ * Walks all cases which are not directly instantiated and tries to match them to instantiated cases -
+ * represent same data as instantiated case, only case name or schema path is different. This is
+ * required due property of binding specification, that if choice is in grouping schema path location
+ * is lost, and users may use incorrect case class using copy builders.
+ */
+ for (final Class<?> substitution : potentialSubstitutions) {
+ for (final Entry<Class<?>, DataContainerCodecPrototype<?>> real : byClassBuilder.entrySet()) {
+ if (BindingReflections.isSubstitutionFor(substitution, real.getKey())) {
+ bySubstitutionBuilder.put(substitution, real.getValue());
+ break;
+ }
+ }
+ }
+ byClassBuilder.putAll(bySubstitutionBuilder);
+ byYangCaseChild = ImmutableMap.copyOf(byYangCaseChildBuilder);
+ byClass = ImmutableMap.copyOf(byClassBuilder);
+ byCaseChildClass = ImmutableMap.copyOf(byCaseChildClassBuilder);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nonnull
+ @Override
+ public <DV extends TreeNode> DataContainerCodecContext<DV, ?> streamChild(@Nonnull final Class<DV> childClass) {
+ final DataContainerCodecPrototype<?> child = byClass.get(childClass);
+ return (DataContainerCodecContext<DV,
+ ?>) childNonNull(child, childClass, "Supplied class %s is not valid case", childClass).get();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <DV extends TreeNode> Optional<DataContainerCodecContext<DV, ?>>
+ possibleStreamChild(@Nonnull final Class<DV> childClass) {
+ final DataContainerCodecPrototype<?> child = byClass.get(childClass);
+ if (child != null) {
+ return Optional.of((DataContainerCodecContext<DV, ?>) child.get());
+ }
+ return Optional.absent();
+ }
+
+ Iterable<Class<?>> getCaseChildrenClasses() {
+ return byCaseChildClass.keySet();
+ }
+
+ private DataContainerCodecPrototype<ChoiceCaseNode> loadCase(final Class<?> childClass) {
+ final Optional<ChoiceCaseNode> childSchema =
+ factory().getRuntimeContext().getCaseSchemaDefinition(getSchema(), childClass);
+ if (childSchema.isPresent()) {
+ return DataContainerCodecPrototype.from(childClass, childSchema.get(), factory());
+ }
+
+ LOG.debug("Supplied class %s is not valid case in schema %s", childClass, getSchema());
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public NodeCodecContext<?> yangPathArgumentChild(final YangInstanceIdentifier.PathArgument arg) {
+ final DataContainerCodecPrototype<?> cazeProto;
+ if (arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
+ cazeProto = byYangCaseChild.get(new NodeIdentifier(arg.getNodeType()));
+ } else {
+ cazeProto = byYangCaseChild.get(arg);
+ }
+
+ return childNonNull(cazeProto, arg, "Argument %s is not valid child of %s", arg, getSchema()).get()
+ .yangPathArgumentChild(arg);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nonnull
+ @Override
+ public D deserialize(@Nonnull final NormalizedNode<?, ?> data) {
+ Preconditions.checkArgument(data instanceof ChoiceNode);
+ final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> casted =
+ (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) data;
+ final NormalizedNode<?, ?> first = Iterables.getFirst(casted.getValue(), null);
+
+ if (first == null) {
+ return null;
+ }
+ final DataContainerCodecPrototype<?> caze = byYangCaseChild.get(first.getIdentifier());
+ return (D) caze.get().deserialize(data);
+ }
+
+ @Override
+ protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
+ return deserialize(normalizedNode);
+ }
+
+ @Nonnull
+ @Override
+ public TreeArgument<?> deserializePathArgument(@Nonnull final YangInstanceIdentifier.PathArgument arg) {
+ Preconditions.checkArgument(getDomPathArgument().equals(arg));
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public YangInstanceIdentifier.PathArgument serializePathArgument(@Nonnull final TreeArgument<?> arg) {
+ return getDomPathArgument();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.DataContainerCodecPrototype;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.TreeNodeCodecContext;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Notification;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+
+/**
+ * Context for prototype of notification.
+ *
+ * @param <D>
+ * - type of tree node
+ */
+@SuppressWarnings("rawtypes")
+@Beta
+public final class NotificationCodecContext<D extends TreeNode & Notification>
+ extends TreeNodeCodecContext<D, NotificationDefinition> {
+
+ /**
+ * Prepare context for notification from prototype.
+ *
+ * @param key
+ * - binding class
+ * @param schema
+ * - schema of notification
+ * @param factory
+ * - codec context factory
+ */
+ public NotificationCodecContext(final Class<?> key, final NotificationDefinition schema,
+ final CodecContextFactory factory) {
+ super(DataContainerCodecPrototype.from(key, schema, factory));
+ }
+
+ @Nonnull
+ @Override
+ public D deserialize(@Nonnull final NormalizedNode<?, ?> data) {
+ Preconditions.checkState(data instanceof ContainerNode);
+ return createBindingProxy((NormalizedNodeContainer<?, ?, ?>) data);
+ }
+
+ @Override
+ protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
+ return deserialize(normalizedNode);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.value.EncapsulatedValueCodec;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Context for serializing input value of union type and deserializing objects to binding.
+ *
+ */
+@Beta
+public class UnionValueOptionContext {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UnionValueOptionContext.class);
+
+ private static final MethodType OBJECT_TYPE = MethodType.methodType(Object.class, Object.class);
+
+ private final Class<?> bindingType;
+ private final Codec<Object, Object> codec;
+ private final MethodHandle getter;
+ private final MethodHandle unionCtor;
+
+ /**
+ * Prepare union as binding object and codec for this object, make a direct method handle of getting union
+ * type and constructor of union type for initializing it.
+ *
+ * @param unionType
+ * - union as binding object
+ * @param valueType
+ * - returned type of union
+ * @param getter
+ * - method for getting union type
+ * @param codec
+ * - codec for serialize/deserialize type of union
+ */
+ public UnionValueOptionContext(final Class<?> unionType, final Class<?> valueType, final Method getter,
+ final Codec<Object, Object> codec) {
+ this.bindingType = Preconditions.checkNotNull(valueType);
+ this.codec = Preconditions.checkNotNull(codec);
+
+ try {
+ this.getter = MethodHandles.publicLookup().unreflect(getter).asType(OBJECT_TYPE);
+ } catch (final IllegalAccessException e) {
+ throw new IllegalStateException("Failed to access method " + getter, e);
+ }
+
+ try {
+ this.unionCtor = MethodHandles.publicLookup()
+ .findConstructor(unionType, MethodType.methodType(void.class, valueType)).asType(OBJECT_TYPE);
+ } catch (IllegalAccessException | NoSuchMethodException e) {
+ throw new IllegalStateException(
+ String.format("Failed to access constructor for %s in type %s", valueType, unionType), e);
+ }
+ }
+
+ /**
+ * Serialize input based on prepared codec.
+ *
+ * @param input
+ * - object to serialize
+ * @return serialized objetc
+ */
+ public Object serialize(final Object input) {
+ final Object baValue = getValueFrom(input);
+ return baValue == null ? null : codec.serialize(baValue);
+ }
+
+ /**
+ * Deserialize input object via prepared codec for invoking new object of union as binding.
+ *
+ * @param input
+ * - input object for deserializing
+ * @return deserialized union binding type object
+ */
+ public Object deserializeUnion(final Object input) {
+ // Side-step potential exceptions by checking the type if it is available
+ if (codec instanceof EncapsulatedValueCodec && !((EncapsulatedValueCodec) codec).canAcceptObject(input)) {
+ return null;
+ }
+
+ final Object value;
+ try {
+ value = codec.deserialize(input);
+ } catch (final Exception e) {
+ LOG.debug("Codec {} failed to deserialize input {}", codec, input, e);
+ return null;
+ }
+
+ try {
+ return unionCtor.invokeExact(value);
+ } catch (final ClassCastException e) {
+ // This case can happen. e.g. NOOP_CODEC
+ LOG.debug("Failed to instantiate {} for input {} value {}", bindingType, input, value, e);
+ return null;
+ } catch (final Throwable e) {
+ throw new IllegalArgumentException("Failed to construct union for value " + value, e);
+ }
+ }
+
+ private Object getValueFrom(final Object input) {
+ try {
+ return getter.invokeExact(input);
+ } catch (final Throwable e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingType.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof UnionValueOptionContext)) {
+ return false;
+ }
+
+ final UnionValueOptionContext other = (UnionValueOptionContext) obj;
+ return bindingType.equals(other.bindingType);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base.LeafNodeCodecContext;
+import org.opendaylight.yangtools.concepts.Codec;
+
+/**
+ * Context for serialize/deserialize leaf.
+ */
+@Beta
+public final class ValueContext {
+
+ private static final MethodType OBJECT_METHOD = MethodType.methodType(Object.class, Object.class);
+ private final Codec<Object, Object> codec;
+ private final MethodHandle getter;
+ private final Class<?> identifier;
+ private final String getterName;
+
+ /**
+ * Prepare codec of leaf value and getter of binding leaf object for getting leaf.
+ *
+ * @param identifier
+ * - binding class
+ * @param leaf
+ * - leaf codec context
+ */
+ public ValueContext(final Class<?> identifier, final LeafNodeCodecContext<?> leaf) {
+ getterName = leaf.getGetter().getName();
+ try {
+ getter = MethodHandles.publicLookup().unreflect(identifier.getMethod(getterName)).asType(OBJECT_METHOD);
+ } catch (IllegalAccessException | NoSuchMethodException | SecurityException e) {
+ throw new IllegalStateException(String.format("Cannot find method %s in class %s", getterName, identifier), e);
+ }
+ this.identifier = identifier;
+ codec = leaf.getValueCodec();
+ }
+
+ /**
+ * Get object via invoking getter with input and serializes it by prepared codec of leaf.
+ *
+ * @param obj
+ * - input object
+ * @return serialized invoked object
+ */
+ public Object getAndSerialize(final Object obj) {
+ final Object value;
+ try {
+ value = getter.invokeExact(obj);
+ } catch (final Throwable e) {
+ throw Throwables.propagate(e);
+ }
+
+ Preconditions.checkArgument(value != null,
+ "All keys must be specified for %s. Missing key is %s. Supplied key is %s",
+ identifier, getterName, obj);
+ return codec.serialize(value);
+ }
+
+ /**
+ * Deserialize input object by prepared codec.
+ *
+ * @param obj
+ * - input object
+ * @return deserialized object
+ */
+ public Object deserialize(final Object obj) {
+ return codec.deserialize(obj);
+ }
+}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
- static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Class<?> cls, final T schema,
+ public static <T extends DataSchemaNode> DataContainerCodecPrototype<T> from(final Class<?> cls, final T schema,
final CodecContextFactory factory) {
return new DataContainerCodecPrototype(cls, NodeIdentifier.create(schema.getQName()), schema, factory);
}
- static DataContainerCodecPrototype<SchemaContext> rootPrototype(final CodecContextFactory factory) {
+ public static DataContainerCodecPrototype<SchemaContext> rootPrototype(final CodecContextFactory factory) {
final SchemaContext schema = factory.getRuntimeContext().getSchemaContext();
final NodeIdentifier arg = NodeIdentifier.create(schema.getQName());
return new DataContainerCodecPrototype<>(TreeRoot.class, arg, schema, factory);
return new DataContainerCodecPrototype(augClass, arg, schema, factory);
}
- static DataContainerCodecPrototype<NotificationDefinition> from(final Class<?> augClass, final NotificationDefinition schema, final CodecContextFactory factory) {
+ public static DataContainerCodecPrototype<NotificationDefinition> from(final Class<?> augClass,
+ final NotificationDefinition schema, final CodecContextFactory factory) {
final PathArgument arg = NodeIdentifier.create(schema.getQName());
return new DataContainerCodecPrototype<>(augClass, arg, schema, factory);
}
- protected T getSchema() {
+ public T getSchema() {
return schema;
}
return factory;
}
- protected Class<?> getBindingClass() {
+ public Class<?> getBindingClass() {
return bindingClass;
}
return this;
}
- final Method getGetter() {
+ public final Method getGetter() {
return getter;
}
* types, which are same as in NormalizedNode model.
*/
@Beta
-final class EncapsulatedValueCodec extends ReflectionBasedCodec implements SchemaUnawareCodec {
+public final class EncapsulatedValueCodec extends ReflectionBasedCodec implements SchemaUnawareCodec {
private static final Lookup LOOKUP = MethodHandles.publicLookup();
private static final MethodType OBJ_METHOD = MethodType.methodType(Object.class, Object.class);
* @param value Value to be checked
* @return True if the value can be encapsulated
*/
- boolean canAcceptObject(final Object value) {
+ public boolean canAcceptObject(final Object value) {
return valueType.isInstance(value);
}
@Override
- public Object deserialize(Object input) {
+ public Object deserialize(final Object input) {
try {
return constructor.invokeExact(input);
- } catch (Throwable e) {
+ } catch (final Throwable e) {
throw Throwables.propagate(e);
}
}
@Override
- public Object serialize(Object input) {
+ public Object serialize(final Object input) {
try {
return getter.invokeExact(input);
- } catch (Throwable e) {
+ } catch (final Throwable e) {
throw Throwables.propagate(e);
}
}