Tuesday, May 26, 2015

Instance Control In Java Serialization

One of the behaviors of deserialization is that a new object is created every time the deserialization process is executed. This gives a big impact if we serialize singleton object, because, after deserialization, the singleton rule is no longer applied.

class App {

    private static final String EARTH_SER = "Earth.ser";
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Earth planet1 = Earth.getInstance();
        Earth planet2 = Earth.getInstance();
        System.out.println(planet1 == planet2); //true, singleton is applied
        
        serialize(Earth.getInstance());//serialize the singleton object
        
        Earth planet3 = deserialize(); //deserialize
        Earth planet4 = deserialize(); //deserialize again
        
        //false, object come back from serialization is a new/clone object
        System.out.println(planet1 == planet3); 

        //false, every object returned from serialization is a new/clone object
        System.out.println(planet3 == planet4); 
    }
    
    static void serialize(Earth instance) throws IOException {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(EARTH_SER))) {
            oos.writeObject(instance);
            oos.flush();
        }
    }
    
    static Earth deserialize() throws IOException, ClassNotFoundException {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(EARTH_SER))) {
            return (Earth) ois.readObject();
        }
    }
}

class Earth implements Serializable {

    private static final Earth INSTANCE = new Earth();
    
    private Earth() {}
    
    static Earth getInstance() {
        return INSTANCE;
    }
}

Imagine if the "Earth" is an instance variable of many serializable objects, after all these objects gone through the serialization and deserialization process, each of them is actually holding a brand new "Earth" object. This not only defeats the purpose of Singleton but also causing unnecessary memory consumed by redundant "Earth" objects. In order to resolve these issues, implement the special method readResolve() in Earth class. So that, Java Serialization runtime will pick up the loaded one and only "Earth" object instead of constitutes and returns a new "Earth" object.

private Object readResolve() throws ObjectStreamException {
    return INSTANCE; //the one and only instance created when Earth class is loaded
}

Re-run the App program again, and now we will get all true result.

There is another even more straight forward and safest way to resolve the serializable singleton object issue. Since enum type was introduced in Java 5, we can make use of single-element enum type to implement the singleton pattern. It is by default guarantee to only return a single instance of its element even in serialization environment. This could free us from implementing the special method readResolve() by yourself. Replace the Earth class with the "Earth enum type" below and re-run the App, we will get all true result as well.


enum Earth {
    INSTANCE;
}

Reference:
Book: Effective Java 2nd Edition by Joshua Bloch

Monday, May 25, 2015

Security In Java Serialization

Serialization turns Java object into a compact binary form which hardly read by ordinary people. This does not mean that the serialized form is encrypted safely. It can be read and analyzed by any determined person by referring to the Java Object Serialization Spec - Object Serialization Stream Protocol provided by Oracle. As a consequence, attacker is able to access the information in the serialized form or even makes up a fake binary form which could bypass the object validation rules that we enforced during the time we construct the object, and it will cause unexpected behavior in our software. You can read more about the how the attack can be done from the book Effective Java (2nd edition) Chapter 11.

class ApprovedLoanApplication implements Serializable {
    
    private static final long serialVersionUID = 1L;
    private static final double LEAST_ANNUAL_SALARY = 108000;
    
    private final String applicationId; // immutable field
    private final double annualSalary; // immutable field
    private final Date endDate;
    
    ApprovedLoanApplication(
        String applicationId, double annualSalary, Date endDate) {

        if (applicationId == null || applicationId.length() == 0) {
            throw new IllegalArgumentException(
                "Applicant Name is required.");
        }
        if (annualSalary < LEAST_ANNUAL_SALARY) {
            throw new IllegalArgumentException(
                "Least annual salary requirement not met. " 
                + "Loan application rejected.");
        }
        if (endDate == null) {
            throw new IllegalArgumentException("End Date is required.");
        }
        this.applicationId = applicationId;
        this.annualSalary = annualSalary;
        this.endDate = new Date(endDate.getTime()); //defensive copy
    }

    // other methods...
}

The ApprovedLoanApplication class above has done a good job in ensuring the object is valid and immutable during object construction. However, once this object is serialized into serialized form, the confidential data like annualSalary is visible even thought it been declared as private. One more issue is that, when the serialized form is deserialized, the same validation rules would not applied as the deserialization process will never call the class constructor in order to re-constitute back the object. This is one of the most important behavior of deserialization that we must aware of and react on it. It is causing the ApprovedLoanApplication facing security risks of data integrity breaking as the validated data could be hijacked and replaced with
  • modified data. For example, the attacker changes the mutable endDate to extends the loan period,
  • invalid data. For example, the attacker injects null applicationId which could cause system behave abnormally.

Encrypt serializable fields

To against unauthorized disclosure attack, we have to encrypt the confidential data before it is serialized. Encrypted data will be decrypted later during the deserialization process. Add the following methods into ApprovedLoanApplication.

private int encrypt(int figure) {
    // Encryption algorithm.
    // Could be replaced by complex encryption algorithm.
    return figure << 2; 
}

private int decrypt(int figure) {
    return figure >> 2; // Decryption algorithm.
}

private void writeObject(ObjectOutputStream out)
    throws IOException {
    
    this.annualSalary = encrypt(annualSalary); // encrypt
    out.defaultWriteObject();
}

private void readObject (ObjectInputStream in) 
    throws IOException, ClassNotFoundException {
   
    in.defaultReadObject();
    this.annualSalary = decrypt(annualSalary); //decrypted
}

Defensive copy

To against data modification attack, we have to perform defensive copy on our mutable object. Add the following code line into readObject() method.

this.endDate = new Date(endDate.getTime()); // defensive copy

Invariant checking

To against invariant breaking attack, we have to validate the data come from deserialization. As I mentioned earlier, deserialization does not invoke class constructor but instead, it will for sure invoke readObject() method, which give us a chance of managing the incoming stream data. Which means that we can do the same validation in the readObject() method. We may consider readObject() method is a constructor in serialization world. However, in this example, instead of duplicate the validation codes, I've offloaded the validation logic to a validator class which implements java.io.ObjectInputValidation. The validateObject() callback method will be called during deserialization runtime. Below is the full version after combining with data encryption and defensive copy techniques.

class ApprovedLoanApplication implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    private final String applicationId;
    private int annualSalary; // can't be final due to encryption
    private Date endDate; // can't be final due to defensive copy

    //validator need not to be serialized
    private final transient ApprovedLoanApplicationValidator validator; 
    
    ApprovedLoanApplication(
        String applicationId, int annualSalary, Date endDate) {
        
        this.validator = 
            new ApprovedLoanApplicationValidator(applicationId, annualSalary, endDate);
        try {
            this.validator.validateObject(); // call the same validation logic
        } catch (InvalidObjectException ex) {
            throw new IllegalArgumentException(ex.getMessage());
        }
        this.applicationId = applicationId;
        this.annualSalary = annualSalary;
        this.endDate = new Date(endDate.getTime());
    }
    
    private int encrypt(int figure) {
        return figure << 2;
    }
    
    private int decrypt(int figure) {
        return figure >> 2;
    }
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        this.annualSalary = encrypt(annualSalary);
        out.defaultWriteObject();
    }
    
    private void readObject (ObjectInputStream in) 
        throws IOException, ClassNotFoundException {
        
        in.defaultReadObject();
        this.annualSalary = decrypt(annualSalary);
        this.endDate = new Date(endDate.getTime());
        in.registerValidation(new ApprovedLoanApplicationValidator(
            applicationId, annualSalary, endDate), 0); //register validator
    }
    
    // other methods...

    // Validator inner class which implements the validation logic
    private final class ApprovedLoanApplicationValidator 
        implements ObjectInputValidation {
        
        private static final int LEAST_ANNUAL_SALARY = 108000;

        private final String applicationId;
        private final int annualSalary;
        private final Date endDate;
        
        private ApprovedLoanApplicationValidator(
            String applicationId, int annualSalary, Date endDate) {

            this.applicationId = applicationId;
            this.annualSalary = annualSalary;
            this.endDate = endDate;
        }
        
        @Override
        public void validateObject() throws InvalidObjectException {
            if (applicationId == null || applicationId.length() == 0) {
                throw new IllegalArgumentException(
                    "Applicant Name is required.");
            }
            if (annualSalary &lt; LEAST_ANNUAL_SALARY) {
                throw new IllegalArgumentException(
                    "Least annual salary requirement not met."
                    + "Loan application rejected.");
            }
            if (endDate == null) {
                throw new IllegalArgumentException("End Date is required.");
            }
        }
    }   
}

Serialization Proxy

There is another way to prevent data integrity breaking by implementing serialization proxy pattern. This implementation basically takes the advantage of the fact that serialization allow us to serialize replacement object instead of the real object.


class ApprovedLoanApplication implements Serializable {
    private static final long serialVersionUID = 1L;
    private static final double LEAST_ANNUAL_SALARY = 108000;
    
    private final String applicationId;
    private final int annualSalary; // maintain immutable
    private final Date endDate; // maintain immutable
    
    ApprovedLoanApplication(
        String applicationId, int annualSalary, Date endDate) {

        if (applicationId == null || applicationId.length() == 0) {
            throw new IllegalArgumentException(
            "Applicant Name is required.");
        }
        if (annualSalary &lt; LEAST_ANNUAL_SALARY) {
            throw new IllegalArgumentException(
            "Least annual salary requirement not met."
            + "Loan application rejected.");
        }
        if (endDate == null) {
            throw new IllegalArgumentException("End Date is required.");
        }
        this.applicationId = applicationId;
        this.annualSalary = annualSalary;
        this.endDate = new Date(endDate.getTime());
    }
    
    private Object writeReplace() throws ObjectStreamException {
        // serialize replacement object
        return new SerializationProxy(applicationId, annualSalary, endDate); 
    }
    
    private void readObject(ObjectInputStream in)
        throws InvalidObjectException {
        // Read data from stream in order to construct object's
        // fields in this method is no longer valid
        throw new InvalidObjectException("Proxy required."); 
    }

    // other methods...
    
    // static inner serializable proxy class
    private static class SerializationProxy implements Serializable { 
        private static final long serialVersionUID = 1L;
        private final String applicationId;
        private final int annualSalary;
        private final Date endDate;
        
        private SerializationProxy(
            String applicationId, int annualSalary, Date endDate) {

            this.applicationId = applicationId;
            this.annualSalary = encrypt(annualSalary);
            this.endDate = endDate;
        }
        
        private Object readResolve() throws ObjectStreamException {
            // return a new valid object
            return new ApprovedLoanApplication(
                applicationId, decrypt(annualSalary), endDate); 
        }
        
        private int encrypt(int figure) {
            return figure << 2;
        }

        private int decrypt(int figure) {
            return figure >> 2;
        }
    }
}

As you may aware that, using Serialization Proxy pattern, we mostly maintain our original code.  readResolve() method of a proxy class will create a new ApprovedLoanApplication object by calling the same class constructor, where the defensive copy and invariant checking are resided. Moreover, we could maintain the final declaration for ApprovedLoanApplication fields, which is not possible in the earlier techniques. This is very helpful because we could concentrate and remain on our class implementation instead of revising it to handle security in serialization.

In short, we should aware of the fact that, serialization does not provide security on itself. I even doubt that those techniques above may not enough to secure our objects, but at least those are best practices we should apply especially our serialized form contains sensitive information.

Reference:
Book: Effective Java 2nd Edition by Joshua Blosh

Saturday, May 16, 2015

Designing Serialized Form

Default Serialized Form

By merely adding implements Serializable to a Java class, Java Serialization runtime will be able to serialize an object of that class into binary form. Basically, Java Serialization runtime takes the default strategy to executes the serialization process, hence the output can be called as default serialized form.

public class FavoriteStockWatchList implements Serializable {

   private final int maxSize;

   // StockDetail class is also serializable
   private final Map<Integer, StockDetail> watchList; 

   //watchList and tempRanking are implementation detail
   private int tempRanking;

   public FavoriteStockWatchList(int maxSize) {
       this.maxSize = maxSize;
       this.watchList = new HashMap<>;(maxSize);
   }

   void addStock(String code, int ranking) {
       if (ranking < 1 || ranking > maxSize) {
           throw new IllegalArgumentException("Invalid ranking.");
       }
       if (watchList.containsKey(ranking)) {
           pushDownRanking(ranking);
       }
       this.watchList.put(ranking, new StockDetail(code));
   }

   void pushDownRanking(int ranking) {
       StockDetail stock = watchList.get(ranking);
       if (stock != null) {
           tempRanking = ranking + 1;
           pushDownRanking(tempRanking);
       }
       if (stock != null && tempRanking <= maxSize) {
           this.watchList.put(tempRanking, stock);
       }
   }

   StockDetail getStockDetailByRanking(int ranking) {
       StockDetail stockDetail = watchList.get(ranking);
       // Calling update() method to retrieve statistic and
       // other detail and keep in stockDetail object.
       stockDetail.update();
       return stockDetail;
   }
}

The class above is a simple implementation of a serializable FavoriteStockWatchList. As you can see, besides added implements Serializable, the rest are just ordinary codes and it works as coded. Moreover, the FavoriteStockWatchList object can be serialized to a default serialized form. "Perfect! Everything I want is working fine and I could happily release the FavoriteStockWatchList to the public. Hey, implements serialization is just a piece of cake!" This is exactly how I feel for the first time when I touch on serialization. However, my view changed when I dig in deeper.

The core value for the list item is code and ranking, and it is up to the programmer to implements the way to manages them. In the example above, we use Map of  Integer key (to represents rankingand StockDetail as value. So? What's wrong of using Map? It is not wrong or right matter but is good or bad design. After serialization, the watchList Map becomes part of the serialized form, which actually exposing the internal/private implementation detail to the public. Imagine after some time, we found that Map is not efficient or even is not appropriate and we would like to replace it with different implementation, we have no choice but to continue support watchList Map for those old serialized forms to maintain backward compatibility. In short, by serializing implementation detail, it greatly downgrades the level of flexibility for future change in the class.

The second concern is performance. StockDetail is a serializable class which could also hold other serializable classes such as Statistic class for example. The StockDetail not only is used to hold the code, but also bring out and keeps all the stock information every time getStockDetailByRanking() method is called. Imagine we have 10 StockDetail in the list, and each of them has filled up with all the information. This will give the impact as below,
  • Consuming longer processing time
    • to serialize derived fields in StockDetail
    • to traverse the class hierarchy of each serializable field and tailor the class description accordingly.
  • Serialized form become bulky because of storing extra metadata info and it drags down the speed of object transmission over the network.
Therefore, we should only accept the default serialized form if the instance fields are all core values. Of course, the core values should be carefully designed as well. Serialization limits the flexibility of future change, and hence, the make-it-work-and-refactor-later approach is not efficient at all in serialization.

Custom Serialized Form

We could customize our FavoriteStockWatchList class to determine how does our object should be serialized and deserialized. The output of serialization is still the in binary form physically, but logically, it is now called as custom serialized form. We could customize our class by applying the following techniques,
  • declare instance field to transient, hence, it won't be serialized,
  • use ObjectOutputStream.write<DataType>() methods to write core data into serialized form,
  • use ObjectInputStream.read<DataType>() methods to read core data from serialized form.

public class FavoriteStockWatchList implements Serializable {

   private final int maxSize;

   // Marked as transient. Has to give up 'final'.
   // StockDetail no longer necessary to be a serializable class
   private transient Map<Integer, StockDetail> watchList;

   // Marked as transient. tempRanking is not a core value.
   private transient int tempRanking;

   public FavoriteStockWatchList(int maxSize) {
       this.maxSize = maxSize;
       this.watchList = new HashMap<>(maxSize);
   }

   private void writeObject(ObjectOutputStream out) 
       throws IOException {
       /** 
        * call default serialization process. This will serialize 
        * all non-transient and non-static instance fields as usual.
        * "maxSize", in this example. 
        */
       out.defaultWriteObject(); 
       out.writeInt(watchList.size()); // write list size
       for (Map.Entry<Integer, StockDetail> entry : watchList.entrySet()) {
           out.writeUTF(entry.getValue().getCode()); // write core value - code
           out.writeInt(entry.getKey()); // write core value - ranking
       }
   }

   private void readObject(ObjectInputStream in) 
       throws IOException, ClassNotFoundException {
       /**
        * Call default deserialization process. This will deserialize
        * all non-transient and non-static instance fields as usual.
        * "maxSize", in this example.
        */
       in.defaultReadObject();
       int listSize = in.readInt(); // read list size
       this.watchList = new HashMap<>(maxSize);
       for (int i=0; i<listSize; i++) {
           // read core value and add them as new stock to the list
           addStock(in.readUTF(), in.readInt()); 
       }
   }

   // other methods...
}

Above is a custom version of FavoriteStockWatchList. watchList and tempRanking have been declared as transient in order to be excluded from being serialized. In other words, we have excluded the implementation detail from serialized form. Instead, we write the core values (code and ranking) into serialized form in writeObject() method. This greatly improve the room for future change in the class. For example, we could replace the Map to List to manage the stock list, and this changes won't break the backward compatibility because the core values are still the same. You may doubt that, this didn't help if we change the core value. Yes, if core value has changed, for example, replace integer ranking with alphabet ranking, then we really got to handle the backward compatibility issue. That is why, determining the correct core value is also very important when we design our serializable class.

From the performance perspective, since the complete StockDetail could be retrieved during the runtime, so we only write the code for each list item instead of the whole StockDetail. This significantly slim down the size of serialized form because less class description and field values are written into serialized form. Moreover, the processing time could be shorten as it doesn't need to traverses unnecessary dependent classes to construct object graph.

By the way, either you are using default or custom serialized form, you also have to take care of the security. Read Security in Serialization for more security best practises in serialization.

Proxy Serialized Form

By using writeReplace() and readResolve() method, we could generate proxy serialized form instead of taking the default/custom serialized form for the real object. Below is the proxy version of FavoriteStockWatchList.

public class FavoriteStockWatchList implements Serializable {

   private final int maxSize;

   // Can stay 'final'
   private final Map<Integer, StockDetail> watchList; 

   private int tempRanking;

   public FavoriteStockWatchList(int maxSize) {
       this.maxSize = maxSize;
       this.watchList = new HashMap<>(maxSize);
   }

   void addStock(String code, int ranking) {
       if (ranking < 1 || ranking > maxSize) {
           throw new IllegalArgumentException("Invalid ranking.");
       }
       if (watchList.containsKey(ranking)) {
           pushDownRanking(ranking);
       }
       this.watchList.put(ranking, new StockDetail(code));
   }

   private Object writeReplace() throws ObjectStreamException {
       return new CoreValueProxy(this); // write replacement object
   }

   private static class CoreValueProxy implements Serializable {

       private int maxSize; // core value

       private int[] rankings; // core value - ranking in list

       private String[] codes; // core value - code in list

       private CoreValueProxy(FavoriteStockWatchList instance) { 
           this.maxSize = instance.maxSize;
           Set<Map.Entry<Integer, StockDetail>> entrySet
               = instance.watchList.entrySet();
           int size = entrySet.size();
           rankings = new int[size];
           codes = new String[size];
           int i = 0;
           for (Map.Entry<Integer, StockDetail> entry : entrySet) {
               rankings[i] = entry.getKey();
               codes[i] = entry.getValue().getCode();
               i++;
           }
       }

       private Object readResolve() throws ObjectStreamException {
           // construct real object from serialized proxy form
           FavoriteStockWatchList instance
               = new FavoriteStockWatchList(maxSize);
           for (int i=0; i<codes.length; i++) {
               instance.addStock(codes[i], rankings[i]);
           }
           // return the real object
           return instance; 
       }
   }

   //other methods...
}

Proxy serialized form also having its own advantages. With the proxy pattern in mind, it could help the programmer to easily identify/differentiate the core value and implementation detail. The proxy class will hold the core values, and all the implementation detail will stay in the enclosing class. This is much more easy to pick up, straight forward, and object-oriented compare to writing the core value directly to stream in custom serialized form. Besides, it also giving the advantage of security. Read Security in Serialization for more detail.

As a conclusion, DO NOT simply implements Serializable and accept default serialized form without proper design. You can't see the impact in the short term, but you will feel the pain in the long term. On the other hand, spend more effort in understand and designing the serializable class at the very beginning in order to save cost for supporting the mess in the long term.

Reference:
Book: Effective Java 2nd Edition by Joshua Bloch

Friday, May 15, 2015

Locale Evolution

"Locale" is used to performs locale-sensitive operations such as formatting numeric value; it is also used to tailors locale-sensitive information for a user who from different geographical, political, or cultural region. While we could choose which locale to use in our application, but in common, the application locale is based on the computer platform locale. In other words, the application is taking the default locale. This post does not cover every feature of locale. It is about the change of default locale's behavior on Windows platform along with the evolution from Java 6 to 8.

Locale in Java 6

In Java 6, Locale is the only instance that determines the value format as well as the information display. The locale data returned by Locale.getDefault() and the locale data used in NumberFormat.getInstance() in the same.

>> Window platform

Change of the Region and Language - Formats - Format (as shown in the image below), will change the default locale in our application.


NumberFormat format1 = NumberFormat.getNumberInstance();
String formattedValue = format1.format(88000);
System.out.println(formattedValue);
       
NumberFormat format2 = NumberFormat.getNumberInstance(Locale.getDefault());
Number parsedValue = format2.parse(formattedValue);
System.out.println(parsedValue);

No matter what Windows region-format setting we set, the numeric value that is handled by format1 and format2 object in the code snippet above always maintain its value. For example, if the region format is set to Portuguese (Portugal), then the formattedValue is 88.000 ("." is the grouping symbol in Portuguese locale); and the parsedValue is 88000. It is confirmed that, NumberFormat.getNumberInstance() and NumberFormat.getNumberInstance(Locale.getDefault()) behaves the same.

>> Locale provider

However, it is important to be aware that, Java application takes the locale data which is provided in JRE based on the setting above. The locale data is not come from the hosting platform. This is why the customized formats in the Windows Region-Format setting do not apply to the application. In the case where JRE itself does not support the requested locale, then Locale methods will look for the locale data from any installed locale sensitive service provider interfaces (SPIs). This order is fixed.

>> VM options

There is another way to set the application locale. This can be done by setting the language and country VM options as below when launching the Java application. VM options below will make the application to picks up Portuguese (Portugal) locale data from JRE. In this way, the Java application will ignore the Windows Region-Format setting.

-Duser.language=pt -Duser.country=PT

Locale in Java 7

Since Java 7, Locale comes in two categories. Locale.Category.Format is for formatting value; Locale.Category.Display is for displaying texts. The locale data returned by Locale.getDefault() is display locale. The locale data used in NumberFormat.getInstance() is format locale.

>> Window platform

Change of the Region and Language - Formats - Format will change the format locale data; Change of the Region and Language - Administrative - Change System Locale (as shown in the image below) will change the display locale data. In others words, an Java application could have two different default locale data at the same time.


Running the same code snippet again with Portuguese (Portugal) region format setting and English (US) system locale, we now get the different formatted value for both format objects.

// Region-format: Portuguese (Portugal)
NumberFormat format1 = NumberFormat.getumberInstance(); // taking format locale (Portuguese)
String formattedValue = format1.format(88000);
System.out.println(formattedValue); // output: 88.000
       
// System locale: English (US)
NumberFormat format2 = NumberFormat.getNumberInstance(Locale.getDefault());  // taking display locale (English)
Number parsedValue = format2.parse(formattedValue);
System.out.println(parsedValue); // output: 88

The value formattedValue and parsedValue has significant difference even thought they derived from the same numeric value. NumberFormat.getNumberInstance() and NumberFormat.getNumberInstance(Locale.getDefault()) is no longer behaves the same. The resolution is just let the format object to use its default format locale, and only supply locale data to it if you know what you are doing.

>> Locale provider

Same as Java 6.

>> VM options

Same as Java 6. But to be specific, setting the language and country VM options to, let's said Portuguese (Portugal) will make the format locale and display locale become Portuguese basis.

Locale in Java 8

Same as Java 7.

>> Window platform

Same as Java 7.

>> Locale provider

Besides JRE and SPI, there are two new locale data providers supported in Java 8.
  • Common Locale Data Repository (CLDR): Released by Unicode Consortium "to support the world's languages, with the largest and most extensive standard repository of locale data available.
  • Host: The current customized locale setting of the underlying operating system.

>> VM options

The language and country VM options effect are same as Java 7. Moreover, the order of locale providers searching is not fixed and could be specified using the VM options as below.

-Djava.locale.providers=SPI,HOST,CLDR,JRE

Calendar calendar = Calendar.getInstance();
DateFormat df = SimpleDateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL); 
System.out.println(df.format(calendar.getTime()));

Run the code snippet above with different locale provider VM options on Windows platform will get the result as below:

HOST (Customized to MMMM dd, yyyy):- February 27, 2015 12:15:02 AM
JRE:- Friday, February 27, 2015 12:13:10 AM SGT
CLDR:- Friday, February 27, 2015 12:13:42 AM Singapore Standard Time

Related posts:
Text Collation

References:
http://stackoverflow.com/questions/24616848/get-number-format-from-os http://docs.oracle.com/javase/8/docs/technotes/guides/intl/enhancements.8.html http://docs.oracle.com/javase/8/docs/api/java/util/spi/LocaleServiceProvider.html http://docs.oracle.com/javase/7/docs/api/java/util/Locale.html