[Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 318
  • Last Modified:

RMI Serialization and Collections

    Hello,

     since serialization creates new instances of an object, making sense
     of a serialized Collection seems difficult.  i have a need to put
     things in Sets or Lists and later, "across the wire", compare them
     against other Sets, Lists, or Objects.  anyone have advice on a
     (hopefully simple) way to do this in general?  for specifics, consider
     the following two classes (simplified and abbreviated) and output:
     --------------------------------------------------------------------------
     public class TestServerImpl extends UnicastRemoteObject implements
     TestServer, Serializable {

       // only used because Object doesn't implement Serializable...
       class SerialObject implements Serializable {}

       private SerialObject theObject;
       private Collection theSet;

       static public void main() {

         TestServer ts = new TestServerImpl()
         Naming.rebind("//host:port/testServer",testServer);
       
       }
       private TestServer() {
         theObject = new SerialObject();
         theSet = new HashSet();
         theSet.add(theObject);
       }
       // methods promised in TestServer interface
       public Object getObject() { return theObject; }
       public Collection getSet() { return theSet; }
     }
     ------------------------------------------------------------------
     public class Test {
       public static void main() {
         TestServer ts = (TestServer)
     Naming.lookup("//host:port/testServer");
         Object aThing = ts.getObject();
         Collection aSet = ts.getSet();
         System.out.println("thing is :"+aThing);
         System.out.println("set is :"+aSet);
         System.out.println("set contains thing? "+aSet.contains(aThing));
       }
     }
     ----------------------------------------------------------------------
     the output is what you'd expect, but not what you'd want.  something
     like:

     thing is :SerialObject@743399
     set is :[SerialObject@67b241]
     set contains thing? false

     i know readResolve() can be used to return an existing object instead
     of a new object from the deserialization process, but this seems an
     awfully bulky solution in general.  am i just way off base in my
     approach?

     thoughts?

     -don.
0
dddexter
Asked:
dddexter
  • 4
  • 3
  • 2
  • +1
1 Solution
 
pellepCommented:
Classes implementing Collection (and List) implements (or should implement, according the the spec)
Collection.contains(Object obj)
by iterating over the collection, calling
object.equals(obj) where object is the current object returned by the iterator.

So, by overriding equals(Object obj) from class Object, you can specify your own comparison routine
ie
class Bla {
private int iVal = 5;
public int getIVal() {
return iVal;
}
public boolean equals(Object o) {
if (obj intanceof Bla && ((Bla) obj).getIVal() == this.getIVal()) {
return true;
} else {
return false;
}
}
0
 
pellepCommented:
class Bla {
private int iVal = 5;
public int getIVal() {
return iVal;
}
public boolean equals(Object obj) {
if (obj intanceof Bla && ((Bla) obj).getIVal() == this.getIVal()) {
return true;
} else {
return false;
}
}
}

anyway
0
 
objectsCommented:
The default implementation of equals() provided by Object simply returns true of the tow objects are the same instance. ie. a==b.
Which in this case they aren't.
If theObject was a String or an Integer for example you would get the desired result.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
dddexterAuthor Commented:

i'm not convinced that implementing equals() (and hashCode()) is the way to go.  i received a similar response to the question on google, so perhaps i'm
just being beligerent....

BUT, suppose (as is the case in my app) that the objects
are mutable:
Mutable a = new Mutable(propertySetA);
Mutable b = new Mutable(propertySetB);
aSet.add(a);
// a==b false.  a.equals(b) false.  aSet.contains(b) false.
b.setProperties(a.getProperties())
// a==b false.  a.equals(b) true?  aSet.contains(b) true?
a.setProperties(propertySetB);
// a==b false.  a.equals(b) false? aSet.contains(a) false?


further, if there are no obvious fields that clearly
define equals(), one would need to do something like add
a uniqueId field as sort of a "key" to *every* class that
is to be serialized. this seems bulky and non-intuitive.
what do we do for classes provided by sun which may not
override equals()?  subclass or wrap each one in order
to serialize it?  seems messy.

Summary:
on the server-side we can easily share references for any object w/o any extra coding...just assign a variable.
is there no way to, in general, deserialize the *same* object (a single reference)to two variables and compare
them as equal?  i'm beginning to doubt it, but it seems suspect.

thanks for your input,

-don.
0
 
dddexterAuthor Commented:
Ok, I give.

guess my unfamiliarity w/ serialization was really the underlying problem.
i just couldn't get it through my thick skull that a single object serialized and
deserialized twice to two different references would appear as two new and
distinct objects.  period.  

options are to a)  implement equals() to make them "appear" to be the same
object (sort of) or b) implement readResolve().  readResolve() is probably
closer to what i was after, but to use it in a simple manner requires some
of the same hooks as implementing equals() (either an immutable object
or some sort of unique id field).  

in the end, i've resolved the problem by only passing objects once (which
is probably better) and doing the logic on the client side.

i *think* a solution for what i was after (although an overly complex one)
would be to :
1) implement writeObject() and readObject for every object to be sent
to the client.  they would perform default operation with the addition of
writing/reading the object's hashCode.  since the writeObject() is server
side, the hashCode would be that of the server-side object.
2) build a hashMap on the client that contains every object recieved
indexed by its *server-side* hashCode.
3) implement readResolve() for every object to be passed.  have it
check the local hasMap to see if the object has already been passed
and return that copy if so - otherwise add it.

still wouldn't work for a mutable object modified on the server between
serializations....but i'm not sure it should...

thoughts?

-don.
0
 
objectsCommented:
Doesn't that solution assume that hash code of evey object is unique?
0
 
dddexterAuthor Commented:
check that,  you clearly can't use hashCode
because these aren't guarenteed to be unique.
you'd have to develop a good unique id for each
object.

-don.
0
 
nir2002Commented:
I think the solution is to supply stable hashCode and equals for your own types.
You can build equals and hashCode according to the member class they have.

In your example you have to supply it to the SerialObject
for example:

public int hashCode() {
   //assuming HashSet suplly stable and good hash code even it  recreated
   return theSet.hashCode();
}

public boolean equals(Object obj) {
  if(obj instanceOf SerialObject) {
       //assuming the collection provide good equals method.
       return theSet.equals(((SerialObject)obj).getSet());
  } else {
       return false;
  }
}
0
 
dddexterAuthor Commented:
evidently, this has run its course for new ideas.  i think the idea of using something
like "an interface defining a good uniqeObjectId (as distinct from a hashCode)
to build a client object map which readResolve uses to ensure that objects are
only built on the client side a single time" is interesting, but i ain't pursuing it.

points are yours "objects".  by default i suppose.

-don.
0
 
objectsCommented:
Ta :)
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 4
  • 3
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now