Spring MVC Formatters for BigDecimal and Long

by GarciaPL on Saturday 23 January 2016

In recent times I had issue with web application written in Spring. The problem was that some numbers stored in database as a BigDecimal's and Long's were not being stored/processed properly for different locales. On backend the numbers were processed of course using English locale, but when you have number saved with different locale the calculations might be different.

Saved BigDecimal's and Long's were processed against English locale, but presentation of numbers were based on appropriate locale of present user context.


Parse BigDecimal => 12,333,444
English => 12333444
Indonesian => 12333444

Print BigDecimal => 12345.50
English => 12345.50
Indonesian => 12345,50


Only difference for printed numbers for above locales was how decimal places is presented. For English we use dot. For Indonesian comma is used.


Parse Long => 12,333,444
English => 12333444
Indonesian => 12333444

Print Long => 12333444
English => 12333444
Indonesian => 12333444


For Long's the formatter we are going to just remove grouping commas.

So, below you can find CurrencyLocaleBigDecimalFormatter :

package pl.garciapl.test;

import org.springframework.format.Formatter;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;

public class CurrencyLocaleBigDecimalFormatter implements Formatter<BigDecimal> {

    @Override
    public BigDecimal parse(String text, Locale locale) throws ParseException {
        DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ENGLISH);
        format.applyPattern("#,##0.00");
        format.setParseBigDecimal(true);
        format.setGroupingUsed(true);
        return (BigDecimal) format.parse(text);
    }

    @Override
    public String print(BigDecimal object, Locale locale) {
        DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(locale);
        format.applyPattern("#,##0.00");
        format.setParseBigDecimal(true);
        format.setGroupingUsed(false);
        return format.format(object);
    }
}



and CurrencyLocaleLongFormatter :


package pl.garciapl.test;

import org.springframework.format.Formatter;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;

public class CurrencyLocaleLongFormatter implements Formatter<Long> {

    @Override
    public Long parse(String text, Locale locale) throws ParseException {
        DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ENGLISH);
        format.applyPattern("#,##0.00");
        format.setParseBigDecimal(false);
        format.setGroupingUsed(true);
        return (Long) format.parse(text);
    }

    @Override
    public String print(Long object, Locale locale) {
        DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(locale);
        format.applyPattern("#,##0.00");
        format.setParseBigDecimal(false);
        format.setGroupingUsed(false);
        return format.format(object);
    }
}


Also CurrencyLocaleFormatterRegistrar is needed because of Spring framework needs to register formatters in registry to use them.

package pl.garciapl.test;

import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistrar;
import org.springframework.format.FormatterRegistry;

import java.util.HashSet;
import java.util.Set;

public class CurrencyLocaleFormatterRegistrar implements FormatterRegistrar {

    private Set<Formatter> formatters = new HashSet<>();

    public CurrencyLocaleFormatterRegistrar(Set<Formatter> formatters) {
        this.formatters = formatters;
    }

    @Override
    public void registerFormatters(FormatterRegistry registry) {
        for (Formatter element : this.formatters) {
            registry.addFormatter(element);
        }
    }
}

And finally whole beans configuration for Spring

    <bean id="currencyLocaleBigDecimalFormatter" class="ie.garciapl.test.CurrencyLocaleBigDecimalFormatter"/>
    <bean id="currencyLocaleLongFormatter" class="ie.garciapl.test.CurrencyLocaleLongFormatter"/>
    <bean id="currencyLocaleRegistrar" class="ie.garciapl.test.CurrencyLocaleFormatterRegistrar">
        <constructor-arg>
            <set>
                <ref bean="currencyLocaleBigDecimalFormatter"/>
                <ref bean="currencyLocaleLongFormatter"/>
            </set>
        </constructor-arg>
    </bean>

Do not forget to plug into your conversionCurrencyService as below :

<mvc:annotation-driven conversion-service="conversionCurrencyService"/>

Reference : [1] Spring Docs - Formatters [2] Javabeat.net - Introduction to Spring Converters and Formatters [3] CurrencyLocaleBigDecimalFormatter [4] CurrencyLocaleLongFormatter [5] CurrencyLocaleFormatterRegistrar [6] CurrencyLocaleBigDecimalFormatterTest [7] CurrencyLocaleLongFormatterTest

Browser User Agents (JSON)

by GarciaPL on Saturday 16 January 2016

Below you can find GitHub Gist of User Agents in JSON based on massive list of user agents provided by Chris Pederik [1]. I provided the same list of user agents in more friendly form as a JSON because of this one provided in reference is nested multiple times, what obviously affects the use of content. Moreover I removed duplicates.





Reference : [1] https://gist.github.com/enginnr/ed572cf5c324ad04ff2e

Android Material Design with AppCompat

by GarciaPL on Wednesday 6 January 2016

I just would like to show you how setup styles.xml and values-v21/styles.xml to use Material Design with AppCompat. First of all rename styles21.xml as styles.xml and place in your res/values-v21 folder (you may need to create a values-v21 folder if you don't already have one). Below you might found AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="uk.co.thewirelessguy.myappname" >

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="uk.co.thewirelessguy.myappname.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Then change your build.gradle to provide appropriate compileSdkVersion and buildToolsVersion.


apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.1"

    defaultConfig {
        applicationId "uk.co.thewirelessguy.myappname"
        minSdkVersion 9
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.0'
}

After that you can apply styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="AppTheme.Base"/>

    <style name="AppTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->

        <!-- colorPrimary is used for the default action bar background -->
        <item name="colorPrimary">@color/colorPrimary</item>

        <!-- colorPrimaryDark is used for the status bar -->
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>

        <!-- colorAccent is used as the default value for colorControlActivated
             which is used to tint widgets -->
        <item name="colorAccent">@color/colorAccent</item>

        <!-- You can also set colorControlNormal, colorControlActivated
             colorControlHighlight & colorSwitchThumbNormal. -->
    </style>

</resources>

And also style for v21

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="AppTheme.Base">
        <!-- Customize your theme using Material Design here. -->
    </style>
</resources>


Reference :  [1] https://gist.github.com/thewirelessguy/1875ddb114bda7407402

Introducing Bower & Gulp in Java project

by GarciaPL on Saturday 2 January 2016

In this post I would like to give you some introduction how to integrate Bower and Gulp into your Java project. On the beginning I just would like to explain briefly you what Bower and Gulp are.

Bower - package management system for client-side programming on the World Wide Web. It depends on Node.js and npm. It works with git and GitHub repositories. [Wikipedia]

Gulp - fast and intuitive streaming build tool built on Node.js.


First of all we are going to use very useful plugin called frontend-maven-plugin provided under groupId com.github.eirslett [3]. This plugin will allows us to download/install Node and NPM locally for your project, run NPM install, and then any combination of Bower, Grunt, Gulp, Jspm, Karma, or Webpack.



<plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>0.0.26</version>

                <executions>
                    <execution>
                        <id>install node and npm</id>
                        <goals>
                            <goal>install-node-and-npm</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <nodeVersion>v0.12.9</nodeVersion>
                            <npmVersion>2.14.14</npmVersion>
                        </configuration>
                    </execution>

                    <execution>
                        <id>npm install</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <!-- Uses package.json -->
                        <configuration>
                            <arguments>install</arguments>
                        </configuration>
                    </execution>

                    <execution>
                        <id>bower install</id>
                        <goals>
                            <goal>bower</goal>
                        </goals>
                        <!-- Uses bower.json -->
                        <configuration>
                            <arguments>install</arguments>
                        </configuration>
                    </execution>

                    <execution>
                        <id>gulp build</id>
                        <goals>
                            <goal>gulp</goal>
                        </goals>
                        <!-- Uses gulpfile.js -->
                        <configuration>
                            <arguments>default --env ${gulp.task}</arguments>
                        </configuration>
                    </execution>

                </executions>
            </plugin>

As you can see, first of all above plugin will install locally node and npm. Then npm will install all packages from package.json file. After that bower will install packages used by frontend which are defined in bower.json. The last step is gulp which performs actions defined in gulpfile.js.
Below you can find package.json file in which I have defined bower, gulp and gulp plugins versions :

{
  "name": "simple-web",
  "repository": "git@bitbucket.org:test/test.git",
  "version": "1.0.0",
  "private": true,
  "description": "Simple Web",
  "main": "index.js",
  "author": "GarciaPL",
  "dependencies": {
    "bower": "1.7.0",
    "gulp": "3.9.0",
    "gulp-concat": "2.6.0",
    "gulp-uglify": "1.5.1",
    "gulp-sourcemaps": "1.6.0",
    "gulp-less": "3.0.5",
    "gulp-minify-css": "1.2.2",
    "gulp-environments": "0.1.1"
  }
}

Then let's see what bower.json contains. You can find there defined some plugins from Bower Repository which will be downloaded and installed in bower_components directory :

{
  "name": "Simple Web",
  "version": "1.0.0",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "jquery": "1.11.3",
    "underscore": "1.8.3",
    "autoNumeric": "1.9.25"
  }
}

And the last file is gulpfile.js. In this file you can define special actions which are going to be performed during maven build phase of your Java application. In definition of maven plugin which you might found at the beginning of this post, there is a command : <arguments>default --env ${gulp.task}</arguments>. Variable gulp.task means against what environment application should be build. This variable might be defined in root pom.xml in profile section as a property.
So, according to gulpfile.js for development phase, gulp will provide vendor.map for vendor.js - for this development() method is used. On the other side production phase will provide you uglified vendor.js (compressed) and minified CSS based on base.less - for this one production() method is used. Vendor.js will be placed in /src/main/webapp/static/js/vendor directory, but CSS file might be found in /src/main/webapp/static/css directory.

var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var less = require('gulp-less');
var minifyCSS = require('gulp-minify-css');
var environments = require('gulp-environments');
var development = environments.development;
var production = environments.production;

gulp.task('default', function () {
    console.log('Preparing vendor.js for ' + (production() ? "production" : "development"));
    gulp.start('vendorJS');
    console.log('Preparing less for ' + (production() ? "production" : "development"));
    gulp.start('less');
});

gulp.task('vendorJS', function () {
    gulp.src(['bower_components/jquery/dist/jquery.min.js',
            'bower_components/underscore/underscore-min.js',
            'bower_components/autoNumeric/autoNumeric.js'])
        .pipe(development(sourcemaps.init()))
        .pipe(concat('vendor.js'))
        .pipe(production(uglify()))
        .pipe(development(sourcemaps.write('./')))
        .pipe(gulp.dest('./src/main/webapp/static/js/vendor'));
});

gulp.task('less', function () {
    return gulp.src('src/main/webapp/static/less/base.less')
        .pipe(less())
        .pipe(production(minifyCSS()))
        .pipe(gulp.dest('./src/main/webapp/static/css'));
});





Reference :
[1] Bower.io
[2] Gulpjs.com
[3] Eirslett - frontend-maven-plugin

[4] Npmjs.com
[5] Nodejs.org