Understanding singletons class in Java - java

When reading Effective Java I found that the most useful approach to implement singletons is just using enums with single INSTANCE. But in case we need to make it a class, according to some of his susggestions the perfect serializable thread-safe singleton class would look like this:
public class SerializableSingletonClass implements Serializable{
private static final long serialVersionUID = 1L;
private int value;
private String name;
private SerializableSingletonClass(int value, String name) {
if( value < 0 ) throw new IllegalArgumentException("Value may not be less than 0");
this.value = value;
this.name = Validate.notNull(name, "Name may not be null");
}
private static class SerializableSingletonHolder{
public static final SerializableSingletonClass INSTANCE;
static {
INSTANCE = new SerializableSingletonClass(0, "default");
}
}
private void readObject(ObjectInputStream stream) throws InvalidObjectException{
throw new InvalidObjectException("proxy required");
}
private Object writeReplace(){
return new SerializationProxy(this);
}
private static class SerializationProxy implements Serializable{
private static final long serialVersionUID = 1L;
public SerializationProxy(SerializableSingletonClass ignored) { } //Here is the question
private Object readResolve(){
return SerializableSingletonHolder.INSTANCE;
}
}
}
As far as I got he proposed to just replace serialized instances with one that's used currently.
So, why do we ever need to make singletons serializable in the owing that their serial form would not be ever used. We just throw it out and replace deserialized instance with the current one.
To me the problem of implementing serializable singletons looks like only a theoretical one. Accoring to what I said, deserializing singleton doesn't make much sense (in the case of enums either).
So what did I miss? Couldn't you explain it in a bit more detail?

enums are also serializable, just not their fields.
I think it's important to keep it simple and easy to maintain e.g. use a text file if you are going to save it.
I would add a method like save and load to it (possibly with a filename)
enum SaveableSingleton {
INSTANCE;
String name;
int value;
public void load(String filename) throws IOException {
try (Scanner scanner = new Scanner(new File(filename))) {
name = scanner.nexLine();
value = scanner.nextInt();
}
}
public void save(String filename) throws IOException {
try (PrintWriter pw = new PrintWriter(new File(filename))) {
pw.println(name);
pw.println(value);
}
}
}
creates a file like
my-name-is
12345

If you have some field in some other serializable class where you store this singleton instance and want to serialize / deserialize that class, you would always have to mark that field transient and make sure to fill it manually on deserialization. If you handle it in the Singleton, you don't have to do this. I guess that is the reason for a serializable singleton.

Related

javafx: How to write the writeObject() and readObject() for this object?

I have a Trade object with the code below and it implements the Serializable interface but since it contains javafx properties , I get this java.io.NotSerializableException and hence failed to properly do writeObject() and readObject(). My ultimate goal is to be able to write and read this object using ObjectOutputStream and ObjectInputStream
I read the 3 links:
NotSerializableException on SimpleListProperty
Oracle doc
Java Custom Serialization
Since my Trade class is running a ScheduledService to pick up the closing price from Google Finance, I know that I need to call startService() within the readObject() to ensure that when the readObject() method is called and the object is deserialized, the thread will restart again.
Furthermore, I understand that I need to I need to define these 2 private methods within my Trade Class.
private void writeObject(ObjectOutputStream out) throws IOException
{
out.defaultWriteObject();
// What else should I write in here?
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
// our "pseudo-constructor"
in.defaultReadObject();
// Not sure what else I need to write in here
// now we are a "live" object again, so let's run rebuild and start
startService();
}
Question: I have read the 3rd link above and I am still confused about what else should go into these two private methods above ?
Because my trade object has quite a lot of properties, but all it really needs
are just buySell,transactionDate,symbol, double volume, double price to construct an object. Should I set the rest of the properties to transient then?
public class Trade implements Serializable{
// properties
private Long creationTime;
private int counter;
private ObjectProperty<LocalDate> transactionDate;
private StringProperty symbol;
private StringProperty details;
private StringProperty buySell;
private DoubleProperty volume;
private DoubleProperty price;
private ReadOnlyDoubleWrapper transactionFee;
private final ReadOnlyDoubleWrapper closingPrice;
private final PauseTransition delay;
private ReadOnlyBooleanWrapper caution;
private final ScheduledService<webScraping> stockService = new ScheduledService<webScraping>() {
// web scrape google finance data
...
}
// constructor
public Trade(BuySell buySell, LocalDate transactionDate, String symbol, double volume, double price){
...
startService();
creationTime = Calendar.getInstance().getTimeInMillis();
}
// getters and setters and instance methods that return the properties themselves
public Long getCreationTime(){
return this.creationTime;
}
private Object writeReplace() {
return new TradeProxy(this);
}
private void readObject(ObjectInputStream stream)
throws InvalidObjectException {
throw new InvalidObjectException("Proxy required");
}
...
private static class TradeProxy implements Serializable{
private String buySell;
private LocalDate transactionDate;
private String stockTicker;
private double price;
private double volume;
private Long creationTime;
private TradeProxy(Trade trade){
this.buySell = trade.getBuySell();
this.transactionDate = trade.getTransactionDate();
this.stockTicker = trade.getStockTicker();
this.price = trade.getPrice();
this.volume = trade.getVolume();
this.creationTime = trade.getCreationTime();
}
private void writeObject(ObjectOutputStream s ) throws IOException{
s.defaultWriteObject();
}
private Object readResolve() throws ObjectStreamException{
return new Trade(this.buySell,this.transactionDate, this.symbol, this.volume, this.price);
}
}
}
UPDATE: I have updated my code. But since creationTime is not an argument of the Trade's constructor, I do not know how to serialize/deserialize it in my case. To be more precise, if I create a Trade object at time say creationTime = 1443444301488, I want this object be serialized and when I read in the object and deserialize it, I want to the creationTime to be exactly the same as what it was (i.e. 1443444301488) and I don't know how to achieve this. This is the problem that I am facing now.
I would avoid serializing javafx objects. Instead create a javabean object that contains the state that should be serialized. Then you can have your Trade object build itself from the serialized proxy javabean.
class TradeSerialProxy {
private String simpleBeanFields;
private int moreSimpleStateFields;
//getters and setters
}
then
public Trade (TradeSerialProxy proxy) {
//build the Trade object using the proxy.
}
You see something similar to this in the Effective Java book. Though in that book he uses proxies for security purposes. The rule I follow is to only serialize simple javabean objects and that's that. Avoid serializing complicated objects.
Also, if you use regular Java serialization, then you might run into version problems whenever your class implementation changes. There are ways around this, like using JSON and GSON for serialization. Because I was using pure standard Java, and no external libs/jars, I had to accomplish this with HashMap... where I would only serialize the HashMap and have the real objects build themselves using a HashMap passed to it. I had to do this to avoid getting the constant serial version mismatch exception and sticking to pure standard vanilla Java.
EDIT: This is an object that uses serialization proxy pattern. This apporach is from Effective Java 2nd Edition item 78.
public class UserProfile implements Serializable {
///////////////////////////////////////////////////////////////////////////
//private variables
private String profileName = null;
private int version = 0;
private LeaderboardPermissions leaderboardState = LeaderboardPermissions.ASK;
private boolean upgradeWalkThrough = true;
private final Map<GameType, GameTypeStats> gameTypeStats;
private final String id;
private boolean offNet = true;
///////////////////////////////////////////////////////////////////////////
//serialization stuff
private static final long serialVersionUID = 7625672295622776890L;
private UserProfile(UserProfileProxy t) {
this.profileName = t.profileName;
this.version = t.version;
this.leaderboardState = t.leaderboardState;
this.upgradeWalkThrough = t.upgradeWalkThrough;
this.gameTypeStats = t.gameTypeStats;
this.id = t.id;
this.offNet = t.offNet;
}
private Object writeReplace() {
return new UserProfileProxy(this);
}
private void readObject(ObjectInputStream stream)
throws InvalidObjectException {
throw new InvalidObjectException("Proxy required");
}
///////////////////////////////
//serialization proxy
private static class UserProfileProxy implements Serializable {
private String profileName = null;
private int version = 0;
private final LeaderboardPermissions leaderboardState;
private boolean upgradeWalkThrough = true;
private final Map<GameType, GameTypeStats> gameTypeStats;
private String id;
private static final long serialVersionUID = 6985672045622776890L;
private boolean offNet;
private UserProfileProxy(UserProfile t) {
this.profileName = t.profileName;
this.version = t.version;
this.leaderboardState = t.leaderboardState;
this.upgradeWalkThrough = t.upgradeWalkThrough;
this.gameTypeStats = t.gameTypeStats;
this.id = t.id;
this.offNet = t.offNet;
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
}
private Object readResolve() throws ObjectStreamException {
return new UserProfile(this);
}
}
This approach is baked into Java object serialization protocol. Another method I am using now utilizes a HashMap<String, Object> as the proxy.
Here is the interface. I had to have the methods in this interface return their hash because my extensive use of encrypting the serialized object's hashes to prevent tampering with the saved files. I'm not necessarily recommending this but showing possibilities of serialization proxies.
public interface MapSerializable {
public static String CLASS_KEY = "MapSerializable.CLASS_KEY";
/**
* Object will populate a HashMap of objects that it can use at some later
* point to reinitialize itself. Return the hash of the objects used to
* build itself.
*
* #param serial
* #return
* #throws IOException
*/
public int populateSerialMap(HashMap<String, Object> serial) throws IOException;
/**
* Object will initialize itself using the input HashMap. Returns the hash
* of the objects that were used to initialize itself from the Map.
*
* #param serial
* #return hash of the objects that were used to load yourself.
* #throws IOException
*/
public int initializeFromMap(HashMap<String, Object> serial) throws IOException;
}
And here is an example of an object using it.
public class GameType implements MapSerializable {
////////////////////////////////////////////////////////////////////////////
//private variables
private String displayName = null;
////////////////////////////////////////////////////////////////////////////
//constrcutor
public GameType(String name) {
this.displayName = name;
}
GameType() {
}
////////////////////////////////////////////////////////////////////////////
//public methods
#Override
public int populateSerialMap(HashMap<String, Object> serial) throws IOException {
serial.put("displayName", displayName);
return 17 * Objects.hashCode(displayName);
}
#Override
public final int initializeFromMap(HashMap<String, Object> serial) throws IOException {
int hash = 0;
ObjectHashPair<String> ohp = model.utils.SerialUtils.getObjectFromMap(serial, "displayName", "");
displayName = ohp.obj;
hash += 17 * ohp.hash;
return hash;
}
}
EDIT2: Deeper explanation into the first method.
You need to first understand some of the basics of Java serialization. Java does most of the heavy lifting for you, it actually has a writeObject and readObject that work just fine for most cases. This is good news for you since all you need to do is deciding what fields need to go into the proxy just the things you want to serialize (the state) and not have to worry about actually doing the serialization (adding/removing objects to the stream). Next, you need to be able to initialize your main class using the proxy and vice versa. So create a constructor in your main class that takes a proxy object as input, in that constructor initialize your main class. Do the same for the proxy object. Lastly, Java even gives you the ability to use a proxy for writing and reading via the writeReplace and readResource methods. The writeReplace for the main class will return an instance of the proxy, essentially telling Java to serialize that object instead. On the flip side in the proxy you'll need a readResolve to return an instance of the main object during deserialization.
SO lets go through the steps in a bullet list:
1) Decide what fields need saving and create your proxy class (I used an inner nested class) to have those fields.
2) Create the constructors in main and proxy class. Main(Proxy obj) and Proxy(Main obj).
3) Implement the writeReplace and readResolve on the main and proxy classes, respectively.
I hope that helps.

Getting NotSerializableException when trying to write object

Trying to serialize and send Lot object to socket. Getting error:
java.io.NotSerializableException: com.server.ClientServiceThread
Why?
public class ClientServiceThread extends Thread {... // form here called sendObj ...}
public class FlattenLot {
public void sendObj(){
try {
out = new ObjectOutputStream(oStream);
out.writeObject(lot); // error
out.flush();
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
Lot class:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Date;
import java.util.Calendar;
public class Lot implements Serializable{
private static final long serialVersionUID = 1L;
public ArrayList<ClientServiceThread> clientBidsLog = new ArrayList<ClientServiceThread>();
public ArrayList<Integer> bidLog = new ArrayList<Integer>();
private List<Integer> bids = new ArrayList<Integer>();
private List<ClientServiceThread> clients = new ArrayList<ClientServiceThread>();
private String NAME;
private int INITIAL_PRICE;
private int MAX_BID = 0;
public volatile boolean notAvailable = false;
Lot(String name, int initPrice){
NAME = name;
INITIAL_PRICE = initPrice;
}
public synchronized String getName(){return NAME;}
public synchronized int getInitPrice(){return INITIAL_PRICE;}
public synchronized void subscribe(ClientServiceThread t){
clients.add(t);
}
public synchronized void unsubscribe(ClientServiceThread t){
clients.remove(t);
}
public synchronized boolean makeBid(ClientServiceThread t,int i){
if(i > INITIAL_PRICE && i > MAX_BID){
clientBidsLog.add(t);
bidLog.add(i);
bids.add(i);
MAX_BID = i;
t.LAST_BID = i;
notifyAllSubscribers("New bid: "+this.getMaxBid()+" made by "+this.clientBidsLog.get(this.clientBidsLog.size()-1).CLIENT_NAME);
return true;
}else{
return false;
}
}
public synchronized void notifyAllSubscribers(String msg){
for (ClientServiceThread client : clients){
client.lotUpdated(this, msg);
}
}
public synchronized int getMaxBid(){return MAX_BID;}
private Date time;
public Lot() {
time = Calendar.getInstance().getTime();
}
public Date getTime() {
return time;
}
}
The error is caused by trying to serialize a ClientServiceThread, which is not serializable. Somehow one of those is part of a Lot. If Lot is not declared with a ClientServiceThread field (or with a field that contains a ClientServiceThread), then another possibility is that Lot is a non-static inner class of a class that does have such a field. The outer class instance would then be a (hidden) member of Lot.
The solution is to either make ClientServiceThread serializable (not likely, from its name) or else eliminate it from the serialization by marking the relevant field(s) transient (or removing them from the Lot class).
Lot contains
public ArrayList<ClientServiceThread> clientBidsLog
private List<ClientServiceThread> clients
If you wish this field to be serialized mark the ClientServiceThread serializable too
if you don't want it to be serialized just mark it transient like
public transient ArrayList<ClientServiceThread> clientBidsLog
private transient List<ClientServiceThread> clients
A couple of answers have suggested that you could declare ClientServiceThread serializable as a possible solution.
WARNING - that probably won't work!
Yes, you can declare a Thread subclass that implements Serializable, but the Java serialization mechanism can't serialize the stack of a live thread. In fact, I don't even think it will succeed in serializing an inactive thread's state (e.g. the thread's ThreadGroup reference), so you'll probably end up the more exceptions.
I think your only option is to exclude the threads from serialization by declaring those collections to be transient.

java - an enum question

I have encountered a weird problem in my app (java).
I have an enum. Something like that
public enum myEnum implement myIntrface{
valueA(1),valueb(2),valuec(3),valued(4)
private int i;
// and then - a constructor
public MyEnum(int number){
i = number;
}
private MyObj obj = new MyObj;
// getter and setter for obj
}
and in another class I have this
MyEnum.valueA.setObj(new Obj(...))
in briefe - I have an enum with a private instance member that has a set and a get.
So far so good -
The only thing that amazes me is that later on I look at the value of the MyEnum.valueA().obj is null.
there is nothing that updates the value to null, I have even gave it a default value in the constructor and I still see it null later.
any suggestions?
Enums should be un-modifiable classes so you shouldn't really be doing this. If your looking to modify the state of a type based object like an enum you should use an final class approach with embedded constants. Below is an example of a class based approach with a modifiable name an a un-modifiable name...
public final class Connection {
public static final Connection EMAIL = new Connection("email");
public static final Connection PHONE = new Connection("phone");
public static final Connection FAX = new Connection("fax");
/**/
private final String unmodifiableName; //<-- it's final
private String modifiableName;
/*
* The constructor is private so no new connections can be created outside.
*/
private Connection(String name) {
this.unmodifiableName = name;
}
public String getUnmodifiableName() {
return unmodifiableName;
}
public String getModifiableName() {
return modifiableName;
}
public void setModifiableName(String modifiableName) {
this.modifiableName = modifiableName;
}
}
The purpose of enums is to represent constant values. It does not make any sense to set the fields of a constant value.
You should declare your fields as final, and use the constructor to initialize all of them.
For reference, the following code works as expected:
public class Test {
public static enum MyEnum {
valueA(1),valueb(2),valuec(3),valued(4);
private int i;
private Object o;
private MyEnum(int number) {
i = number;
}
public void set(Object o) {
this.o = o;
}
public Object get() {
return o;
}
}
public static void main(String[] args) {
System.out.println(MyEnum.valueA.get()); // prints "null"
MyEnum.valueA.set(new Integer(42));
System.out.println(MyEnum.valueA.get()); // prints "42"
}
}
the cause of this problem is the db40 framework . It loads an enum from the db using reflection. This is well documented .
http://developer.db4o.com/Forums/tabid/98/aft/5439/Default.aspx

Map from object to a dynamic string

Right now I have about 60 Message types which are passed to a getStuff(Message) method of a class which implements ContainerOfThings. There are multiple variations of an ContainerOfThings such as BoxOfStuff and BagOfTricks both of which realize the getStuff(Message) method which generates a string based on member variables. The result may also have pre-pended or post-pended data such as labels or concatenated data. See code below.
public class BoxOfStuff implements ContainerOfThings
{
private String var1;
private String var2;
private String varN;
public String getStuff(Message message)
{
if (message.equals(Message.GET_STUFF1))
return var1;
else if (message.equals(Message.GET_STUFF2))
return "Var2 is: " + var2;
else if (message.equals(Message.GET_STUFFN))
return varN + "\n";
// Etc. for each Message.GET_*
}
// getters and setters for each var*
}
public class Message
{
private String id = null;
private Message(String id)
{ this.id = id; }
public final String toString()
{ return this.id; }
public static final Message GET_STUFF1 = new Message("V1");
public static final Message GET_STUFF2 = new Message("V2");
public static final Message GET_STUFFN = new Message("VN");
}
I am trying to find a design that meets the following objectives. (1) The string returned from getStuf() needs to reflect the current state of the implementing class's member fields. (2) Also I would prefer to get away from an incredibly long series of if / else if blocks. One concern is ease of potentially changing to a persistent data-driven configurable object approach which a Map lends well towards. (3) Design should allow for simple maintenance and/or edits.
One design that could work but is a little messy is to create a Map with all key/values initialized in the constructor and also reset any key/value pair inside each setter method. In this way, the response to getStuff(Message) is updated to the new content after changes (ie: in a setVar*() method). Any other thoughts?
I think you'll need two maps. One will be a Map<Message, String> where the value will be a format string (i.e. something that will get passed into String.format()). The second map will be a Map<Message, Field> which should be fairly self explanatory once you take a look at the reflection libs. These will need to be setup at init time but after that the getStuff() method should be fairly clean and your setters won't be affected at all.
BTW, Java doesn't generally prefix interfaces with I.
I'm not 100% sure I understand your problem, but it sounds like you want to memoize the result of your getStuff() call.
One easy way to do this is to use the makeComputingMap() method from the MapMaker class in the Google Guava library.
For example, you could do:
Map<Message, String> map = new MapMaker()
.expireAfterWrite(10, TimeUnit.MINUTES)
.makeComputingMap(
new Function<Message, String>() {
public String apply(Message message) {
// Your getStuff() implementation here
}
});
Does that make sense?
How about this:
public abstract class BaseOfBox implements IContainerOfThings {
protected final Map<Message, String> stuffs =
new HashMap<Message, String>();
public final String getStuff(Message message) {
return stuffs.get(message);
}
}
public class BoxOfStuff extends BaseOfBox {
private String var1;
private String var2;
public BoxOfStuff() {
super();
}
public setVar1(String var1) {
this.var1 = var1;
stuffs.put(Message.GET_STUFF1, var1);
}
public setVar2(String var2) {
this.var2 = var2;
stuffs.put(Message.GET_STUFF2, "Var2 is: " + var2);
}
...
}
Frankly, I think this is a pretty ugly solution, but so are the requirements, IMO. I suspect a more elegant solution can only be found if we review the (real) requirements

Java XML Serializing, Missing fields in file

this is the issue at hand, when trying to serialize the class below with the code below i'm getting is the below xml file without all the strings in the class.
The Class (some static values have changed but basically it), I left out all the generated get\set but they are all there with public access modifiers.
public class NotificationConfiguration implements Serializable
{
public static final String PORT_KEY = "mail.smtp.port";
public static final String DEFAULT_PORT_VALUE = "587";
public static final String TTL_KEY = "mail.smtp.starttls.enable";
public static final String DEFAULT_TTL_VALUE = "true";
public static final String AUTH_KEY = "mail.smtp.auth";
public static final String DEFAULT_AUTH_VALUE = "true";
public static final String MAIL_SERVER_KEY = "mail.smtp.host";
public static final String DEFAULT_MAIL_CLIENT_HOST = "smtp.gmail.com";
public static final String DEFAULT_MAIL_CLIENT_USERNAME = "*********";
public static final String DEFAULT_MAIL_CLIENT_PASSWORD = "*********";
public static final String DEFAULT_MAIL_CLIENT_ADDRESS = "*********";
public static final String DEFAULT_ADMIN_EMAIL = "*********";
public static final long DEFAULT_MAIL_INTERVAL = 24*60*60*1000; //One time a day default
public static final String SAVED_FOLDER_NAME = "C:\\Library";
public static final String SAVED_FILE_NAME = "C:\\Library\\NotificationCfg.xml";
private String portValue = DEFAULT_PORT_VALUE;
private String ttlValue = DEFAULT_TTL_VALUE;
private String authValue = DEFAULT_AUTH_VALUE;
private String mailClientHost = DEFAULT_MAIL_CLIENT_HOST;
private String mailClientUserName = DEFAULT_MAIL_CLIENT_USERNAME;
private String mailClientPassword = DEFAULT_MAIL_CLIENT_PASSWORD;
private String mailClientAddress = DEFAULT_MAIL_CLIENT_ADDRESS;
private String adminEMail = DEFAULT_ADMIN_EMAIL;
private boolean overdueSubsNotificationEnabled = false;
private boolean adminReportNotificationEnabled = false;
private long mailInterval =
}
The code used to serialize, which also creates the folder if missing.
public void storeChanges()
{
try
{
try
{
File f = new File(NotificationConfiguration.SAVED_FOLDER_NAME);
f.mkdir();
}
catch (Exception e){}
XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream(new FileOutputStream(NotificationConfiguration.SAVED_FILE_NAME)));
encoder.writeObject(notificationConfig);
encoder.close();
System.out.println(LOG_CONFIGURATION_STORED);
}
catch (Exception ex)
{
System.out.println(LOG_CONFIGURATION_NOT_STORED + ex.getMessage());
}
}
The XML file received, with no exceptions thrown while serializing.
It basically just has the long value.
XMLEncoder encodes information about how to restore your object. If field values haven't changed from their defaults, XMLEncoder doesn't store anything.
This can cause confusion.
Hence, my rules of thumb when using XMLEncoder are:
1. don't initialize fields. don't do private String foo = DEFAULT_FOO;
2. don't do anything in the default constructor.
3. have some other method, or factory that will give you a "default" setup if needed.
I highly recommend to read again the XMLEncoder Javadoc
I will point out the main differences with the binary serialization we all know.
to restore the instance it need the class definition available to the JVM
It serializes only the data. And only the modified from default data.
As result of the 2 points above - is that there is no reason to serialize Static final values - they are part of the class definition.
The binary serialization on the other hand does serialize the class definition and can load from byte stream a class that was not available to the JVM before.
That is why you got results that you see. It Ok this is behavior by design and you use it right. It seems just not to be what you need.
By the way see what Xstream has to offer.
What is SAVED_FOLDER_NAME ? Is that like a factory object and did you by any chance call setMailInterval on that object?
Could that be that only mailInterval has a getter?
Just looked again the question apparently there is getter for all fields so ...

Categories