Tuesday, 20 December 2016

Using p-namespace for shorter XML in Spring

If you have worked on Spring and used XML configuration for wiring beans you would have used <property> element several times for providing property values and/or providing reference for beans. If you are looking for any shorter alternative to nested <property> element you can use p-namespace.

The p-namespace enables you to use the bean element’s attributes, instead of nested <property/> elements.

As example –

If you have a XML configuration for bean employee with property officeAddress of type Address which refers to another bean address like this –

<bean id="employee" class="org.netjs.model.Employee">
    <property name="officeAddress" ref="address"/>
</bean>
You can use p-namespace to shorten it like this –
<bean id="employee" class="org.netjs.model.Employee" p:officeAddress-ref="address">
    <!-- <property name="officeAddress" ref="address"/> -->
</bean>

You can see here that instead of using nested <property> element you can use bean element’s attribute itself.

In this way of using p-namespace for injection of bean reference p:officeAddress-ref="address", p: denotes the use of p-namespace, officeAddress is the property name with in the employee class where value is injected, -ref indicates injection of bean reference.

For literals

Same way p-namespace can be used for injecting literal values.

As example

If you have a XML configuration for bean employee which has a property empName then you can provide a literal value to empName property like this –

<bean id="employee" class="org.netjs.model.Employee">
    <property name="empName" value="Ram"/>
</bean>

Using p-namespace you can shorten it like this –

<bean id="employee" class="org.netjs.model.Employee" p:empName="Ram">
    <!-- <property name="empName" value="Ram"/> -->
</bean>

Full example

As we have already seen there are two classes Address and Employee where Address class bean is referred in Employee.

Address class

public class Address {
 private String number; 
 private String street; 
 private String city; 
 private String state; 
 private String pinCode; 
 public String getNumber() {
  return number;
 }
 public void setNumber(String number) {
  this.number = number;
 }
 public String getStreet() {
  return street;
 }
 public void setStreet(String street) {
  this.street = street;
 }
 public String getCity() {
  return city;
 }
 public void setCity(String city) {
  this.city = city;
 }
 public String getState() {
  return state;
 }
 public void setState(String state) {
  this.state = state;
 }
 public String getPinCode() {
  return pinCode;
 }
 
 public void setPinCode(String pinCode) {
  this.pinCode = pinCode;
 }
}

Employee class

public class Employee {
 private int empId;
 private String empName;
 private int age;
 private Address officeAddress;
 
 public Address getOfficeAddress() {
  return officeAddress;
 }
 public void setOfficeAddress(Address officeAddress) {
  this.officeAddress = officeAddress;
 }
 public int getEmpId() {
  return empId;
 }
 public void setEmpId(int empId) {
  this.empId = empId;
 }
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
}

XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
   
    <bean id="address" class="org.netjs.model.Address" p:number="101" p:street="M I Road" 
            p:city="Jaipur" p:state="Rajasthan" p:pinCode="302001"> 
    </bean>
    <bean id="employee" class="org.netjs.model.Employee" p:empId="1001" p:age="25" p:empName="Ram" p:officeAddress-ref="address">
        <!-- <property name="empName" value="Ram"/> -->
    </bean>
    
</beans>

Here notice the inclusion of xmlns:p="http://www.springframework.org/schema/p in XML configuration for p-namespace.

Test Class

You can run this code using the following code -
public class App {

 public static void main(String[] args) {
  
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
  Employee emp = (Employee)context.getBean("employee");  
  Address addr = emp.getOfficeAddress();
  System.out.println("Name " + emp.getEmpName());
  System.out.println("Age " + emp.getAge());
  System.out.println("city " + addr.getCity());
  context.close(); 
 }
}

Output

Name Ram
Age 25
city Jaipur

Points to remember

  1. The p-namespace is not as flexible as the standard XML format. For example, the format for declaring property references clashes with properties that end in Ref, whereas the standard XML format does not. If you want to reference bean named address and you also have the property named as address-ref then it will result in a clash if you use p-namespace.
  2. You can’t use p-namespace while wiring a collection.

That's all for this topic Using p-namespace for shorter XML in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. What is Dependency Injection in Spring
  2. Dependency Injection using factory-method in Spring
  3. Using Spring profiles to switch environment
  4. How to read properties file in Spring Framework
  5. Autodiscovery of bean using componenent-scan in Spring
  6. Difference between component-scan and annotation-config in Spring

You may also like -

>>>Go to Spring tutorial page

Tuesday, 13 December 2016

Run time injection using Spring Expression Language(SpEL)

Spring Expression Language (SpEL) is available from Spring 3, it is a powerful expression language and provides an option for runtime injection rather than hardcoding values. Using SpEL you can inject values into the properties of a bean or constructor arguments that are evaluated at runtime.

Feature overview

The expression language supports the following functionality

  • Literal expressions
  • Boolean, relational and mathematical operators
  • Regular expressions
  • Accessing properties, arrays, lists, maps
  • Bean references
  • Calling constructors
  • Method invocation
  • Ternary operator

How to write expressions

Spring expression language can be used with XML based configuration or with annotation based configuration to inject values at runtime. You can also write your own code using ExpressionParser interface for parsing an expression.

SpEL expressions are written using the form #{Expression String}. As an example if you have to assign a literal using SpEL in XML configuration it can be done this way -

<bean id="employeeAddress" class="org.netjs.exp.Spring_Example.EmployeeAddress">
    <property name="pinCode" value = "#{'302001'}" />
</bean>

Of course providing a literal expression this way doesn’t offer much advantage, this example just shows the syntax of SpEL.

Bean reference, setting property and Method invocation with SpEL

Let us see one example of bean reference and method invocation with Spring expression language. There are two classes Employee and Address, in Employee class Address class object is referenced.

Address Class

public class Address {
 private String number;
 private String street;
 private String city;
 private String state;
 private String pinCode;
 
 public String getNumber() {
  return number;
 }
 public void setNumber(String number) {
  this.number = number;
 }
 public String getStreet() {
  return street;
 }
 public void setStreet(String street) {
  this.street = street;
 }
 public String getCity() {
  return city;
 }
 public void setCity(String city) {
  this.city = city;
 }
 public String getState() {
  return state;
 }
 public void setState(String state) {
  this.state = state;
 }
 public String getPinCode() {
  return pinCode;
 }
 
 public void setPinCode(String pinCode) {
  this.pinCode = pinCode;
 }
 
 public String getAddress(String empName){
  return empName + " works at " + number + ", " + street + ", " + city + ", " + state + ", " + pinCode;
 }
}

Employee class

public class Employee {
 private long empId;
 private String empName;
 private Address officeAddress;
 private String officeLocation;
 private String employeeInfo;
 
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 
 public long getEmpId() {
  return empId;
 }
 public void setEmpId(long empId) {
  this.empId = empId;
 }
 public Address getOfficeAddress() {
  return officeAddress;
 }
 public void setOfficeAddress(Address officeAddress) {
  this.officeAddress = officeAddress;
 }
 public String getOfficeLocation() {
  return officeLocation;
 }
 public void setOfficeLocation(String officeLocation) {
  this.officeLocation = officeLocation;
 }
 public String getEmployeeInfo() {
  return employeeInfo;
 }
 public void setEmployeeInfo(String employeeInfo) {
  this.employeeInfo = employeeInfo;
 }
 
}

XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    
    <bean id="officeAddress" class="org.netjs.prog.Address">
        <property name="number" value = "101" />
        <property name="street" value = "#{'M I Road'}" />
        <property name="city" value = "Jaipur" />
        <property name="state" value = "Rajasthan" />
        <property name="pinCode" value = "#{'302001'}" />
    </bean>
    
    <bean id="employee" class="org.netjs.prog.Employee">
        <property name="empId" value = "1001" />
        <property name="empName" value = "Ram" />
        <!--  Bean reference through SpEL -->
        <property name="officeAddress" value = "#{officeAddress}" />
        <property name="officeLocation" value = "#{officeAddress.city}" />
        <!--  Method invocation through SpEL -->
        <property name="employeeInfo" value = "#{officeAddress.getAddress('Ram')}" />
    </bean>

</beans>

Here you can note that in the officeAddress Bean properties are given values using literal expressions.
In the employee bean officeAddress property is given address reference using SpEL. For property officeLocation it refers to the property city of officeAddress bean using SpEL. For property employeeInfo method invocation is used and it is calling getAddress method of class Address, again using SpEL.

Test class

You can run this code using the following code -

import org.netjs.prog.Employee;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

 public static void main(String[] args) {
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
  Employee emp = (Employee)context.getBean("employee");
  System.out.println("Office address " + emp.getOfficeAddress().getNumber());
  System.out.println("Location of office " + emp.getOfficeLocation());
  System.out.println("Employee info " + emp.getEmployeeInfo());
 }

}

Output

Office address 101
Location of office Jaipur
Employee info Ram works at 101, M I Road, Jaipur, Rajasthan, 302001

Using Annotation

You can write the same code using annotations. The @Component annotation for registering the bean and @Value for setting values into bean properties. If you want to retain the same functionality as in the above program using XML configuration then the class will look like -

Employee class

@Component("employee")
public class Employee {
 @Value("1001")
 private long empId;
 @Value("Ram")
 private String empName;
 @Value("#{officeAddress}")
 private Address officeAddress;
 @Value("#{officeAddress.city}")
 private String officeLocation;
 @Value("#{officeAddress.getAddress('Ram')}")
 private String employeeInfo;
 
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 
 public long getEmpId() {
  return empId;
 }
 public void setEmpId(long empId) {
  this.empId = empId;
 }
 public Address getOfficeAddress() {
  return officeAddress;
 }
 public void setOfficeAddress(Address officeAddress) {
  this.officeAddress = officeAddress;
 }
 public String getOfficeLocation() {
  return officeLocation;
 }
 public void setOfficeLocation(String officeLocation) {
  this.officeLocation = officeLocation;
 }
 public String getEmployeeInfo() {
  return employeeInfo;
 }
 public void setEmployeeInfo(String employeeInfo) {
  this.employeeInfo = employeeInfo;
 }
 

}

Address class

@Component("officeAddress")
public class Address {
 @Value("101")
 private String number;
 @Value("#{'M I Road'}")
 private String street;
 @Value("Jaipur")
 private String city;
 @Value("Rajasthan")
 private String state;
 @Value("#{'302001'}")
 private String pinCode;
 
 public String getNumber() {
  return number;
 }
 public void setNumber(String number) {
  this.number = number;
 }
 public String getStreet() {
  return street;
 }
 public void setStreet(String street) {
  this.street = street;
 }
 public String getCity() {
  return city;
 }
 public void setCity(String city) {
  this.city = city;
 }
 public String getState() {
  return state;
 }
 public void setState(String state) {
  this.state = state;
 }
 public String getPinCode() {
  return pinCode;
 }
 
 public void setPinCode(String pinCode) {
  this.pinCode = pinCode;
 }
 
 public String getAddress(String empName){
  return empName + " works at " + number + ", " + street + ", " + city + ", " + state + ", " + pinCode;
 }
}

In that case your XML configuration doesn’t need to provide bean definitions as the beans were registered automatically but you do need to provide the base package which Spring needs to scan in order to register the classes.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    <context:component-scan base-package="org.netjs.prog" />

</beans>

Test Class

You can use the same code to run this code -

import org.netjs.prog.Employee;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

 public static void main(String[] args) {
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
  Employee emp = (Employee)context.getBean("employee");
  System.out.println("Office address " + emp.getOfficeAddress().getNumber());
  System.out.println("Location of office " + emp.getOfficeLocation());
  System.out.println("Employee info " + emp.getEmployeeInfo());
 }

}

Output

Office address 101
Location of office Jaipur
Employee info Ram works at 101, M I Road, Jaipur, Rajasthan, 302001

Using Type safe operator (?.)

In the above example in the employee bean, employeeInfo property uses the method invocation expression.

<property name="employeeInfo" value = "#{officeAddress.getAddress('Ram')}" />

Let’s say there is a requirement that this value should be in upper case so you’ll write it like this -

<property name="employeeInfo" value = "#{officeAddress.getAddres('Ram').toUpperCase()}" />

Here one problem is, what if getAddress() method returns null? In that case you will get an error -

Method call: Attempted to call method toUpperCase() on null context object

To avoid that you can use type-safe operator .?

<property name="employeeInfo" value = "#{officeAddress.getAddress('Ram')?.toUpperCase()}" />

Using type-safe operator ensures that whatever is on the left side of the operator doesn’t return null before calling the thing on the right. If null is returned from the left side type-safe operator will halt the execution there itself and return null.

SpEL Operators

SpEL supports many operators that can be used in forming the expression.

Relational operators

The relational operators; equal, not equal, less than, less than or equal, greater than, and greater than or equal are supported using standard operator notation. In addition to standard relational operators SpEL supports the instanceof and regular expression based matches operator. Each symbolic operator can also be specified as a purely alphabetic equivalent. This avoids problems where the symbols used have special meaning for the document type in which the expression is embedded (eg. an XML document). The textual equivalents are shown here: lt (<), gt (>), le (#), ge (>=), eq (==), ne (!=), div (/), mod (%), not (!). These are case insensitive.

Logical operators

The logical operators that are supported are and, or, and not.

Mathematical operators

The addition operator (+) can be used on both numbers and strings. Subtraction, multiplication and division (-, *, /) can be used only on numbers. Other mathematical operators supported are modulus (%) and exponential power (^).

Conditional Operators

?: (ternary), ?: (Elvis)

Let’s see an example using some of these operators, here we have one class OperatorDemo with int and String properties and another class OperatorTest where some of the operators are used.

OperatorDemo class

public class OperatorDemo {
 private int num1;
 private int num2;
 private int num3;
 private String name;
 private String city;
 public int getNum1() {
  return num1;
 }
 public void setNum1(int num1) {
  this.num1 = num1;
 }
 public int getNum2() {
  return num2;
 }
 public void setNum2(int num2) {
  this.num2 = num2;
 }
 public int getNum3() {
  return num3;
 }
 public void setNum3(int num3) {
  this.num3 = num3;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getCity() {
  return city;
 }
 public void setCity(String city) {
  this.city = city;
 }

}

OperatorTest Class

public class OperatorTest {
 private boolean lessThanCheck;
 private int sum;
 private String info;
 private boolean andCheck;
 private boolean orCheck;
 public boolean isLessThanCheck() {
  return lessThanCheck;
 }
 public void setLessThanCheck(boolean lessThanCheck) {
  this.lessThanCheck = lessThanCheck;
 }
 public int getSum() {
  return sum;
 }
 public void setSum(int sum) {
  this.sum = sum;
 }
 public String getInfo() {
  return info;
 }
 public void setInfo(String info) {
  this.info = info;
 }
 public boolean isAndCheck() {
  return andCheck;
 }
 public void setAndCheck(boolean andCheck) {
  this.andCheck = andCheck;
 }
 public boolean isOrCheck() {
  return orCheck;
 }
 public void setOrCheck(boolean orCheck) {
  this.orCheck = orCheck;
 }
 
}

XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- <context:component-scan base-package="org.netjs.prog" /> -->
    
    <bean id="opDemoBean" class="org.netjs.prog.OperatorDemo">
        <property name="num1" value = "10" />
        <property name="num2" value = "20" />
        <property name="num3" value = "30" />
        <property name="name" value = "Ram" />
        <property name="city" value = "Agra" />
    </bean>
    
    <bean id="opTestBean" class="org.netjs.prog.OperatorTest">
        <property name="lessThanCheck" value = "#{opDemoBean.num1 lt opDemoBean.num2}" />
        <property name="sum" value = "#{opDemoBean.num2 + opDemoBean.num3}" />
        <property name="info" value = "#{opDemoBean.name + ' from ' +  opDemoBean.city}" />
        <property name="andCheck" value = "#{opDemoBean.num1 == 10 and opDemoBean.num2 == 20}" />
        
        
        <property name="orCheck" value = "#{opDemoBean.num1 lt 10 or opDemoBean.num3 == 20}" />
    </bean>

</beans>

In order to test this code you can use the following code -

import org.netjs.prog.Employee;
import org.netjs.prog.OperatorTest;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

 public static void main(String[] args) {
  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
  OperatorTest opTest = (OperatorTest)context.getBean("opTestBean");
  System.out.println("num1 is Less than num 2 " + opTest.isLessThanCheck());
  System.out.println("Info " + opTest.getInfo());
  System.out.println("Sum " + opTest.getSum());
  System.out.println("And check " + opTest.isAndCheck());
  System.out.println("Or check " + opTest.isOrCheck());
 }

}

Output

num1 is Less than num 2 true
Info Ram from Agra
Sum 50
And check true
Or check false

Using Ternary and Elvis operator

You can also use ternary operator as an expression. Suppose you want to assign value to num property based on logic that if num1 is less than num3 then num = 10 otherwise num = 30.

<property name="num" value = "#{opDemoBean.num1 lt opDemoBean.num3 ? 10 : 30 }" />

There is also a short form of ternary operator known as Elvis operator. When using ternary operator many a times we have to check for null. With the ternary operator syntax you usually have to repeat a variable twice, for example:

String info = name != null ? name : "Unknown";

Using Elvis operator you can write it like this -

<property name="info" value = "#{opDemoBean.name ?: 'Unknown'}" />

Using Types expression

If you are using static method in SpEL then use the T() operator.

As example if you want to assign some random number to property you can do it like this -

<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

Using regular expression with SpEL

SpEL has a matches operator to be used with regular expression. The matches operator returns true if regular expression matches the given value otherwise false.

As example

#{person.email matches '[a-zA-Z0-9._]+@[a-zA-Z0-9]+\\.com'}

Using SpEL with Collectione like map and list

CollectionDemo class

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CollectionDemo {
    private Map<String, String> map;
    private List<String> list;
    public CollectionDemo() {
        map = new HashMap<String, String>();
        map.put("KEY1", "Value 1");
        map.put("KEY2", "Value 2");
        map.put("KEY3", "Value 3");

        list = new ArrayList<String>();
        list.add("List Value 1");
        list.add("List Value 2");
        list.add("List Value 3");

    }
    public Map<String, String> getMap() {
        return map;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }   
}

CollectionTest Class

public class CollectionTest {
 private String mapValue;
 private String listValue;
 public String getMapValue() {
  return mapValue;
 }
 public void setMapValue(String mapValue) {
  this.mapValue = mapValue;
 }
 public String getListValue() {
  return listValue;
 }
 public void setListValue(String listValue) {
  this.listValue = listValue;
 } 
}

XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- <context:component-scan base-package="org.netjs.prog" /> -->
    
    <bean id="collDemoBean" class="org.netjs.prog.CollectionDemo">
        
    </bean>
    
    <bean id="collTestBean" class="org.netjs.prog.CollectionTest">
        <property name="mapValue" value = "#{collDemoBean.map['KEY2']}" />
        <property name="listValue" value = "#{collDemoBean.list[0]}" />
        
    </bean>

</beans>

To test it -

import org.netjs.prog.CollectionTest;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
        CollectionTest collTest = (CollectionTest)context.getBean("collTestBean");
        System.out.println("Map value " + collTest.getMapValue());
        System.out.println("List Value  " + collTest.getListValue());
        context.close();
    }

}

Output

Map value Value 2
List Value  List Value 1

That's all for this topic Run time injection using Spring Expression Language(SpEL). If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. What is Dependency Injection in Spring
  2. Dependency Injection using factory-method in Spring
  3. Wiring collections in Spring
  4. Spring example program using JavaConfig and Annotations
  5. Spring example program using automatic configuration
  6. How to inject prototype scoped bean in singleton bean

You may also like -

>>>Go to Spring tutorial page

Friday, 9 December 2016

Java Stream API Examples

In the post Stream API in Java 8 we have already got an introduction of Stream API. A Stream can be defined as a sequence of elements supporting sequential and parallel aggregate operations. Using these aggregation operations we can create a pipeline. Some of the aggregation operations provided are collect, concat, count, distinct, filter, forEach, limit, map, max, min, reduce, sorted. In this post we’ll see some examples using these operations and also create pipeline consisting sequence of aggregate operations.

count

count method returns the count of elements in the given stream.

Note that this is a special case of a reduction and it is a terminal operation.

List<Integer> myList = Arrays.asList(7, 18, 10, 24, 17, 5);  
long count = myList.stream().count();
System.out.println("Total elements in the list " + count);

This code snippet will give the count of the elements in the List.

Now if you want to get the count of the elements greater than 10 you can create a pipeline where you first filter on the predicate that you want those elements of the list whose value is greater than 10 and then count those elements.

List<Integer> myList = Arrays.asList(7, 18, 10, 24, 17, 5); 
long count = myList.stream().filter(i -> i > 10).count();
System.out.println("Total elements in the list with value greater than 10 " + count);

concat

Creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.

List<String> myList = Arrays.asList("1", "2", "3", "4", "5");
  
String[] arr1 = { "a", "b", "c", "d" };
// concatenating two streams
Stream<String> stream = Stream.concat(myList.stream(), Arrays.stream(arr1));
stream.forEach(System.out::print);

Output

12345abcd

Here you can see the concatenated stream is returned. If you are wondering what is this System.out::print refer Method reference in Java 8. You may also want to read about forEach statement in Java 8.

Since parameters of the concat operations are streams so all the aggregation operations can be applied to them too. As example if there are two lists having name and you want a merged list with all the names that start with “A” that can be done as follows –

List<String> nameList1 = Arrays.asList("Ram", "Amit", "Ashok", "Manish", "Rajat");
  
List<String> nameList2 = Arrays.asList("Anthony", "Samir", "Akash", "Uttam");
  
String[] arr1 = { "a", "b", "c", "d" };
// concatenating two streams
Stream<String> stream = Stream.concat(nameList1.stream().filter(n -> n.startsWith("A")), nameList2.stream().filter(n -> n.startsWith("A")));

stream.forEach(System.out::println);

distinct

Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.

Using distinct method of the stream duplicate elements from a collection like list can be removed very easily by creating a pipeline where distinct method will return a stream having distinct elements only which can later be collected in a list using collect method.

List<Integer> myList = Arrays.asList(7, 18, 10, 7, 10, 24, 17, 5);
  
System.out.println("Original list: " + myList);
List<Integer> newList = myList.stream().distinct().collect(Collectors.toList());

System.out.println("new List : " + newList);

filter

filter method returns a stream consisting of the elements of this stream that match the given predicate.

Here note that Predicate is a functional interface and can be implemented as a lambda expression. In the above examples we have already used filter method.

As an example let’s say we have a list of names and we want to print names which doesn’t start with “A”.

List<String> nameList = Arrays.asList("Ram", "Amit", "Ashok", "Manish", "Rajat");
  
nameList.stream().filter(n -> !n.startsWith("A")).collect(Collectors.toList()).forEach(System.out::println);

Output

Ram
Manish
Rajat

limit

Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.

If you want 10 random numbers, then you can use limit method with the int stream.

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

map

Returns a stream consisting of the results of applying the given function to the elements of this stream. So, whatever function is provided is applied on all the elements of the stream. Note that this is an intermediate operation.

As Example – If you have a list of salaries and you want to increase it by 10%.

List<Integer> myList = Arrays.asList(7000, 5000, 4000, 24000, 17000, 6000);
  
myList.stream().map(i -> (i+ i * 10/100)).forEach(System.out::println);

findFirst() and findAny()

  • findFirst() - Returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty. If the stream has no encounter order (List or Array wil be ordered, where as set or map won’t), then any element may be returned.
  • findAny() - Returns an Optional describing some element of the stream, or an empty Optional if the stream is empty. The behavior of this operation is explicitly nondeterministic; it is free to select any element in the stream. This is to allow for maximal performance in parallel operations; the cost is that multiple invocations on the same source may not return the same result. (If a stable result is desired, use findFirst() instead.)
List<String> nameList = Stream.of("amy", "nick", "margo", "desi");
Optional<String> name = nameList.stream().findFirst();
System.out.println("First Name " + name);

name = nameList.parallelStream().findAny();
System.out.println("First Name " + name);

Output

First Name Optional[amy]
First Name Optional[margo]

You can see in case of findFirst() method, first element of the list is displayed. Even with parallelStream, findFirst() will give the first element.

Whereas in case of findAny() method any random element is picked. You can see that findAny() method is used with parallelStream here.

max and min

  • max - Returns the maximum element of this stream according to the provided Comparator.
  • min - Returns the minimum element of this stream according to the provided Comparator.

max and min are also reduction operations. Both of them are terminal operations.

List<Integer> myList = Arrays.asList(7000, 5000, 4000, 24000, 17000, 6000);
// Obtain a Stream to the array list.
Stream<Integer> myStream = myList.stream();
Optional<Integer> val = myStream.min(Integer::compare);
if(val.isPresent()){
 System.out.println("minimum value in the list " + val.get());
}  
Optional<Integer> val1 = myList.stream().max(Integer::compare);
if(val1.isPresent()){
 System.out.println("maximum value in the list " + val1.get());
}

Note that here Optional class is used. To know more about Optional class refer Optional class in Java 8.

sorted

sorted method returns a stream consisting of the elements of this stream, sorted according to natural order or there is another variant where custom comparator can be provided.

List<Integer> myList = Arrays.asList(7000, 5000, 4000, 24000, 17000, 6000);
myList.stream().sorted().forEach(System.out::println);

Summary Statistics

A state object for collecting statistics such as count, min, max, sum, and average. There are different SummaryStatistics classes like IntSummaryStatistics, DoubleSummaryStatistics, LongSummaryStatistics.

As example –

 
List<Integer> myList = Arrays.asList(7, 5, 4, 24, 17, 6);
IntSummaryStatistics stats = myList.stream().collect(Collectors.summarizingInt(i-> i));

System.out.println("Sum - " + stats.getSum());
System.out.println("Count " + stats.getCount());
System.out.println("Average " + stats.getAverage());
System.out.println("Max " + stats.getMax());
System.out.println("Min " + stats.getMin());

Here Collectors.summarizingInt method is used which applies an int-producing mapping function to each input element, and returns summary statistics for the resulting values.

In place of

IntSummaryStatistics stats = myList.stream().collect(Collectors.summarizingInt(i-> i));

Using mapToInt method it can also be written as -

IntSummaryStatistics stats = myList.stream().mapToInt(i -> i).summaryStatistics();

That's all for this topic Java Stream API Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Primitive type streams in Java Stream API
  2. Reduction Operations in Java Stream API
  3. Parallel Stream in Java Stream API
  4. Overview of lambda expressions
  5. Method reference in Java 8
  6. Optional class in Java 8

You may also like -

>>>Go to Java advance topics page

Thursday, 8 December 2016

Using Conditional annotation in Spring framework

In some cases you do want to conditionally enable or disable a complete @Configuration class, or even individual @Bean methods. One common example of this is to use the @Profile annotation to activate beans only when a specific profile has been enabled in the Spring Environment.

Spring 4 @Conditional annotation

In Spring 4 @Conditional annotation has been added which can be used for providing your own logic for conditional checking and then decide whether specific bean should be registered or not.

The @Conditional annotation indicates specific org.springframework.context.annotation.Condition implementations that specifies the condition which should be consulted before a @Bean is registered.

Condition interface

A single condition that must be matched in order for a component to be registered. The class given as value in @Conditional annotation has to implement the Condition interface. Condition interface required that you provide an implementation for the matches() method.

  • boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) - Determine if the condition matches.

    Parameters:

    • context - the condition context
    • metadata - metadata of the class or method being checked
    • Returns: true if the condition matches and the component can be registered or false to veto registration.

Conditional annotation example

Suppose you want to create a bean only if a specific condition is present in the property file otherwise you don’t to create the bean. That can be done using @Conditional annotation.

TestBean class

public class TestBean {
 private String name;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 } 
}

TestBeanCondition class

This is the class which implements the Condition interface and provides the condition for creating the TestBean. As you can see in the matches method it checks if environment contains the property “test”.

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class TestBeanCondition implements Condition {

 @Override
 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  Environment env = context.getEnvironment();
  return env.containsProperty("test");
 }

}

test.properties class

test=true
country=India

TestBeanConfig class

This is the class where TestBean is created, you can see the @Conditional annotation used here with the class that provides the condition.
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource(value="classpath:config/test.properties", ignoreResourceNotFound=true)
public class TestBeanConfig {
 @Bean
 @Conditional(TestBeanCondition.class)
 public TestBean testBean() {
  System.out.println("test bean creation");
  return new TestBean();
 }
}

You can test this code using the following piece of code -

 
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppProfile {
 public static void main( String[] args ){
  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBeanConfig.class);
  
  TestBean tb = (TestBean)context.getBean("testBean");  
  tb.setName("Ram");
  System.out.println("" + tb.getName());
  context.close();
    }
}

Output

test bean creation
Ram

That's all for this topic Using Conditional annotation in Spring framework. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Using Spring profiles to switch environment
  2. Insert\Update using JDBCTemplate in Spring framework
  3. Wiring collections in Spring
  4. Data access in Spring framework
  5. What is Dependency Injection in Spring

You may also like -

>>>Go to Spring tutorial page

Monday, 5 December 2016

Using Spring profiles to switch environment

While developing an application its very common to switch environments. As example while developing an application we may use different DB configuration, in QA environment another set of DB configuration and in production altogether different DB configuration. Few other examples are encryption techniques, caching, interaction with other systems may vary among different deployment environments.

Bean definition profiles

In order to have different beans for different environment we do need to register different beans in different environments.

Let’s consider the first use case in a practical application that requires a DataSource. In a dev environment, the configuration may look like this:

@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
      .setType(EmbeddedDatabaseType.HSQL)
      .addScript("my-schema.sql")
      .addScript("my-test-data.sql")
      .build();

In QA environment lets say you are using commons DBCP connection pool -

@Bean(destroyMethod="close")
public DataSource dataSource() {
  BasicDataSource dataSource = new BasicDataSource();
  dataSource.setUrl("jdbc:mysql://localhost:3306/test");
  dataSource.setDriverClassName("com.mysql.jdbc.Driver");
   dataSource.setUsername("user");
  dataSource.setPassword("password");
  dataSource.setInitialSize(10);

  return dataSource;
}

In production environment assuming that the datasource for the application will be registered with the production application server’s JNDI directory. Our dataSource bean now looks like this:

@Bean(destroyMethod="")
public DataSource dataSource() throws Exception {
    Context ctx = new InitialContext();
    return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}

So you can see that ultimately you are getting a datasource but all the three environments have their own ways for getting the different versions of data sources.

One way to do that is having a combination of system environment variables and XML <import/> statements containing ${placeholder} tokens that resolve to the correct configuration file path depending on the value of an environment variable.

What you need here is register certain bean definitions in certain contexts, while not in others. Spring provides bean profiles as a better option to do that.

Spring bean profiles

Spring bean profiles allow you to indicate that a component is eligible for registration, it can be done using -

  1. profile annotation with Java configuration.
  2. profile attribute of the <beans> element with XML configuration.

Here note that Spring makes the decision which environment is needed at runtime.

So, to summarize it using profiles is a two step process -

  1. You have to get varying bean definitions into one or more profiles.
  2. Make sure that the proper profile is active when your application is deployed in each environment.

So using @Profle annotation you can write DB configuration for dev environment as -

@Configuration
@Profile("dev")
public class StandaloneDataConfig {
    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.HSQL)
        .addScript("classpath:com/bank/config/sql/schema.sql")
        .addScript("classpath:com/bank/config/sql/test-data.sql")
        .build();
    }
}
And for production as -
@Configuration
@Profile("production")
public class JndiDataConfig {
    @Bean(destroyMethod="")
    public DataSource dataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}

Here you can note that @Profile annotation is applied at the class level. That was the only way to do it in Spring 3.1. Starting with Spring 3.2, however, you can use @Profile at the method level, alongside the @Bean annotation. In that case you need only one particular bean of a configuration class. In the preceding example I’ll use @Profile at the method level.

Spring profiles example

In this example there is DBConfiguration class which has different profiles for dev, qa and production.

As this example uses Java configuration so please refer Spring example program using JavaConfig and Annotations to know more about Java configuration.

DBConfiguration class

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jndi.JndiObjectFactoryBean;

@Configuration
public class DBConfiguration {
    //private static final Logger log = LoggerFactory.getLogger(DBConfiguration.class);
    
    @Bean(destroyMethod="shutdown")
    @Profile("dev")
    public DataSource embeddedDataSource() {
        System.out.println("profile for dev");
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript("classpath:schema.sql")
            .addScript("classpath:test-data.sql")
            .build();
    }
    
    @Bean
    @Profile("prod")
    public DataSource jndiDataSource() {
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName("jdbc/myDS");
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource) jndiObjectFactoryBean.getObject();
    }
    
    @Bean
    @Profile("qa")
    public DataSource qaDataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUsername("user");
        dataSource.setPassword("password");
        dataSource.setInitialSize(10);

        return dataSource;

    }
}

Setting active profile

You can set active profile programmatically against the Environment API which is available via an ApplicationContext:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppProfile {
 public static void main( String[] args ){
  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
  // Setting active profile
  context.getEnvironment().setActiveProfiles("dev");
  // Registering configuration class
  context.register(DBConfiguration.class);
  context.refresh();
  context.close();
    }
}

Running this class will give output as “profile for dev” as dev profile is active.

Different types of profiles

Apart from active profile there is also an option to declare a default profile. The default profile represents the profile that is enabled by default.

As example

@Configuration
@Profile("default")
public class DefaultDataConfig {
    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
 dataSource.setUrl("jdbc:mysql://localhost:3306/test");
 dataSource.setDriverClassName("com.mysql.jdbc.Driver");
 dataSource.setUsername("user");
 dataSource.setPassword("password");
 dataSource.setInitialSize(10);

 return dataSource;
    }
}

If no profile is active, the dataSource above will be created; this can be seen as a way to provide a default definition for one or more beans. If any profile is enabled, the default profile will not apply.

Different ways of activating profiles

In the above example you have already seen how to activate profile programmatically against the Environment API. But there are several other ways profile can be activated.

  • As initialization parameters on DispatcherServlet
  • As context parameters of a web application
  • As environment variables
  • As JVM system properties
  • Using the @ActiveProfiles annotation on an integration test class

As initialization parameters on DispatcherServlet

<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>
    org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
   <param-name>spring.profiles.active</param-name>
   <param-value>dev</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

As context parameters of a web application

<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>

As system property

-Dspring.profiles.active = "qa"

OR in the AppProfile class used in above example -

public class AppProfile {
 public static void main( String[] args ){
  System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, "qa");
  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DBConfiguration.class);
  // Setting active profile
  //context.getEnvironment().setActiveProfiles("qa");
  // Registering configuration class
  //context.register(DBConfiguration.class);
  //context.refresh();
  context.close();
    }
}

XML Bean definition profiles

Apart from Java Configuration you can also use XML configuration to define various profiles. This can be done by setting the profile attribute of the <beans> element.

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- other bean definitions -->
   <beans profile="dev">
       <jdbc:embedded-database id="dataSource">
       <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
       <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
       </jdbc:embedded-database>
   </beans>

   <beans profile="prod">
       <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
   </beans>

   <beans profile="qa">
      <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value = "${db.driverClassName}" />
        <property name="url" value = "${db.url}" />
        <property name="username" value = "${db.username}" />
        <property name="password" value = "${db.password}" />
        <property name="initialSize" value = "${pool.initialSize}" />
    </bean>
  </beans>
</beans>

Here note that there are three beans and all are of type javax.sql.DataSource and with an ID of dataSource. But at runtime, Spring container will create only one bean, depending on which profile is active.

Few Points about Profiles

  • You can enable more than one profile.
    context.getEnvironment().setActiveProfiles("profile1", "profile2");
    
  • You can also use NOT operator (!) with the profile.

    As example, if there are two methods -

    @Bean(destroyMethod="shutdown")
    @Profile("!dev")
    public DataSource embeddedDataSource() {
     ....
     ....
    }
    
    @Bean
    @Profile("qa")
    public DataSource qaDataSource() {
     ....
     ....
    }
    

    In that case registration for dev will occur if profile 'qa' is active or if profile 'dev' is not active. Which, in a way means if qa profile is active apart from qa, dev profile will also be registered, making “dev” profile as active will result in no registration at all.

  • As we have already seen @profile can be used at method level from Spring 3.2. In Spring 3.1 only at class level.
  • You can also have default profile. The default profile represents the profile that is enabled by default.

That's all for this topic Using Spring profiles to switch environment. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Using Conditional annotation in Spring framework
  2. Data access in Spring framework
  3. What is Dependency Injection in Spring
  4. Spring example program using automatic configuration
  5. Bean definition inheritance in Spring

You may also like -

>>>Go to Spring tutorial page

Wednesday, 30 November 2016

Select query using NamedParameterJDBCTemplate in Spring framework

In the post Insert\Update using NamedParameterJDBCTemplate in Spring framework I have already discussed how NamedParameterJDBCTemplate can be used for inserting and updating data in the DB. In this post we’ll see how to read data from DB using named parameters. Main intention to have it as a separate post is to discuss callback part in detail.

In the post Data access in Spring framework it has been discussed in detail how Spring framework provides templates to manage the fixed part and use call back to handle the variable part. Fetching data from DB using select query has, as usual, the fixed part like getting connection, cleaning up, handling exception but at the same time Spring framework does need help to map the fetched data to the model. That’s where callback comes into picture.

NamedParameterJdbcTemplate

Spring framework provides NamedParameterJdbcTemplate class which adds support for programming JDBC statements using named parameters, as opposed to programming JDBC statements using only classic placeholder ('?') arguments.

Here one thing to note is NamedParameterJdbcTemplate class wraps a JdbcTemplate, and delegates to the wrapped JdbcTemplate to do much of its work.

NamedParameterJdbcTemplate with Select query example

Note that NamedParameterJdbcTemplate needs a DataSource in order to perform its management of fixed part like getting a DB connection, cleaning up resources.

In this post Apache DBCP is used which provides pooled datasource and MYSQL is used as the back end.

Technologies used

  • Spring 4.2.1
  • Apache DBCP2
  • MYSQL 5.1.39
  • Java 8
  • Apache Maven 3.3.3

Maven dependencies

If you are using maven then you can provide dependencies in your pom.xml.

With all the dependencies your pom.xml should look something like this -

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.netjs.prog</groupId>
  <artifactId>maven-spring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>maven-spring</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>4.2.1.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    
     <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>
    
    <!-- Spring JDBC Support -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    
   <!-- MySQL Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.39</version>
    </dependency>
    
    <!--  Apache DBCP connection pool -->
    <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-dbcp2</artifactId>
       <version>2.1</version>
    </dependency>
  </dependencies>
</project>

Alternatively you can download the jars and add them to the class path.

Database table

For this example I have created a table called employee with the columns id, name and age in the MYSQL DB. Column id is configured as auto increment checked so no need to pass id from your query as DB will provide value for it.

CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(35) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

Setting up dependencies

First thing is to set up DataSource as a bean. I have used properties file to configure datasource where all the properties are there in the db.properties file.

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value = "${db.driverClassName}" />
    <property name="url" value = "${db.url}" />
    <property name="username" value = "${db.username}" />
    <property name="password" value = "${db.password}" />
    <property name="initialSize" value = "${pool.initialSize}" />
</bean>

Where as db.properties file which is under the config folder has all the properties.

db.properties

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/netjs
db.username=
db.password=
pool.initialSize=5

Description for the properties used here is as -

driver class name is the JDBC driver for the DB used. Since MYSQL is used here so the jdbc driver for the same (com.mysql.jdbc.Driver) is provided.

Url – You need to provide url to access your DB server. I have created a schema called netjs and DB is running on the same system so url is jdbc:mysql://localhost:3306/netjs.

Username and password for the DB.

IntialSize is the initial size of the connection pool. It is given as 5 so initially 5 connections will be created and stored in the pool.

To use properties file you need to put following configuration in your XML.

<context:property-placeholder location="classpath:config/db.properties" />

Configuring NamedParameterJDBCTemplate

DataSource bean has to be provided as a reference in NamedParameterJDBCTemplate.

<bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">  
    <constructor-arg ref="dataSource"></constructor-arg> 
</bean>

Java Classes

Since Spring always promotes to use interfaces and there is also a JEE design pattern for database layer called DAO which also says the same thing - Separate low level data access code from the business layers.

So we have a EmployeeDAO interface with insert, update and delete methods and its implementing class EmployeeDAOImpl. There is also a model class Employee with all the getters/setters.

Employee.java class

public class Employee {
 private int empId;
 private String empName;
 private int age;
 
 public int getEmpId() {
  return empId;
 }
 public void setEmpId(int empId) {
  this.empId = empId;
 }
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
}

EmployeeDAO interface

public interface EmployeeDAO {
    
    public List<Employee> findAllEmployees();
    
    public Employee findEmployee(int empId);
    
}

EmployeeDAOImpl class

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.netjs.dao.EmployeeDAO;
import org.netjs.model.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class EmployeeDAOImpl implements EmployeeDAO {
    private NamedParameterJdbcTemplate namedJdbcTemplate; 
    
    final String SELECT_BY_ID_QUERY = "SELECT id, name, age from EMPLOYEE where id = :id";
    final String SELECT_ALL_QUERY = "SELECT id, name, age from EMPLOYEE";
    
    @Autowired
    public EmployeeDAOImpl1(NamedParameterJdbcTemplate namedJdbcTemplate){
        this.namedJdbcTemplate = namedJdbcTemplate;
    }

    @Override
    public List<Employee> findAllEmployees() {
        return this.namedJdbcTemplate.query(SELECT_ALL_QUERY, new EmployeeMapper());
    }

    @Override
    public Employee findEmployee(int empId) {
        return this.namedJdbcTemplate.queryForObject(SELECT_BY_ID_QUERY, new MapSqlParameterSource("id", empId), new EmployeeMapper());
    }
    
    private static final class EmployeeMapper implements RowMapper<Employee> {
        public Employee mapRow(ResultSet rs, int rowNum) throws SQLException         {
            Employee emp = new Employee();
            emp.setEmpId(rs.getInt("id"));
            emp.setEmpName(rs.getString("name"));
            emp.setAge(rs.getInt("age"));
            return emp;
        }
    }
}
If you have more than one named parameter you can also use a hashMap or create a chain of addValue() methods with a MapSqlParameterSource class object. Refer Insert\Update using NamedParameterJDBCTemplate in Spring framework to see an example.

Notice how you are not writing any code for getting or closing connection, exception handling. All that fixed part is managed by the template class.

If there is any SQLException thrown that is also caught by JDBCTemplate and translated to one of the DataAccessException and rethrown.

But the main thing to demonstrate here is how callback works. Here template callbacks are used to query the DB and then map the returned result set to the model (Employee) object(s).

If you have noticed in findEmployee(int empId) method queryForObject method of JDBCTemplate is used which takes 3 parameters -

  • SQL query String.
  • Object of type SQLParameterSource that is where MapSqlParameterSource object is passed which stores all the named parameters to be bound to the query.
  • RowMapper object that maps a single result row to a Java object via a RowMapper.

Whereas in findAllEmployees() method query method is used which takes only two parameters –

  • SQL query String
  • RowMapper object

Main thing here is RowMapper object which in this example is the object of class EmployeeMapper implementing the RowMapper interface.

RowMapper interface has a single method mapRow which takes two arguments -

  • ResultSet - A table of data representing a database result set.
  • int - the number of the current row
and this method returns the result object for the current row.

For every row in the result set, JDBCTemplate calls the mapRow() method of the RowMapper interface implementing class. Arguments passed are ResultSet and an integer which is the number of the current row in the result set. Using that row number cursor is moved to the given row in the result set.

Full XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
   <context:component-scan base-package="org.netjs.daoimpl" />
    <!--  For reading properties files --> 
    <context:property-placeholder location="classpath:config/db.properties" />
    
    <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">  
        <constructor-arg ref="dataSource"></constructor-arg> 
    </bean> 
    <!-- <bean id="employeeDAO" class="org.netjs.daoimpl.EmployeeDAOImpl">
        <property name="namedJdbcTemplate" ref="namedJdbcTemplate"></property>  
    </bean> -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value = "${db.driverClassName}" />
        <property name="url" value = "${db.url}" />
        <property name="username" value = "${db.username}" />
        <property name="password" value = "${db.password}" />
        <property name="initialSize" value = "${pool.initialSize}" />
    </bean>

</beans>

If you are not using automatic configuration, then you can uncomment the bean definition for the EmployeeDAO.

Test class

You can use the following code in order to test the code -

import java.util.List;
import org.netjs.dao.EmployeeDAO;
import org.netjs.model.Employee;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
        EmployeeDAO dao = (EmployeeDAO)context.getBean("employeeDAOImpl");  
               
        Employee emp = dao.findEmployee(5);
        System.out.println("Name - "+ emp.getEmpName() + " Age - " + emp.getAge());        
        List<Employee> empList = dao.findAllEmployees();
        System.out.println("Name - "+ empList.get(3).getEmpName() + " Age - " + empList.get(3).getAge());
    }
}

That's all for this topic Select query using NamedParameterJDBCTemplate in Spring framework. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring example program using automatic configuration
  2. Select query using JDBCTemplate in Spring framework
  3. Configuring DataSource in Spring Framework
  4. Autodiscovery of bean using componenent-scan in Spring
  5. How to read properties file in Spring Framework

You may also like -

>>>Go to Spring tutorial page

Monday, 28 November 2016

Insert\Update using NamedParameterJDBCTemplate in Spring framework

In the post Insert\Update using JDBCTemplate in Spring framework we have already seen how JDBCTemplate can be used in Spring framework for data access. If you have noticed the examples, in the SQL queries there indexed parameters are used with the place holder '?'.

With indexed parameter it is very important that you pass the parameters in the correct order in the query. Problem with indexed parameter is that any change in the query may require a change in order of the parameters too. If you want to avoid that another option is named parameters. As the name suggests here each parameter is given a name and you bind the parameters to the query using those names.

NamedParameterJdbcTemplate

Spring framework provides NamedParameterJdbcTemplate class which adds support for programming JDBC statements using named parameters, as opposed to programming JDBC statements using only classic placeholder ('?') arguments.

Here one thing to note is NamedParameterJdbcTemplate class wraps a JdbcTemplate, and delegates to the wrapped JdbcTemplate to do much of its work.

NamedParameterJdbcTemplate Example

Note that NamedParameterJdbcTemplate needs a DataSource in order to perform its management of fixed part like getting a DB connection, cleaning up resources.

In this post Apache DBCP is used which provides pooled datasource and MYSQL is used as the back end.

Technologies used

  • Spring 4.2.1
  • Apache DBCP2
  • MYSQL 5.1.39
  • Java 8
  • Apache Maven 3.3.3

Maven dependencies

If you are using maven then you can provide dependencies in your pom.xml.

With all the dependencies your pom.xml should look something like this -

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.netjs.prog</groupId> <artifactId>maven-spring</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>maven-spring</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.2.1.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> <!-- Spring JDBC Support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!-- MySQL Driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version> </dependency> <!-- Apache DBCP connection pool --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.1</version> </dependency> </dependencies> </project>

Alternatively you can download the jars and add them to the class path.

Database table

For this example I have created a table called employee with the columns id, name and age in the MYSQL DB. Column id is configured as auto increment checked so no need to pass id from your query as DB will provide value for it.

CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(35) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

Setting up dependencies

First thing is to set up DataSource as a bean. I have used properties file to configure datasource where all the properties are there in the db.properties file.

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value = "${db.driverClassName}" />
    <property name="url" value = "${db.url}" />
    <property name="username" value = "${db.username}" />
    <property name="password" value = "${db.password}" />
    <property name="initialSize" value = "${pool.initialSize}" />
</bean>

Where as db.properties file which is under the config folder has all the properties.

db.properties

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/netjs
db.username=
db.password=
pool.initialSize=5

Description for the properties used here is as -

driver class name is the JDBC driver for the DB used. Since MYSQL is used here so the jdbc driver for the same (com.mysql.jdbc.Driver) is provided.

Url – You need to provide url to access your DB server. I have created a schema called netjs and DB is running on the same system so url is jdbc:mysql://localhost:3306/netjs.

Username and password for the DB.

IntialSize is the initial size of the connection pool. It is given as 5 so initially 5 connections will be created and stored in the pool.

To use properties file you need to put following configuration in your XML.

<context:property-placeholder location="classpath:config/db.properties" />

Configuring NamedParameterJDBCTemplate

DataSource bean has to be provided as a reference in NamedParameterJDBCTemplate.

<bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">  
    <constructor-arg ref="dataSource"></constructor-arg> 
</bean>

Java Classes

Since Spring always promotes to use interfaces and there is also a JEE design pattern for database layer called DAO which also says the same thing - Separate low level data access code from the business layers.

So we have a EmployeeDAO interface with insert, update and delete methods and its implementing class EmployeeDAOImpl. There is also a model class Employee with all the getters/setters.

Employee.java class

public class Employee {
 private int empId;
 private String empName;
 private int age;
 
 public int getEmpId() {
  return empId;
 }
 public void setEmpId(int empId) {
  this.empId = empId;
 }
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
}

EmployeeDAO interface

public interface EmployeeDAO {
 public int save(Employee employee);
 
 public void update(Employee employee);
 
 public void deleteEmpById(int empId);
}

EmployeeDAOImpl class

import java.util.HashMap;

import java.util.Map;
import org.netjs.dao.EmployeeDAO;
import org.netjs.model.Employee;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;

public class EmployeeDAOImpl implements EmployeeDAO {
    private NamedParameterJdbcTemplate namedJdbcTemplate; 
    
    final String INSERT_QUERY = "insert into employee (name, age) values (:name, :age)";
    final String UPDATE_QUERY = "update employee set age = :age where id = :id";
    final String DELETE_QUERY = "delete from employee where id = :id";
    
    public NamedParameterJdbcTemplate getNamedJdbcTemplate() {
        return namedJdbcTemplate;
    }

    public void setNamedJdbcTemplate(NamedParameterJdbcTemplate namedJdbcTemplate) {
        this.namedJdbcTemplate = namedJdbcTemplate;
    }

    @Override
    public int save(Employee employee) {
        // Creating map with all required params
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("name", employee.getEmpName());
        paramMap.put("age", employee.getAge());
        // Passing map containing named params
        return namedJdbcTemplate.update(INSERT_QUERY, paramMap);  
    }

    @Override
    public void update(Employee employee) {
        // Adding params using MapSqlParameterSource class
        SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("age", employee.getAge()).addValue("id", employee.getEmpId());
        int status = namedJdbcTemplate.update(UPDATE_QUERY, namedParameters); 
        if(status != 0){
            System.out.println("Employee data updated for ID " + employee.getEmpId());
        }else{
            System.out.println("No Employee found with ID " + employee.getEmpId());
        }
    }

    @Override
    public void deleteEmpById(int empId) {
        // Adding params using MapSqlParameterSource class
        SqlParameterSource namedParameters = new MapSqlParameterSource("id", empId);
        int status = namedJdbcTemplate.update(DELETE_QUERY, namedParameters);
        if(status != 0){
            System.out.println("Employee data deleted for ID " + empId);
        }else{
            System.out.println("No Employee found with ID " + empId);
        }
    }
}

This class contains namedJdbcTemplate property which will be wired by the Spring framework. In the save method named parameters are stored in a Map and that map is passed. In the update method another option MapSqlParameterSource class is used which has addValue method. Using the addValue method key, value pair is stored and later passed to the query.

Also notice how you are not writing any code for getting or closing connection, exception handling. All that fixed part is managed by the template class itself.
If there is any SQLException thrown that is also caught by JDBCTemplate and translated to one of the DataAccessException and rethrown.

Full XML configuration

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- For reading properties files --> <context:property-placeholder location="classpath:config/db.properties" /> <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg ref="dataSource"></constructor-arg> </bean> <bean id="employeeDAO" class="org.netjs.daoimpl.EmployeeDAOImpl"> <property name="namedJdbcTemplate" ref="namedJdbcTemplate"></property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value = "${db.driverClassName}" /> <property name="url" value = "${db.url}" /> <property name="username" value = "${db.username}" /> <property name="password" value = "${db.password}" /> <property name="initialSize" value = "${pool.initialSize}" /> </bean> </beans>

Here note that in the bean definition for NamedParameterJdbcTemplate, data source property is passed as a constructor argument.

Test class

You can use the following code in order to test the insertion, update and deletion.

import org.netjs.dao.EmployeeDAO;
import org.netjs.model.Employee;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
        
        EmployeeDAO dao=(EmployeeDAO)context.getBean("employeeDAO");  
        Employee emp = new Employee();
        emp.setEmpName("John");
        emp.setAge(25);
        int status = dao.save(emp);  
        System.out.println(status);  
        // For update
        emp.setEmpId(9);
        emp.setAge(25);
        dao.update(emp);
        
        // For delete
        dao.deleteEmpById(10);
    }
}

Using automatic configuration with @Repository annotation

You can also use component scanning to automatically scan and wire the classes. For that you can use @Repository annotation with your DAO implementation classes and @Autowired annotation to automatically wire dependencies.

In that case your EmployeeDAOImpl will look like this -

import java.util.HashMap;
import java.util.Map;

import org.netjs.dao.EmployeeDAO;
import org.netjs.model.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository;

@Repository
public class EmployeeDAOImpl implements EmployeeDAO {
    private NamedParameterJdbcTemplate namedJdbcTemplate; 
    
    final String INSERT_QUERY = "insert into employee (name, age) values (:name, :age)";
    final String UPDATE_QUERY = "update employee set age = :age where id = :id";
    final String DELETE_QUERY = "delete from employee where id = :id";
    
    @Autowired
    public EmployeeDAOImpl(NamedParameterJdbcTemplate namedJdbcTemplate){
        this.namedJdbcTemplate = namedJdbcTemplate;
    }
    

    @Override
    public int save(Employee employee) {
        // Creating map with all required params
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("name", employee.getEmpName());
        paramMap.put("age", employee.getAge());
        // Passing map containing named params
        return namedJdbcTemplate.update(INSERT_QUERY, paramMap);  
    }

    @Override
    public void update(Employee employee) {
        // Adding params using MapSqlParameterSource class
        SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("age", employee.getAge()).addValue("id", employee.getEmpId());
        int status = namedJdbcTemplate.update(UPDATE_QUERY, namedParameters); 
        if(status != 0){
            System.out.println("Employee data updated for ID " + employee.getEmpId());
        }else{
            System.out.println("No Employee found with ID " + employee.getEmpId());
        }
    }

    @Override
    public void deleteEmpById(int empId) {
        // Adding params using MapSqlParameterSource class
        SqlParameterSource namedParameters = new MapSqlParameterSource("id", empId);
        int status = namedJdbcTemplate.update(DELETE_QUERY, namedParameters);
        if(status != 0){
            System.out.println("Employee data deleted for ID " + empId);
        }else{
            System.out.println("No Employee found with ID " + empId);
        }
    }
}

XML Configuration

XML configuration will also change as you have to provide the base package to scan and you can also comment the bean definition for EmployeeDAO as it will be done automatically.

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.netjs.daoimpl" /> <!-- For reading properties files --> <context:property-placeholder location="classpath:config/db.properties" /> <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg ref="dataSource"></constructor-arg> </bean> <!-- <bean id="employeeDAO" class="org.netjs.daoimpl.EmployeeDAOImpl"> <property name="namedJdbcTemplate" ref="namedJdbcTemplate"></property> </bean> --> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value = "${db.driverClassName}" /> <property name="url" value = "${db.url}" /> <property name="username" value = "${db.username}" /> <property name="password" value = "${db.password}" /> <property name="initialSize" value = "${pool.initialSize}" /> </bean> </beans>

That's all for this topic Insert\Update using NamedParameterJDBCTemplate in Spring framework. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Select query using JDBCTemplate in Spring framework
  2. Data access in Spring framework
  3. Configuring DataSource in Spring Framework
  4. How to inject prototype scoped bean in singleton bean
  5. What is Dependency Injection in Spring

You may also like -

>>>Go to Spring tutorial page