Serializing objects that are only available through a factory

Discussion in 'Java' started by Hendrik Maryns, Dec 2, 2008.

  1. -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    Hi,

    I have some classes (wrappers around a string, each with their own
    semantics) which can only be created through a factory method, which
    ensures that there is always only one object of the given class with the
    given name (String). I want to make these classes Serializable. What
    is the best way to do this?

    Example class:

    import java.util.HashMap;
    import java.util.Map;
    public class FirstOrderVariable {
    private static final long serialVersionUID = -6957388990994668892L;
    /**
    * Factory method to get a variable. If a variable with the given name
    already
    * exists, it is returned.
    *
    * @param name
    * The name of the variable.
    * @return The unique variable with the given name. If the name is not
    * effective, a variable with a random name is returned. | if
    ( name
    * != null ) | then result.getName() == name
    */
    public static FirstOrderVariable getVariable(final String name) {
    FirstOrderVariable result;
    if (name == null) {
    result = new FirstOrderVariable();
    } else {
    result = FirstOrderVariable.variables.get(name);
    }
    if (result == null) {
    result = new FirstOrderVariable(name);
    FirstOrderVariable.variables.put(name, result);
    }
    return result;
    }
    private static Map<String, FirstOrderVariable> variables = new
    HashMap<String, FirstOrderVariable>();
    private final String name;
    private FirstOrderVariable() {
    name = "v_" + FirstOrderVariable.getNumber();
    }
    private static int getNumber() {
    return FirstOrderVariable.totalNumber++;
    }
    private static int totalNumber = 0;
    private FirstOrderVariable(final String name) {
    this.name = name;
    }
    }

    I know I should introduce the method readObject(ObjectInputStream in),
    but I am unsure what to do in there. Add the name - var mapping to the
    static map, yes, but what if there already is a variable with that name?
    I can’t return another object from readObject.

    Of course, if I deserialize a Formula in which the variable is
    contained, inside of that formula, there will only be one variable with
    the given name, but if I deserialize multiple formulas, even if
    originally they had the same variable, I cannot guarantee that they will
    use the same variable now, can I? Even when, maybe the variable has
    been created in my application already (likely for names like “x†and
    “yâ€), these have to be the same too.

    Grateful for suggestions.

    H.
    - --
    Hendrik Maryns
    http://tcl.sfs.uni-tuebingen.de/~hendrik/
    ==================
    Ask smart questions, get good answers:
    http://www.catb.org/~esr/faqs/smart-questions.html
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v2.0.9 (GNU/Linux)
    Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

    iEYEARECAAYFAkk1LfQACgkQBGFP0CTku6N9AgCfcQldWPfmj0K4TU17eD0PuXjB
    oR0An2DgawVz06c6xu2mPlwy+r2J/32e
    =nrpG
    -----END PGP SIGNATURE-----
    Hendrik Maryns, Dec 2, 2008
    #1
    1. Advertising

  2. -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    Hendrik Maryns schreef:
    > Hi,
    >
    > I have some classes (wrappers around a string, each with their own
    > semantics) which can only be created through a factory method, which
    > ensures that there is always only one object of the given class with the
    > given name (String). I want to make these classes Serializable. What
    > is the best way to do this?
    >
    > Example class:
    >
    > import java.util.HashMap;
    > import java.util.Map;
    > public class FirstOrderVariable {
    > private static final long serialVersionUID = -6957388990994668892L;
    > /**
    > * Factory method to get a variable. If a variable with the given name
    > already
    > * exists, it is returned.
    > *
    > * @param name
    > * The name of the variable.
    > * @return The unique variable with the given name. If the name is not
    > * effective, a variable with a random name is returned. | if
    > ( name
    > * != null ) | then result.getName() == name
    > */
    > public static FirstOrderVariable getVariable(final String name) {
    > FirstOrderVariable result;
    > if (name == null) {
    > result = new FirstOrderVariable();
    > } else {
    > result = FirstOrderVariable.variables.get(name);
    > }
    > if (result == null) {
    > result = new FirstOrderVariable(name);
    > FirstOrderVariable.variables.put(name, result);
    > }
    > return result;
    > }
    > private static Map<String, FirstOrderVariable> variables = new
    > HashMap<String, FirstOrderVariable>();
    > private final String name;
    > private FirstOrderVariable() {
    > name = "v_" + FirstOrderVariable.getNumber();
    > }
    > private static int getNumber() {
    > return FirstOrderVariable.totalNumber++;
    > }
    > private static int totalNumber = 0;
    > private FirstOrderVariable(final String name) {
    > this.name = name;
    > }
    > }
    >
    > I know I should introduce the method readObject(ObjectInputStream in),
    > but I am unsure what to do in there. Add the name - var mapping to the
    > static map, yes, but what if there already is a variable with that name?
    > I can’t return another object from readObject.
    >
    > Of course, if I deserialize a Formula in which the variable is
    > contained, inside of that formula, there will only be one variable with
    > the given name, but if I deserialize multiple formulas, even if
    > originally they had the same variable, I cannot guarantee that they will
    > use the same variable now, can I? Even when, maybe the variable has
    > been created in my application already (likely for names like “x†and
    > “yâ€), these have to be the same too.


    To answer my own question: I found
    http://java.sun.com/developer/JDCTechTips/2002/tt0205.html and
    consequently added the following method to the above class:

    /**
    * If there is already a variable with the name of the deserialized
    * object, return that variable, otherwise register this variable
    * with the class.
    *
    * @return The variable registered in this class with the name of
    * the deserialized variable. May be the deserialized
    * variable itself.
    * @throws ObjectStreamException
    */
    @SuppressWarnings("unused")
    private FirstOrderVariable readResolve()
    throws ObjectStreamException {
    if (!FirstOrderVariable.variables.containsKey(this.name)) {
    FirstOrderVariable.variables.put(this.name, this);
    }
    return FirstOrderVariable.getVariable(this.name);
    }

    I think this is the proper solution. Feedback still welcome of course,
    and does anyone have a suggestion as to what to put in the comment to
    the throws clause?

    TIA, H.
    - --
    Hendrik Maryns
    http://tcl.sfs.uni-tuebingen.de/~hendrik/
    ==================
    Ask smart questions, get good answers:
    http://www.catb.org/~esr/faqs/smart-questions.html
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v2.0.9 (GNU/Linux)
    Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

    iEYEARECAAYFAkk1NG8ACgkQBGFP0CTku6MRKgCfeJ1GL9YFLj/kKrHpEZ4Sq+ql
    piUAoJB5Fo52DfnuRHvYRtciWqGthOR9
    =ViOA
    -----END PGP SIGNATURE-----
    Hendrik Maryns, Dec 2, 2008
    #2
    1. Advertising

  3. In article <gh3c9f$g8s$-tuebingen.de>,
    Hendrik Maryns <> wrote:

    [...]
    > To answer my own question: I found
    > http://java.sun.com/developer/JDCTechTips/2002/tt0205.html and
    > consequently added the following method to the above class:
    >

    [...]
    > private FirstOrderVariable readResolve()

    [...]
    >
    > I think this is the proper solution. Feedback still welcome of course,
    > and does anyone have a suggestion as to what to put in the comment to
    > the throws clause?

    [...]

    The article cites Joshua Bloch's item 57 from the first edition of
    Effective Java, "Provide a readResolve method when necessary". The
    second edition, item 77, adds to that advice, saying one "should use
    enum types to enforce instance control invariants wherever possible."

    For comparison, I looked at the JScience library, which implements
    Serializable for Polynomial Functions of one or more Variable(s). The
    authors appear to be planning to use XML to manage variables by name;
    sadly, the feature is marked TODO in version 4.3.1.

    My proposed exception message: "The variable name <" + this.name + ">
    was a complete surprise to me at this point." Cf.:

    <http://www.frivolity.com/teatime/Computers/MPW_errors.html>

    --
    John B. Matthews
    trashgod at gmail dot com
    http://home.roadrunner.com/~jbmatthews/
    John B. Matthews, Dec 2, 2008
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Christopher V. Kimball

    Serializing generic objects

    Christopher V. Kimball, Dec 11, 2004, in forum: Java
    Replies:
    0
    Views:
    332
    Christopher V. Kimball
    Dec 11, 2004
  2. Medi Montaseri
    Replies:
    17
    Views:
    836
    Medi Montaseri
    Sep 3, 2003
  3. C#
    Replies:
    4
    Views:
    387
  4. Matt
    Replies:
    1
    Views:
    144
  5. Matt Bush

    Serializing custom exception through a webmethod call.

    Matt Bush, Nov 9, 2004, in forum: ASP .Net Web Services
    Replies:
    1
    Views:
    211
    Dan Rogers
    Nov 11, 2004
Loading...

Share This Page