This documentation is not maintained. Please refer to doc.castsoftware.com/technologies to find the latest updates.

Summary: This document provides information about the extension providing Spring Data JPA and Spring Data JDBC  support for JEE.


What's new

In this new release version all the links are created at analysis level.

Extension ID

com.castsoftware.springdata

What's new?

See Spring Data - 2.0 - Release Notes for more information.

Description

In what situation should you install this extension?

This extension is specifically targeted at the Spring Data framework and should be used in conjunction with the JEE Analyzer extension. CRUD operations and Named Queries (@NamedQuery and @NamedQueries Annotations) are supported for JPA and JDBC.

In addition, this extension provides support for JdbcTemplate which is the main Spring JDBC API, which allows access to almost all functionalities of this framework. We focus here on running basic queries and running queries with named parameters.

When client code uses any of these coding mechanisms, the extension will create the links from the calling method to the database table. This helps form the complete transaction.

Links creation

The following links will be generated:

useSelectLink
  • find..By methods
  • SELECT sql query
useDeleteLink
  • delete, delete.., flush methods
  • DELETE sql query
useUpdateLink
  • save, save.. methods
  • UPDATE sql query
useInsertLink
  • INSERT sql query
accessReadLink
  • read..By, query..By, count..By, get..By, exists, fetch, count, read methods

Features

Managing Crud method calls

Spring Data Repository abstraction is used to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores. A number of CRUD methods are provided to improve data access. Some of the CRUD methods are as follows:

  • count
  • deleteById
  • delete
  • deleteAll
  • deleteAllInBatch
  • deleteInBatch
  • exists
  • existsById
  • findAll
  • findById
  • findOne
  • flush
  • save
  • saveAll
  • saveAndFlush

Using CRUD methods with Spring Data JPA


@Override
public ProductsEntity getProductById(String pIdProd) {
    if (logger.isInfoEnabled()) {
        logger.info(new StringBuilder("Get product by id =").append(pIdProd).toString());
    }
    BsProduitsEntity productsEntity = productRepository.findOne(pIdProd);
}

We do the same in Spring Data JPA  extension for methods calling JpaRepository methods as illustrated below.

@Override
public List<ProductsEntity> findAll() {
    return productRepository.findAll();
}

Where findAll() si implemented here:

org.springframework.data.jpa.repository.JpaRepository.findAll

package org.springframework.data.jpa.repository ;
@org.springframework.data.repository.NoRepositoryBean()
public interface JpaRepository<T extends java.lang.Object, ID extends java.lang.Object> extends org.springframework.data.repository.PagingAndSortingRepository<T, ID>,org.springframework.data.repository.query.QueryByExampleExecutor<T>
{
  public  java.util.List<T> findAll() ;
}

The same use case for JpaSpecificationExecutor methods:

package org.springframework.data.jpa.repository ;
public interface JpaSpecificationExecutor<T extends java.lang.Object>
{
  public  java.util.List<T> findAll(@org.springframework.lang.Nullable() org.springframework.data.jpa.domain.Specification<T> p1) ;
}
public List<TransactionCDTO> searchProducts(BasketsSearchBO criteria) {
	...
	List<TransactionCDTO> dtos = productRepo.findAll(fullProductsIds);
	...
}

Using CRUD methods with Spring Data JDBC

Spring Data JDBC uses a syntax that is similar to Spring Data JPA. We can create a Spring Data JDBC repository by extending the Repository, CrudRepository, or PagingAndSortingRepository interface. By implementing CrudRepository, we receive the implementation of the most commonly used methods like save, delete, and findById, among others, as listed for above.

Custom JDBC Repository

In Spring Data JDBC, we write queries in plain SQL. Custom methods are decorated with the @Query annotation and inside we have the SQL query.

interface LegoSetRepository extends CrudRepository<LegoSet, Integer> {

	@Query("SELECT m.name model_name, m.description, l.name set_name" +
			"  FROM model m" +
			"  JOIN lego_set l" +
			"  ON m.lego_set = l.id" +
			"  WHERE :age BETWEEN l.min_age and l.max_age")
	List<ModelReport> reportModelForAge(@Param("age") int age);

	@Modifying
	@Query("UPDATE model set name = lower(name) WHERE name <> lower(name)")
	int lowerCaseMapKeys();
}
public void customQueries() {
	List<ModelReport> report = repository.reportModelForAge(6);
}

Named Queries

Using JPA NamedQueries

The @NamedQuery annotations can be used individually or can coexist in the class definition for an entity. The annotations define the name of the query, as well as the query text. In a real application, you will probably need multiple named queries defined on an entity class. For this, you will need to place multiple @NamedQuery annotations inside a @NamedQueries annotation. @NamedNativeQueries and @NamedNativeQuery are also supported and their functionality is the same.

Example @NamedQueries code:

@Entity
@Table(name = "users")
@NamedQuery(name = "User.findByEmailAddress", query = "select u from User u where u.emailAddress = ?1")
@NamedQueries(value = {
		@NamedQuery(name = "User.findByLastname", query = "select u from User u where u.lastname = ?1") })
public class User {
	...
}


import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
...
/**
 * UserRepository demonstrates the method name query generation.
 */
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
	User findByEmailAddress(String emailAddress);
	List<User> findByLastname(String lastname);
}
@Override
public void run(String... args) throws Exception {
	...
	System.out.println(" ---------------@NamedNativeQuery ---------------------");
	System.out.println("--------------findByEmailAddress -----------------");
		
	User user2 = userRepository.findByEmailAddress("ramesh24@gmail.com");
		
	System.out.println(" ---------------@NamedNativeQueries ---------------------");
	System.out.println("--------------findByLastname -----------------");
		
	List<User> user3 = userRepository.findByLastname("Fadatare");
}

The code listed above will produce the following links and objects when the Spring Data extension is installed:

Using JPA NamedQueries via XML

NamedQuery works with annotations as well as with XML files. The application's web.xml file contains the param-value which indicates the XML file that contains the named query. Using the Spring Data extension, proper links can be created from the methods which call these queries to the data base table.

web.xml

<web-app id="WebApp_ID" version="2.4"
	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

	<display-name>Spring-data Application</display-name>
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/spring-servlet.xml,/WEB-INF/orm.xml
		</param-value>
	</context-param>

orm.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">

  <!--  <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
    <mapping-file>META-INF/orm.xml</mapping-file>
    <exclude-unlisted-classes/>
  </persistence-unit> -->
  
<!-- Named Query using XML Configuration -->
	<named-query name="User.findByEmailAddress">
		<query>select u from User u where u.emailAddress = ?1</query>
	</named-query>
</persistence>


@Entity
@Table(name = "users")
public class User {
	...
}


import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
...
/**
 * UserRepository demonstrates the method name query generation.
 */
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
	User findByEmailAddress(String emailAddress);
}

The code listed above will produce the following links and objects when the Spring Data extension is installed. A link will be created from the method namedQueryCall to the table users:

Using JDBC NamedQueries

@Entity
@Table(name = "SCHEDULING_ORDER")
@NamedQueries({ @NamedQuery(name = "Order.findByOrderNumberAndAppointmentType",
query = "SELECT o FROM Order o LEFT JOIN FETCH o.appointments "
		+ "WHERE o.orderNumber = :orderNumber and o.appointmentType = :appointmentType") })
public class Order {
	...
}
@Override
public Order findByOrderNumberAndAppointmentType(final OrderNumber orderNumber,
    final AppointmentType appointmentType) throws ObjectNotFoundException
{
    Query query = this.em.createNamedQuery("Order.findByOrderNumberAndAppointmentType");
}

Using JDBC NamedQueries via XML

<named-query name="ActivityTask.queryActivityById">
	<query>SELECT activityId FROM ActivityTask</query>
</named-query>

<entity class="com.amdocs.oss.aff.omx.impl.model.ActivityTask"
		access="FIELD" metadata-complete="true">

	<table name="ACTIVITY_TASK_TABLE" />

	<attributes>

		<id name="activityId">
			<column name="ACTIVITY_ID" />
		</id>
		<basic name="taskId">
			<column name="TASK_ID" updatable="true" />
		</basic>
		<basic name="projectId">
			<column name="PROJECT_ID" updatable="true" />
		</basic>
	</attributes>
</entity>
private static final String QUERY_ACTIVITY_BY_ID = "ActivityTask.queryActivityById";

public  ActivityTask getActivityByActivityId(String activityId) {

		EntityManager entityManager = emp.getEntityManager();
		Query query = entityManager.createNamedQuery(QUERY_ACTIVITY_BY_ID );
		query.setParameter("activityId", activityId);
		ActivityTask activityTask = (ActivityTask) query.getSingleResult();
		return activityTask;
}

Creating query by inference in Spring Data JPA

The query builder mechanism of Spring Data is useful for building queries over entities of the repository. The mechanism is to create the query for patterns such as  find..By, read..By, query..By, count..By, and get..By. Spring Data parses this string as it may contain further expressions, such as a Distinct to set a distinct flag on the query to be created. However, the first By acts as delimiter to indicate the start of the actual criteria. In the Spring Data extension, the transaction link can be drawn from these methods to the database table.
 

import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
 
@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
 
}


import java.util.List;
import org.springframework.data.repository.query.Param;
 
public interface SettingRepository extends BaseRepository<Setting, Long> {
    List<Setting> findByKey(@Param("key") String key);
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;

@Entity
@Table(name = "TABLE_SETTING")
public class Setting {
	...
}
public getMessage(String key) {
    List<Setting> settings = settingRepository.findByKey(key);
    ...
}

The code listed above will produce the following links and objects when the Spring Data extension is installed:

 

Creating query by inference in Spring Data JPA with @Query annotation

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
	@Query("select u from Users u where u.emailAddress = ?1")
	User findByEmailAddress(String emailAddress);
}
@Override
public void run(String... args) throws Exception {
	...
	User user = userRepository.findByEmailAddress("john@gmail.com");
	System.out.println(user.toString());
	...
}

Creating query by inference in Spring Data JPA with @Query annotation : support of nativeQuery parameter

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
	@Query(value = "select u from Users u where u.emailAddress = ?1", nativeQuery = true)
	User findByEmailAddress(String emailAddress);
}
@Override
public void run(String... args) throws Exception {
	...
	User user = userRepository.findByEmailAddress("john@gmail.com");
	System.out.println(user.toString());
	...
}

Handling Query Dsl in Spring Data JPA

Querydsl is a framework which enables the construction of statically typed SQL-like queries, instead of writing queries as inline strings.Querydsl for JPA/Hibernate is an alternative to both JPQL and JPA 2 Criteria queries. It combines the dynamic nature of Criteria queries with the expressiveness of JPQL and all that in a fully typesafe manner.

To include Querydsl in the project, dependencies should be present in the project.

<properties>
    <querydsl.version>4.1.3</querydsl.version>
</properties>
<dependencies>

    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-apt</artifactId>
        <version>${querydsl.version}</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-jpa</artifactId>
        <version>${querydsl.version}</version>
    </dependency>

</dependencies>

The querydsl-apt dependency is an annotation processing tool. It allows processing of annotations in source files before they move on to the compilation stage. This tool generates the so called Q-types — classes that directly relate to the entity classes of your application, but are prefixed with letter Q. For instance, if you have a User class marked with the @Entity annotation in your application, then the generated Q-type will reside in a QUser.java source file.

Example: Product.java

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="PRODUCT")
public class Product {

	@Id
	private Long id;
	
	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 double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public Category getCategory() {
		return category;
	}

	public void setCategory(Category category) {
		this.category = category;
	}

	private String name;
	
	private double price;
	
	@ManyToOne
	private Category category;
}

DemoService.java

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import static com.mysema.demo.QProduct.product;

import com.querydsl.jpa.impl.JPAQuery;

public class DemoService {
	
	public List<Product> findProductsByNameAndCategoryId(String name, Long categoryId){
		QProduct myQproduct;
		EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("persistence");
        EntityManager entityManager = entityManagerFactory.createEntityManager();

		QCategory cat = QCategory.category;
		JPAQueryFactory qry = new JPAQueryFactory(entityManager);
		qry.from(myQproduct);				
		
		if(name != null){
			qry.select(myQproduct.name.like(name));
		}
		
		if(categoryId != null){
			qry.select(myQproduct.category.catId.eq(categoryId));
		}
		
		return qry.fetch();
	}

	private JPAQuery createQuery(QProduct product,JPAQuery qr) {
		return (JPAQuery) qr.from(product);
	}

}

The following link is created with above code when the Spring Data extension is used:

Support for Spring Boot Starter

Spring-boot-starter-data-jpa POM provides a quick way to get started. It provides the following key dependencies

  • Hibernate: One of the most popular JPA implementations.
  • Spring Data JPA: Makes it easy to implement JPA-based repositories.

The Spring Boot application invokes the application which uses the Spring Data JPA. For example, the source code below shows how the Spring Boot Starter invokes the Spring Data JPA application:

Application.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.web.config.EnableSpringDataWebSupport;

import com.onlinetutorialspoint.entity.Person;
import com.onlinetutorialspoint.repository.PersonRepository;
import com.onlinetutorialspoint.service.PersonService;

@SpringBootApplication
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class);
	}
	@Autowired
	PersonService personService;
	@Bean
	public CommandLineRunner run(PersonRepository repository) {
		return (args) -> {
			Person person = new Person();
			person.setName("Chandra Shekhar Goka");
			person.setCity("Hyderabad");
			Person p = savePersonDetails(person);
			
			System.out.println("Person Id : "+p.getId() +" Person Name : "+p.getName());
		};
	}
	
	public Person savePersonDetails(Person p){
		return personService.savePerson(p);
	}
	
	public Person getPerson(Person person){
		return personService.getPerson(person.getId());
	}
}

PersonService.java

@Service
@Transactional
public class PersonService {
	@Autowired
	PersonRepository personRepo;

	public void savePersonDetails(PersonDTO personDto) {
		try {
			Person person = new Person();
			person.setCity(personDto.getpCity());
			person.setName(personDto.getpName());
			person.setId(personDto.getPid());
			personRepo.save(person);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public Person savePerson(Person person) {
		return personRepo.save(person);
	}
}

Person.java

@Entity
@Table(name = "person")
public class Person {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	private String name;
	@Column(name="pcity")
	private String city;

	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}

	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 getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	@Override
	public String toString() {
		return "Person [pid=" + id + ", pName=" + name + ", pCity=" + city
				+ "]";
	}

}

The code above will produce the following objects and links:

Support for Spring JDBC

To populate the databases, Spring JDBC JdbcTemplates and NamedParameterJdbcTemplate APIs are used. This extension supports them also.

Basic queries with JdbcTemplate

public class PersonDAOImpl implements PersonDAO {

	JdbcTemplate jdbcTemplate;
    
	private static final String SQL_FIND_PERSON = "select * from people where id = ?";
	private static final String SQL_DELETE_PERSON = "delete from people where id = ?";
	private static final String SQL_UPDATE_PERSON = "update people set first_name = ?, last_name = ?, age  = ? where id = ?";
	private static final String SQL_GET_ALL = "select * from people";
	private static final String SQL_INSERT_PERSON = "insert into people(id, first_name, last_name, age) values(?,?,?,?)";

	@Autowired
	public PersonDAOImpl(DataSource dataSource) {
		jdbcTemplate = new JdbcTemplate(dataSource);
	}

	public Person getPersonById(Long id) {
		return jdbcTemplate.queryForObject(SQL_FIND_PERSON, new Object[]{id}, new PersonMapper());
	}

	public List<Person> getAllPersons() {
		return jdbcTemplate.query(SQL_GET_ALL, new PersonMapper());
	}

	public boolean deletePerson(Person person) {
		return jdbcTemplate.update(SQL_DELETE_PERSON, person.getId()) > 0;
	}

	public boolean updatePerson(Person person) {
		return jdbcTemplate.update(SQL_UPDATE_PERSON, person.getFirstName(), person.getLastName(), person.getAge(),
				person.getId()) > 0;
	}

	public boolean createPerson(Person person) {
		return jdbcTemplate.update(SQL_INSERT_PERSON, person.getId(), person.getFirstName(), person.getLastName(),
				person.getAge()) > 0;
	}
}

Queries with NamedParameterJdbcTemplate

public Map<Long, UserDetail> getUsers(String subQuery, Map<String, Object> parameterValues) {
	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    MapSqlParameterSource parameters = new MapSqlParameterSource(parameterValues);
	String sqlQuery = "select usr as assigneeUser from Assigned_Users" 
					+ " where usr_id in ( " + subQuery + " )";
	userDetails = namedParameterJdbcTemplate.query(sqlQuery, parameters);
}

SimpleJdbcInsert

This API provides insert capabilities into a table. The methods calling execute(), executeBatch() or executeAndReturnKey() will be linked to tables. The withTableName() call helps identify the table.

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;

@Repository
public class Main
{
   private JdbcTemplate jdbcTemplate;
   private SimpleJdbcInsert simpleJdbcInsert;
   private SimpleJdbcCall simpleJdbcCall;

   @Autowired
   public void setDataSource(DataSource dataSource)
   {
      this.jdbcTemplate = new JdbcTemplate(dataSource);
      simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName(
            "Persons").usingGeneratedKeyColumns("id");
      this.simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate);
      Map<String, Object> args = new HashMap<String, Object>(2);
      args.put("personid", task.getPersonId());
      simpleJdbcInsert.execute(args);
   }
}

SimpleJdbcCall

This API represents a call to a stored procedure or a stored function. In this extension we handle the stored procedures. The methods calling execute() will be linked to procedures. The withProcedureName() call helps us identify the procedure.

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;

class Main
{
	private JdbcTemplate jdbcTemplateObject;
	public void setDataSource(DataSource dataSource) {
      this.dataSource = dataSource;
      this.jdbcTemplateObject = new JdbcTemplate(dataSource);
    }
    public Student getStudent(Integer id) {
      SimpleJdbcCall jdbcCall = new SimpleJdbcCall(dataSource).withProcedureName("getRecord");
      SqlParameterSource in = new MapSqlParameterSource().addValue("in_id", id);
      Map<String, Object> out = jdbcCall.execute(in);
    }
}

Table declaration:

CREATE TABLE Student(
   ID   INT NOT NULL AUTO_INCREMENT,
   NAME VARCHAR(20) NOT NULL,
   AGE  INT NOT NULL,
   PRIMARY KEY (ID)
);

Procedure declaration:

DELIMITER $$

DROP PROCEDURE IF EXISTS `TEST`.`getRecord` $$
CREATE PROCEDURE `TEST`.`getRecord` (
IN in_id INTEGER,
OUT out_name VARCHAR(20),
OUT out_age  INTEGER)
BEGIN
   SELECT name, age
   INTO out_name, out_age
   FROM Student where id = in_id;
END $$

DELIMITER ;

Function Point, Quality and Sizing support

This extension provides the following support:

Function Points
(transactions)
Quality and Sizing
(tick)(error)

CAST AIP compatibility

This extension is compatible with:

CAST AIP release

Supported

8.3.x(tick)
8.2.x(tick)

Supported DBMS servers

This extension is compatible with the following DBMS servers:

CAST AIP releaseCSSOracleMicrosoft
All supported releases (see above)(tick)(tick)(error)

Prerequisites

(tick)

An installation of any compatible release of CAST AIP (see table above)

Dependencies with other extensions

Some CAST extensions require the presence of other CAST extensions in order to function correctly. The SPRING-DATA extension requires that the following other CAST extensions are also installed:

  • com.castsoftware.internal.platform (internal technical extension).

Note that when using the CAST Extension Downloader to download the extension and the Manage Extensions interface in CAST Server Manager to install the extension, any dependent extensions are automatically downloaded and installed for you. You do not need to do anything.

Download and installation instructions

Please see:

The latest release status of this extension can be seen when downloading it from the CAST Extend server.

Packaging, delivering and analyzing your source code

Once the extension is installed, no further configuration changes are required before you can package your source code and run an analysis.

What results can you expect?

This extension will create the links between objects that are created by the JEE analyzer, the JAVA Methods, and the TABLES created by the SQL Analyzer.

Limitations

In QueryDsl framework, the generated Q-type classes must be present in the source files. The code analysis is based on their presence. If it is not the case, no link will be created between calling methods and tables.