Core Java

Optional Fields in JPA Entity Example

1. Introduction

JPA Entity can have optional fields as not every data is needed for every operation. In this example, I will create a simple Spring Data JPA application that shows how to define the optional fields and retrieve the optional data from a database.

2. Setup

In this step, I will create a Spring boot gradle project along with Lombok, Spring Data JPA, Rest, and H2 libraries via Spring Initializer.

Jpa Optional Field Project
Figure 1 Jpa Optional Field Project

Here is the generated build.gradle file. No modification is needed.

build.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.3.5'
	id 'io.spring.dependency-management' version '1.1.6'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(17)
	}
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-data-rest'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
	
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
	useJUnitPlatform()
}

2.1 Generated Spring Boot Application

No modification is needed for the generated DemoOptionalFieldsApplication.java.

DemoOptionalFieldsApplication.java

package com.example.demo_OptionalFields;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoOptionalFieldsApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoOptionalFieldsApplication.class, args);
	}

}

2.2 Generated Spring Properties

In this step, I will update the generated application.properties to enable the logger for SQL statements.

application.properties

spring.application.name=demo-OptionalFields

spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true
  • Line 3, 4: enable the SQL logging.

3. Jpa Optional Field Entity

In this step, I will create an OptionalFieldsEntity.Java class that includes an optional field – usedName and two projections: IdName and Names.

OptionalFieldsEntity.java

package com.example.demo_OptionalFields;

import org.springframework.data.rest.core.config.Projection;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Entity
@Table(name = "T_DEMOTABLE")
@NoArgsConstructor
public class OptionalFieldsEntity {

	@Id
	@GeneratedValue
	private Long id;

	@Column(name = "T_NAME", nullable = false)
	private String name;

	@Column(name = "T_USED_NAME", nullable = true)
	private String usedName;
	
	@Projection(name = "idName", types = { OptionalFieldsEntity.class })
	public interface IdName {
		Long getId();
		String getName();
	}

	@Projection(name = "Names", types = { OptionalFieldsEntity.class })
	public interface Names {
		String getName();
		String getUsedName();
	}

}
  • Line 14, 15: annotates with @Entity and @Table and the database table name is “T_DEMOTABLE“.
  • Line 23: annotates @Column with nullable=false attribute for a mandatory field.
  • Line 26: annotates @Column with nullable=true attribute for an optional field.
  • Line 29, 35: annotates @Projection with a different grouping of fields.

4. Jpa Optional Field Repository

In this step, I will create an OptionalFieldsRepo.java that extends from JpaRepository. It has three methods:

  • finalAllIdName: annotates @Query with HQL query and returns the result as a list of the projection IdName interface.
  • finalAllNames: similar to finalAllIdName but returns a list of the Names projection.
  • finalAllNamesWithoutUsedName: annotates @Query with raw SQL query and returns results as a list of OptionalFieldsEntity.

OptionalFieldsRepo.java

package com.example.demo_OptionalFields;

import java.util.List;

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

@Repository
public interface OptionalFieldsRepo extends JpaRepository<OptionalFieldsEntity, Long> {

	@Query(value = "SELECT idName from OptionalFieldsEntity idName")
	List<OptionalFieldsEntity.IdName> finalAllIdName();

	@Query(value = "SELECT names from OptionalFieldsEntity names")
	List<OptionalFieldsEntity.Names> finalAllNames();

	@Query(value = "SELECT * from T_DEMOTABLE where t_used_name is null", nativeQuery = true)
	List<OptionalFieldsEntity> finalAllNamesWithoutUsedName();

}
  • Line 12, 13: use a native HQL query to return the IdName projection.
  • Line 15, 16: use a native HQL query to return the Names projection.
  • Line 18, 19: use a native raw SQL query to return the OptionalFieldsEntity. Note: nativeQuery = true.

5. JPA Optional Field Test

In this step, I will create an OptionalFieldsRepoTest.java that has three tests to save and verify the optional field data via findAll methods.

OptionalFieldsRepoTest.java

package com.example.demo_OptionalFields;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.example.demo_OptionalFields.OptionalFieldsEntity.Names;

@SpringBootTest
class OptionalFieldsRepoTest {

	@Autowired
	private OptionalFieldsRepo testClass;

	private OptionalFieldsEntity buildData(String name, String usedName) {
		OptionalFieldsEntity user1 = new OptionalFieldsEntity();
		user1.setName(name);
		if (usedName != null) {
			user1.setUsedName(usedName);
		}
		return user1;
	}

	@Test
	void test_findAll_hql() {
		testClass.save(buildData("Mary", "Shuning"));
		testClass.save(buildData("Zheng", null));

		List<OptionalFieldsEntity> allData = testClass.findAll();
		assertEquals("Shuning", allData.get(0).getUsedName());
		assertNull(allData.get(1).getUsedName());
	}

	@Test
	void test_findAll_projection() {
		testClass.save(buildData("Mary", "Shuning"));
		testClass.save(buildData("Zheng", null));

		List<OptionalFieldsEntity.IdName> allData = testClass.finalAllIdName();
		assertEquals("Mary", allData.get(0).getName());
		assertEquals("Zheng", allData.get(1).getName());

		List<Names> names = testClass.finalAllNames();
		assertEquals("Mary", names.get(0).getName());
		assertEquals("Zheng", names.get(1).getName());
		assertEquals("Shuning", names.get(0).getUsedName());
		assertNull(names.get(1).getUsedName());
	}

	@Test
	void test_findAll_raw_sql() {
		testClass.save(buildData("Mary", "Shuning"));
		testClass.save(buildData("Zheng", null));

		List<OptionalFieldsEntity> allData = testClass.finalAllNamesWithoutUsedName();
		assertEquals(1, allData.size());
		assertEquals("Zheng", allData.get(0).getName());
		assertNull(allData.get(0).getUsedName());

	}

}
  • Line 35, 36, 51, 52, 63: the optional field – useName – can have a null value.

Ran the Junit test and verified tests were passed.

Jpa Optional Field Tests
Figure 2 Jpa Optional Field Tests

6. Conclusion

In this example, I created a simple Spring boot application that defined a JPA entity with an optional field and created a repository interface to retrieve the data via both Spring projection interface and native query with HQL and raw SQL.

7. Download

This was an example of a gradle project that included Jpa optional fields.

Download
You can download the full source code of this example here: Optional Fields in JPA Entity Example

Mary Zheng

Mary graduated from the Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She worked as a lead Software Engineer where she led and worked with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button