Sunday, 30 June 2013

Spring Data - REST

Gone are the days when people used to take significant amount of time to expose REST service APIs for their domain objects. "SPRING DATA - REST" project is under active development to make your life easy. Its 1.0.0.RC3 version was released on Sep 14, 2012. We can expect the final build to be released soon.

The goal of this project is to expose CRUD operations on JPA entities in the form of REST services.

You can focus on defining your domain classes and SPRING DATA - REST framework will do the job of exposing them in the form of REST services (In simple words you don’t have to write even a single line of code to achieve this.) It is just a matter of configuring your project rightly with the framework.

Here are few simple steps to get started with.

Step 1 :

Add the following maven dependency in your pom.xml :

<dependency>
  <groupId>org.springframework.data</groupId>
  <artifactId>spring-data-rest-webmvc</artifactId>
  <version>1.0.0.RC3</version>
</dependency>

Use the following repository to resolve this dependency :

<repository>
  <id>spring-milestone</id>
  <name>Spring Maven MILESTONE Repository</name>
  <url>http://repo.springsource.org/libs-milestone</url>
</repository>

Step 2 :

Add RepositoryRestExporterServlet in your web.xml which will act as an exporter for your JPA repositories :

<servlet>
 <servlet-name>exporter</servlet-name>
 <servlet-class>org.springframework.data.rest.webmvc.RepositoryRestExporterServlet</servlet-class>
 <load-on-startup>1</load-on-startup>
</servlet> 

<servlet-mapping>
 <servlet-name>exporter</servlet-name>
 <url-pattern>/*</url-pattern>
</servlet-mapping>

Step 3 :

No change is needed in your Spring JPA config file. Here is my config file for your reference :


<?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:jpa="http://www.springframework.org/schema/data/jpa"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd         http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd
 http://www.springframework.org/schema/data/jpa
 http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<context:property-placeholder location="classpath*:*.properties" />
<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${database.driverClassName}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.username}"/>
        <property name="password" value="${database.password}"/>
</bean>  

<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 <property name="packagesToScan" value="com.viracct.rest.demo" />
 <property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
     <property name="showSql" value="${hibernate.showSql}" />
     <property name="generateDdl" value="true" />
        </bean>
</property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
 <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<jpa:repositories base-package="com.viracct.rest.demo.dao" />

</beans>

Here I have defined some simple JPA entities - Company, Department, Employee.

package com.viracct.rest.demo.domain;

@Entity

public class Company {

 @Id

 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;
 private String name;
 private String description;
 @OneToMany
 private List<Department> departments;

 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

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

 public String getDescription() {
  return description;
 }

 public void setDescription(String description) {
  this.description = description;
 }

 public List<Department> getDepartments() {
  return departments;
 }

 public void setDepartments(List<Department> departments) {
  this.departments = departments;
 }

}


@Entity

public class Department {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;
 private String name;
 private String description;
 @OneToMany
 private List<Employee> employees;

 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

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

 public String getDescription() {
  return description;
 }

 public void setDescription(String description) {
  this.description = description;
 }

 public List<Employee> getEmployees() {
  return employees;
 }

 public void setEmployees(List<Employee> employees) {
  this.employees = employees;
 }

}



@Entity

public class Employee {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;
 private Long code;
 private String name;
 private String designation;

 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 public Long getCode() {
  return code;
 }

 public void setCode(Long code) {
  this.code = code;
 }

 public String getName() {
  return name;
 }

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

 public String getDesignation() {
  return designation;
 }

 public void setDesignation(String designation) {
  this.designation = designation;
 }

}

Here are the JPA repositories for the entities mentioned above.

package com.viracct.rest.demo.dao;

public interface CompanyRepository extends JpaRepository {
}

public interface DepartmentRepository extends JpaRepository {
}

public interface EmployeeRepository extends JpaRepository {
}

Once you have deployed this application, you can see the service end points for your entities by hitting the following URL:  http://localhost:8080/restdemo and the output will be :

{
  "links" : [ {
    "rel" : "department",
    "href" : "http://localhost:8080/restdemo/department"
  }, {
    "rel" : "company",
    "href" : "http://localhost:8080/restdemo/company"
  }, {
    "rel" : "employee",
    "href" : "http://localhost:8080/restdemo/employee"
  } ],
  "content" : [ ]
}

You can browse employee objects with the following URL : http://localhost:8080/restdemo/employee and the output will be :


{
  "links" : [ ],
  "content" : [ {
    "links" : [ {
      "rel" : "self",
      "href" : "http://localhost:8080/restdemo/employee/1"
    } ],
    "name" : "Anuja Kumar",
    "designation" : "Software Developer",
    "code" : 100051
  } ],
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 1
  }
}

Similarly you can access department object with id=2 with the following URL : http://localhost:8080/restdemo/department/2 and the output will be :

{
  "links" : [ {
    "rel" : "self",
    "href" : "http://localhost:8080/restdemo/department/2"
  }, {
    "rel" : "department.Department.employees",
    "href" : "http://localhost:8080/restdemo/department/2/employees"
  } ],
  "description" : "Product Development Team",
  "name" : "Development"
}

Now if you want to access employee with employee-id=1 from department with department-id=2, you can get that using the following URL: http://localhost:8080/restdemo/department/2/employees/1 and the output will be :

{
  "links" : [ {
    "rel" : "self",
    "href" : "http://localhost:8080/restdemo/employee/1"
  }, {
    "rel" : "department.Department.employees",
    "href" : "http://localhost:8080/restdemo/department/2/employees/1"
  } ],
  "name" : "Anuja Kumar",
  "designation" : "Software Developer",
  "code" : 100051
}

Friday, 28 June 2013

Sharing CSS Properties Between Classes

Very recently I came across a situation where one of the existing CSS class was a perfect fit for it except for its background property. Just because 1 property was unwanted, I thought to override it with 'style' attribute and setting the background with no image. Very straightforward! Despite the simplicity of this solution, I felt to check what is the recommended practice in such scenarios...may be putting needed common features in one class and inheriting from it. I stumbled across the question- Does CSS support inheritance? (I felt stupid for not knowing the answer).
There are tools/frameworks like OOCSS and LESS which do support inheritance. Without any of them, the better approach to my scenario would be to have a css class and write common properties in it. Then repeat the css class and add rest of the properties to it. Here it is:

.oldClass, .newClass{
 common properties go here
}

.old class{
 the extra one goes here e.g. background: url("../images/arrow.png");
}