Showing posts with label Computer Science. Show all posts
Showing posts with label Computer Science. Show all posts

Tuesday, May 3, 2016

You're Killing Me Spring: "Singleton" Scope

Introduction

I generally try to avoid traditional Gang of Four Design Pattern Singletons.  In Java they are only guaranteed to be singular per running Java Virtual Machine, don't scale to a clustered environment, can be serialized / deserialized to create a duplicate even in the same JVM and are generally the OOP version of global variables.
However, in a given project I had an exception to this rule.  I had an object that was using a single TCP port going into an environment where only one instance would be deployed per machine so I thought to myself that I would use the Singleton pattern.

Background

Created at imgflip, original image copyright Dos Equis.
I have had problems with Spring before.  Specifically I was working with Spring Web Flow 3 years ago and had some configuration (including setters) in my beans.xml file, in my Spring Web Flow xml file I imported the (Singleton) beans defined in the beans.xml file.  However, instead of importing the bean it created a new instance of it, and on top of that it didn't call any of the initialization configuration in the beans.xml file leading to null pointer exceptions.  It took me three weeks to track this down.  I was working for myself (e.g. that time was on my own dime) and I ragequit Spring in favor of Google Guice.  For this project I was forced into using Spring so I had the following Hypothesis.

Hypothesis

"Verify that Spring is treating Singletons correctly because it's been unreliable, surprising and buggy in the past."  In code-form it was a standard Spring @Service in the default Singleton scope with a check in the constructor (see Further Reading for other reasons to do this) to blow up if the constructor is called twice.  In addition, Spring makes you have a public constructor even for your Singletons so blowing up can avoid programmer error of someone later trying to just call new ExampleSingleton.
@Service
// implied Spring Singleton Scope
public class ExampleSingleton {

    // should only be called once by Spring
    public ExampleSingleton() 
    {
        if (instance != null) {
            throw new IllegalStateException("Singleton constructor called twice!");
        }
    }
}    

Results

As you may have guessed from the image, Spring was attempting to create the "Singleton" repeatedly and blowing up with the IllegalStateException.  From doing some research I found that @ComponentScan was behaving strangely.  It turns out that if you have multiple Spring @Configuration classes and if they overlap on a package (e.g. @ComponentScan(basePackages = {"com.yourcompany"}) and another with @ComponentScan(basePackages = {"com.yourcompany.utils"}), Spring will (re)create all of the Singletons in the overlap (in this example com.yourcompany.utils) twice.  I found this surprising and very strange.  In addition, the same link mentions that Spring only promises that a Singleton will happen once per ApplicationContext, and Servlets usually have more than one.

Conclusion

I concluded that you can't trust Spring to honor the @Singleton contract and to manage my instances myself.  After doing more research I found that in Java the best way is to have a SingletonFactory.  I ended up having a base class called SpringSingleton, which has the documentation on why all of this is necessary and a protected constructor that keeps track of which sub-classes have been instantiated with a Set<SpringSingleton> that is accessed in a synchronized block.  In addition the @Configuration classes have an @Autowired SingletonFactory and @Bean definitions that get the beans from the SingletonFactory.  All in all it still isn't foolproof for Serializable Singletons (see below) but does a great job otherwise.  There is more complexity (4 classes for the simple case) but new Singletons end up being easy to implement and work correctly.  I would post the code but I made it at work so the company has copyright.

Too bad I couldn't just have @Component on a class with the default scope and have it work right.

Further Reading

You can abuse an enum in Java to ensure a "serializable" Singleton can't be easily duplicated but that has some drawbacks.  Given that you can invoke even a private constructor via the Java reflections API you will still want to verify that your Singletons are only being called once (or at least post a warning in the logs).

PS

There was an issue with the site CSS where black lines would appear over an image. This has been fixed.

Wednesday, April 13, 2016

LocalDateTime Is Not Local!

No one ever has problems with Dates and Times!  (Y2k, 2038, 10,000)

Java8 dates and times were supposed to be a lot easier and designed by the Joda-Time guys.

One problem, after struggling for a full working day - LocalDateTimes are NOT Local!  Maybe in the sense of localized?  They are definitely UTC, not your local timezone.  Looking back at it, it says that it doesn't capture timezone information in the docs, but I didn't look at the docs because I thought that the name was blindingly obvious.

Copyright BBC
I was pulling my hair out when I wrote a function todayAt that returned a date that didn't register as today.  A time at 3:45 PM was being converted to 2 AM UTC (the next day) because LocalDateTime wasn't local.  I was looking for ZonedDateTime.

As they say, there are two hard things in Computer Science: caching, naming things and off by one errors.

Tuesday, February 2, 2016

Blog Reboot: For SCIENCE!

It has been a heck of a year since the last time there was a new post here.

As mentioned on the Thirteen Blog Cliches on Coding Horror no one likes explainations of why a Blog hasn't been consistent.

Moving forward the posts are going to get a little more Computer Science-y, not in the hard-to read way but in the basic core of reproducing / verifying another persons claims.

In practice, I go through a lot of material that I get off of the web and a lot of times there are gotchas or caveats that the original author did not mention.  They will be mentioned and refined here.  There will be basic sections on hypothesis, results and conclusion.  Nothing super-heavy weight.

I'll keep this short: like I said, nothing super-heavy weight.