views:

157

answers:

8

I am parsing an XML file where one of the fields I want to be immutable, ID, has to be set after the object is created. Should I set it to null, and throw an exception in the setID() method if ID!=null ?

Edit: I am parsing an XML file, and at the beginning, I create an object whose fields and objects are populated using information in XML file. I want to be able to set ID, which should be immutable, after creating the root object.

Edit: changed "final" to "immutable" because that's really what I meant semantically. (Sorry :( )

+8  A: 

You cannot change a final member outside of a constructor. You will have to make it not final.

Mark Byers
+1  A: 

You definitely cannot make it final. Throwing an exception from setID() if ID != null is a good idea. Maybe if you provide some more details, someone can come up with a more creative solution?

dbyrne
What kind of exception should I throw?
Aymon Fournier
IllegalStateException
John K
Thanks. I like that too
Aymon Fournier
Agreed. `IllegalStateException` is a good choice.
dbyrne
+5  A: 

Final fields, by definition, do not change after construction of the object. If what you really mean is that you want the field to be set once, then you could simply initialize the field to null have the setter for that field throw an exception if the field is no longer null.

Uri
What kind of exception should I throw?
Aymon Fournier
@Aymon: that is up to you. If this is something that can occur in multiple classes or fields in your system, define a custom common type such as RepeatedAssignmentException
Uri
@Aymon: I'd probably use an IllegalStateException, or something derived from it.
Laurence Gonsalves
+11  A: 

The most common way around this is to use the builder pattern. You build up an object using setters and then once it's ready you create the immutable object using the builder as a template.

Mark Peters
I have many other fields that are set and are not immutable before I reach what the information that I want to store in an immutable field
Aymon Fournier
This is a great solution. The drawback can be the tedium of nearly duplicating a lot of code.
erickson
You may be able to shove the data in the XML handler instance.
Tom Hawtin - tackline
A: 

The field cannot be declared final unless it is initialized during construction. I think something like this might meet your requirements.

class Foo {

  private Bar x;

  void setX(Bar x) {
    if (x == null)
      throw new IllegalArgumentException();
    if (this.x != null)
      throw new IllegalStateException();
    this.x = x;
  }

}

This Foo implementation is intended for access by a single thread. For multi-thread access, you could use an AtomicReference or externally synchronize access.

Also note that if null is a valid value for x, you can create a private, dummy Bar instance and use it in place of null.

erickson
A: 

Maybe this nice lib will help you whith parsing xml XStream, so you don't have to bother about object creation. I don't know if you can configure it the way you want, but im sure its worth a look.

I would try to aviod a public setId method, since you get rid of this problem, if you don't have one which some client could call. Try to use the language to tell the user what he can do and what he should not.

If you don't store the id in the xml file you should use a factory which creates the object and uses a parameterized constructor.

If you don't provide a setter for the id, users can only "set" a id when creating the object, and I think thats what you want.

InsertNickHere
+5  A: 

A better approach might be to use a Builder, as described in Effective Java 2nd Edition in Item 2.

The basic idea is to have a Builder class that has setters (but usually not getters) for the different constructor parameters. There's also a build() method. The Builder class is often a (static) nested class of the class that it's used to build. The outer class's constructor is often private.

The end result looks something like:

public class Foo {
  public static class Builder {
    public Foo build() {
      return new Foo(this);
    }

    public Builder setId(int id) {
      this.id = id;
      return this;
    }

    // you can set defaults for these here
    private int id;
  }

  public static Builder builder() {
      return new Builder();
  }

  private Foo(Builder builder) {
    id = builder.id;
  }

  private final int id;

  // The rest of Foo goes here...
}

To create an instance of Foo you then write something like:

Foo foo = Foo.builder()
    .setId(id)
    .build();

You can also split this up, of course:

// I don't know the ID yet, but I want a place to store it.
Foo.Builder fooBuilder = Foo.builder();
...
// Now I know the ID:.
fooBuilder.setId(id);
...
// Now I'm done and want an immutable Foo.
Foo foo = fooBuilder.build();

You can have multiple setters on the builder, and even add additional parameters to build() or the Builder's constructor.

This lets you have a mutable object while parsing, but switch to an immutable object when you're finished. Your API only ever need expose the immutable object in many cases.

Laurence Gonsalves
A: 

Technically if you can change the value after executing the constructor, it is not "immutable". It's more "semimutable".

But terminology aside: The first idea that occurs to me is to have a "validate" function of some sort. Go through all your setters, and when you think you're done, call validate. If it fails, the object is missing required fields or whatever.

The idea of a builder object is good too. I've never used that pattern. 'Have to think through the pros and cons.

Jay