import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
-
import java.io.IOException;
import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
-
import org.opendaylight.yangtools.concepts.Builder;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.concepts.Path;
*
*/
public class InstanceIdentifier<T extends DataObject> implements Path<InstanceIdentifier<? extends DataObject>>, Immutable, Serializable {
- private static final long serialVersionUID = 1L;
+ private static final Field PATHARGUMENTS_FIELD;
+ private static final long serialVersionUID = 2L;
/*
* Protected to differentiate internal and external access. Internal
* access is required never to modify the contents. References passed
* to outside entities have to be wrapped in an unmodifiable view.
*/
- protected final Iterable<PathArgument> pathArguments;
+ protected transient final Iterable<PathArgument> pathArguments;
private final Class<T> targetType;
private final boolean wildcarded;
private final int hash;
+ static {
+ final Field f;
+ try {
+ f = InstanceIdentifier.class.getDeclaredField("pathArguments");
+ } catch (NoSuchFieldException | SecurityException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ f.setAccessible(true);
+ PATHARGUMENTS_FIELD = f;
+ }
+
InstanceIdentifier(final Class<T> type, final Iterable<PathArgument> pathArguments, final boolean wildcarded, final int hash) {
this.pathArguments = Preconditions.checkNotNull(pathArguments);
this.targetType = Preconditions.checkNotNull(type);
}
private void writeObject(final java.io.ObjectOutputStream out) throws IOException {
- out.writeObject(targetType);
- out.writeBoolean(wildcarded);
- out.writeInt(hash);
- out.write(Iterables.size(pathArguments));
+ out.defaultWriteObject();
+ out.writeInt(Iterables.size(pathArguments));
for (Object o : pathArguments) {
out.writeObject(o);
}
}
private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
- // TODO Auto-generated method stub
+ in.defaultReadObject();
+
+ final int size = in.readInt();
+ final List<PathArgument> args = new ArrayList<>(size);
+ for (int i = 0; i < size; ++i) {
+ args.add((PathArgument) in.readObject());
+ }
+
+ try {
+ PATHARGUMENTS_FIELD.set(this, ImmutableList.copyOf(args));
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new IOException(e);
+ }
}
}
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, String> TOSTRINGCACHE_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, String.class, "toStringCache");
private static final YangInstanceIdentifier EMPTY = trustedCreate(Collections.<PathArgument>emptyList());
+ private static final Field PATHARGUMENTS_FIELD;
- private static final long serialVersionUID = 2L;
- private final Iterable<PathArgument> pathArguments;
+ private static final long serialVersionUID = 3L;
+ private transient final Iterable<PathArgument> pathArguments;
private final int hash;
- private transient volatile ImmutableList<PathArgument> legacyPath = null;
+ private volatile ImmutableList<PathArgument> legacyPath = null;
private transient volatile String toStringCache = null;
+ static {
+ final Field f;
+ try {
+ f = YangInstanceIdentifier.class.getDeclaredField("pathArguments");
+ } catch (NoSuchFieldException | SecurityException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ f.setAccessible(true);
+
+ PATHARGUMENTS_FIELD = f;
+ }
+
private final ImmutableList<PathArgument> getLegacyPath() {
// Temporary variable saves a volatile read
ImmutableList<PathArgument> ret = legacyPath;
}
return ret;
}
+
+ private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
+ inputStream.defaultReadObject();
+
+ try {
+ PATHARGUMENTS_FIELD.set(this, legacyPath);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private void writeObject(final ObjectOutputStream outputStream) throws IOException {
+ /*
+ * This may look strange, but what we are doing here is side-stepping the fact
+ * that pathArguments is not generally serializable. We are forcing instantiation
+ * of the legacy path, which is an ImmutableList (thus Serializable) and write
+ * it out. The read path does the opposite -- it reads the legacyPath and then
+ * uses invocation API to set the field.
+ */
+ getLegacyPath();
+ outputStream.defaultWriteObject();
+ }
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map.Entry;
-
import org.junit.Test;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
assertNotNull( node1.toString() ); // for code coverage
}
+
+ @Test
+ public void serializationTest() throws IOException, ClassNotFoundException {
+ final YangInstanceIdentifier expected = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1), new NodeIdentifier(nodeName2));
+
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final ObjectOutputStream oos = new ObjectOutputStream(bos);
+ oos.writeObject(expected);
+ oos.close();
+
+ final byte[] bytes = bos.toByteArray();
+ final ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ final ObjectInputStream ois = new ObjectInputStream(bis);
+
+ final YangInstanceIdentifier read = (YangInstanceIdentifier) ois.readObject();
+ assertEquals(0, ois.available());
+ ois.close();
+
+ assertEquals(expected, read);
+ }
}