Thursday 19 November 2015

How to implement Spring Cache?

To use simple Spring Cache based on Map logic we need to do two things:

1. Add cacheManager in our application context:

<cache:annotation-driven cache-manager="cacheManager"/>

<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
p:name="sourceSystemsCache/>
// add more caches
</set>
</property>
</bean>

2. In bean add annotation above method:

@Cacheable("cacheName") // in our case sourceSystemsCache
public int doSomething(int i) {..}

Note: besides cache name, you can indicate which values not to cache (usually using spring spel) etc.

Also useful is to reset cache which can be done using fake method or method that deletes date from db and we in out case delete it from our cache.

@CacheEvict(value = "cacheName", beforeInvocation = true)
public void deleteCacheName() { //do nothing }

@CacheEvict(value = "userCache", beforeInvocation = true)
public void deleteUserName(User user) { dao.delete(user); }

I had a task to reset all cache using rest, so I wrote service where I have autowired SimpleCacheManager and took its all cacheNames it contained and just cleared them:

public class CacheServiceImpl implements CacheService {

@Autowired
private SimpleCacheManager manager;

@Override
public boolean resetCache() {
    for (String cacheName : manager.getCaheNames()) {
         manager.getCache(cacheName).clear();
}
}

}

Monday 16 November 2015

Why yoda time?



Original - https://mestachs.wordpress.com/tag/jodatime/

Don’t use java built-in classes, use jodatime and enforce this rule with sonar !

Don’t use java built-in classes

How many bugs in 5 lines of code ?
Date date = new Date(2007, 12, 13, 16, 40);
TimeZone zone = TimeZone.getInstance("Europe/Bruxelles");
Calendar cal = new GregorianCalendar(date, zone);
DateFormat fm = new SimpleDateFormat("HH:mm Z");
String str = fm.format(cal);
Just 6 bugs !
int year = 2007 - 1900;
int month = 12 - 1;
Date date = new Date(year, month, 13, 16, 40);
TimeZone zone = TimeZone.getInstance("Europe/Brussels");
Calendar cal = new GregorianCalendar(zone);
cal.setTime(date);
DateFormat fm = new SimpleDateFormat("HH:mm Z");
fm.setTimeZone(zone);
Date calDate = cal.getTime();
String str = fm.format(calDate);
If you want deeper explanations see this [presentation]

java.util.Date issues

  • From JDK1.0
  • Uses two digit years (from 1900)
  • January is 0, December is 11
  • Should have been immutable
  • Most methods deprecated in JDK1.1
  • Uses milliseconds from 1970 representation

java.util.Calendar issues

  • From JDK1.1
  • Uses subclasses for different calendar systems
  • January is 0, December is 11
  • Should have been immutable
  • Uses dual representation internally
    • value for each field
    • milliseconds from 1970 representation
  • Odd performance and bugs

java.util.DateFormat issues

  • Pattern based date formatting
  • “dd MMM yyyy”
  • Requires Date object
  • Not thread-safe : see rule findbugs : Multithreaded correctness – Call to static DateFormat
  • Not especially fast
  • Sun RFE to make thread-safe ignored

SQL – java.util.sql.Date, Time, Timestamp issues

Subclass java.util.Date
  • Date extends Date (!)
  • Time extends Date (!)
  • Override superclass to block methods (throws Exception)
  • Timestamp adds nanoseconds
  • equals() broken
  • All the problems of java.util.Date and more
  • timezone problem new Time(long)

Avoid millis manipulation and let’s use Jodatime !

when playing with java.util.Date you end up doing calculation in millis
int days = 40;
Date now = new Date();
long nowMillis = now.getTime();
Timestamp nowTimestamp = new Timestamp(nowMillis);
long future = 3600 24 * days * 1000;
Timestamp expiryTimestamp = new Timestamp(nowMillis + future);
System.out.println("nowTimestamp " + nowTimestamp);
System.out.println("expiryTimestamp " + expiryTimestamp);
this last code sample contains a bug… int vs long for days !
see this explaination the expiryTimestamp is before the nowTimestamp for “large days count”
nowTimestamp  2011-02-04 12:45:40.381
expiryTimestamp 2011-01-25 19:42:53.085
now let’s write the same code with joda time
DateTime nowTimestamp2 = new DateTime();
System.out.println("nowTimestamp    " + nowTimestamp2);
System.out.println("expiryTimestamp " + nowTimestamp2.plusDays(days));
it’s more readable… and most important it return the correct value ;)
nowTimestamp  2011-02-04T12:45:40.443+01:00
expiryTimestamp 2011-03-16T12:45:40.443+01:00

Sonar to the rescue

sonar can detect these issues :
  • Multithreaded correctness – Call to static Calendar
  • Multithreaded correctness – Call to static DateFormat
to fix them with jodatime let’s use the DateTimeFormat.
fmt=DateTimeFormat.forPattern("MMMM, yyyy");
DateTime datetime = fmt.parseDateTime(duedate);
this one is threadsafe and can be static and final field. or use the toString
datetime.toString("dd:MM:yy");
but the step further is to banish jdk date from your code base !
To do so, let’s define sonar architectural constraint like
  • Arch : avoid java.util.GregorianCalendar
  • Arch : avoid java.util.Date
  • Arch : avoid java.text.SimpleDateFormat
  • Arch : avoid java.sql.Timestamp
  • Arch : avoid java.sql.Date
to banish jdk dates from your model, you may implement hibernate usertype, jaxb adapter,…