Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2007

Tip: Looking for answers? Try searching our database.

How to "force" my object never been changed by other other objects using it?

Thread view: 
www - 08 Feb 2007 15:34 GMT
Hi,

I have a class, Data.java. Once an object of this class is created,
several other kind objects will use it. For example:

Data myDataObj = new Data(...//params);

UserA userA = new UserA(myDataObj);  //pass the object to another object.
double ave = userA.getAverage();

UserB userB = new UserB(myDataObj);
...

I want myDataObj state never been modified by users. Right now, I just
open my eyes widely to make sure that my code does not do it. I am
wondering if I can use some key words to enforce it, like:

final Data myDataObj = new Data(...);  //my feeling this is wrong: it
just make sure the reference myDataObj (the memory address in heap being
referenced) cannot be changed. Or, the street address cannot be changed.
But the house can be modified. Am I correct?

How about ...?

public class UserA()
{
    public UserA(final Data data) //constructor
    {
        ...//code
    }

}

Thank you.
Chris Dollin - 08 Feb 2007 15:33 GMT
> I have a class, Data.java. Once an object of this class is created,
> several other kind objects will use it. For example:
[quoted text clipped - 8 lines]
>
> I want myDataObj state never been modified by users.

Make all its variables private (possibly: protected) and provide
no setters. [Recurse if necessary.]

Signature

Chris "electric hedgehog" Dollin
"We did not have time to find out everything we wanted to know."
- James Blish, /A Clash of Cymbals/

www - 08 Feb 2007 16:13 GMT
> Make all its variables private (possibly: protected) and provide
> no setters. [Recurse if necessary.]

Sorry. My posting was not clear. I don't want Data.java completely
immutable. Occasionally, I want to change the object state, like:

dataObj.setName("bar");   //before it was "foo", now it is bar

My first posting and my purpose is: I don't want dataObj being modified
by other objects without my awareness. Such change could be burried in
UserA class' some method somewhere and I am totally not aware of it.
Chris Dollin - 08 Feb 2007 16:17 GMT
>> Make all its variables private (possibly: protected) and provide
>> no setters. [Recurse if necessary.]
[quoted text clipped - 7 lines]
> by other objects without my awareness. Such change could be burried in
> UserA class' some method somewhere and I am totally not aware of it.

Make all its variables private (possibly: protected) and provide
setters which report the change to you (or your representative code).

If you make the setters [package] protected, and put your "safe" code
in the same package, users can't see the setter anyway.

If you don't mind the value changing, then I'm not sure why you mind
someone else changing it. But then, I don't know what your design goals
are.

Signature

Chris "electric hedgehog" Dollin
"A facility for quotation covers the absence of original thought." /Gaudy Night/

www - 08 Feb 2007 16:21 GMT
For another better example to show my point:

public class Car
{
    final private Engine engine = new Engine();  //even the final word here
may does not serve my purpose

    public void drive()
    {
        ...//code
    }

    public void stop()
    {
        ...//code
    }

    public void turnLeft()
    {
        ...//code
    }

    ...

}

I do not want Engine being completely immutable. I want to be able to
tune or fix Engine sometimes by myself. But I do NOT want when Car is
doing something(driving, stopping, or ...), Car is tuning or modifying
Engine. That is dangerous!
Oliver Wong - 08 Feb 2007 16:43 GMT
> For another better example to show my point:
>
[quoted text clipped - 26 lines]
> something(driving, stopping, or ...), Car is tuning or modifying Engine.
> That is dangerous!

With this new information, I have a different recommendation. I had thought
you wanted to pass off an object which *you* can mutate, but no one else
could. Now it sounds like you want an object which can mutate, but only in
certain states:

public class Car {
 public boolean isSafeToTune() {
   return !driving && !turning;
 }

 public boolean isSafeToTurn() {
   return !driving && ! tuning;
 }

 /**
  * PRECONDITIONS: none
  * POSTCONDITIONS: driving
  */
 public void drive() {
   driving = true;
 }

 /**
  * PRECONDITIONS: none
  * POSTCONDITIONS: !driving
  */
 public void stop() {
   driving = false;
 }

 /**
  * PRECONDITIONS: isSafeToTurn()
  * POSTCONDITIONS: turning
  */
 public void turnLeft() {
   if (!isSafeToTurn()) {
     throw new IllegalStateException();
   }
   turning = true;
 }

 /**
  * PRECONDITIONS: isSafeToTune()
  * POSTCONDITIONS: car is tuned.
  */
 public void tune() {
   if (!isSafeToTune()) {
     throw new IllegalStateException();
   }
   /*tune car somehow*/
 }
}

Users of your class will have to read the javadocs carefully and understand
when and why they are allowed to call certain methods, and not other
methods.

   - Oliver
Eric Sosman - 08 Feb 2007 17:42 GMT
www wrote On 02/08/07 11:21,:
> For another better example to show my point:
>
[quoted text clipped - 26 lines]
> doing something(driving, stopping, or ...), Car is tuning or modifying
> Engine. That is dangerous!

    public void tuneOrFix() {
       if (engineIsRunning())
           throw new IllegalStateException("pphhht!");
       removeSparkPlugs();
       ...
    }

You might also want to modify some of the other methods:

    public void drive() {
       if (maintenanceInProgress())
           throw new IllegalStateException(
               "not while it's on the lift!");
       if (! engineIsRunning())
           start();
       ...
    }

Signature

Eric.Sosman@sun.com

Oliver Wong - 08 Feb 2007 16:25 GMT
> Hi,
>
[quoted text clipped - 17 lines]
> referenced) cannot be changed. Or, the street address cannot be changed.
> But the house can be modified. Am I correct?

   You're right that "final" won't do it. I'm assuming that you want to
make Data immutable mainly for reducing bugs, and not for security purposes.

   Simply provide two interfaces for your Data object, one which provides
getters, and one which provides setters.

public interface ReadableData {
 int getX();
}

public class Data implements ReadableData {
 private int x;
 public int getX() {
   return this.x;
 }

 public void setX(int newValue) {
   this.x = newValue;
 }
}

   And when you want to make your object immutable, upcast it from Data to
ReadableData:

 Data myDataObj = new Data();
 ReadableData immutableViewOfMyDataObj = myDataObj;
 immutableViewOfMyDataObj.setX(5); /*This causes a compile error, setX() is
not defined on the interface.*/

   If you have "malicious programmers" on your team, they can get around
this by downcasting from ReadableData to Data, which is why I say this only
works for bug detecting and not security. If you need something stronger
than this, then you'll probably need to make proxy classes which can read
from the original data object, but never provides a mean to write to it.

   - Oliver
Chris Uppal - 08 Feb 2007 16:46 GMT
> I want myDataObj state never been modified by users.

You can't do it with any combination of "final" flags (unless you want to make
your object completely immutable -- and even then you can't /quite/ manage it).

The closest you can come is to hand out an immutable proxy for the object
instead of the object itself.  E.g.

public interface Data
{
   int getWidth();
   String getName();
   int[] getMoreData();
}

public class RealData
implements Data
{
   private int m_width;
   private String m_name;
   private int[] m_moreData;

   public int getWidth() { return m_width; }
   public String getName() { return m_name; }
   public int[] getMoreData() { return m_moreData; }
   public void setWidth(int width) { m_width = width; }
   public void setName(String name) { m_name = name; }
   public void setMoreData(int[] data) { m_moreData = data; }

   public Data asImmutableData() { return new ImmutableData(); }

   class ImmutableData
   implements Data
   {
       public int getWidth() { return RealData.this.getWidth(); }
       public String getName() { return RealData.this.getName(); }
       public int[] getMoreData() { return
RealData.this.getMoreData().clone(); }
   }
}

Note that there may be nothing to gain in making RealData public, and there may
be nothing to gain in making it implement Data and have public get/set methods.
But I've made it public here to illustrate how, even if it is public, a user of
the object returned by asImmutableData() cannot change it.

Note also the call to clone() in the immutable version of getMoreData() -- we
don't want to hand out a reference to the real array, since arrays (or
references to arrays) cannot be made immutable.

As something of an aside, I would be tempted to add asImmutableData() to the
Data interface, and make ImmutableData.asImmutableData() just
   return this;
The idea is that something can pass on an immutable proxy for a possibly
mutable object to a third party by using asImmutableData() whether originally
had a reference to a RealData or an ImmutableData.

A simpler solution, and in many cases a better solution, is just not to worry
about it.  If the other code changes your object then it must have been given
the relevant access permissions -- and if you've given it that then you
obviously trust it not to do anything stupid.

   -- chris


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.