How to create Search Functionality using Optional Parameter in Spring Boot - spring

I want to build a search functionality in my application. There are many parameters which can be optional.
Model
#Getter
#Setter
#EqualsAndHashCode(exclude = "inventoryInspectionReport")
#NoArgsConstructor
#Entity()
public class Inventory {
#SequenceGenerator(
name = "car_inventory_sequence",
sequenceName = "car_inventory_sequence",
allocationSize = 1
)
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "car_inventory_sequence"
)
private Long id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String owner;
#Column(nullable = false)
private String km_driven;
#Column(nullable = false)
private Integer price;
#Column
private String fuelType;
#Column
private String location;
#Column
private String insuranceValidity;
#Column
private String rto;
}
Controller
#GetMapping("/buy-car")
public String showBuyCarPageList(Model model,
#RequestParam("page") Optional<Integer> page,
#RequestParam("size") Optional<Integer> size
){
int currentPage = page.orElse(1);
int pageSize = size.orElse(16);
Page<Inventory> pageObj = carInventoryService.listAllCarIfShow(currentPage, pageSize);
int totalPages = pageObj.getTotalPages();
long totalItems = pageObj.getTotalElements();
List<Inventory> carInventoryList = pageObj.getContent();
model.addAttribute("currentPage", 1);
model.addAttribute("totalPages", totalPages);
model.addAttribute("totalItems", totalItems);
model.addAttribute("carInfo", carInventoryList);
return "frontend/buy-car-list";
}
#Service
#AllArgsConstructor
public class InventoryServiceImpl implements InventoryService {
#Autowired
private Environment env;
InventoryRepository carInventoryRepository;
InventoryImagesRepository carInventoryImagesRepository;
#Override
public Page<Inventory> listAllCarIfShow(int pageNumber, int pageSize) {
Pageable pageable = PageRequest.of(pageNumber - 1, pageSize);
return carInventoryRepository.findAllByShow(true, pageable);
}
}
My question is, how i can create a search functionality? There can be some parameter null? How i can query or ignore the parameters?
Bellow is query samples
http://localhost:8080/buy-car?page=1&size=1&name=Car2
http://localhost:8080/buy-car?page=1&size=1&name=Car2&owner=1st
http://localhost:8080/buy-car?page=1&size=1&fuelType=Petrol&owner=1st
Sample form image

Assuming that you are using JPA. You can handle it by writing a query as below. This will ignore the where condition if the parameter is null.
#Repository
public class InventoryRepository extends JPARepository<Inventory, Long> {
#Query("SELECT i FROM Inventory i WHERE (:name is null or i.name = :name) and (:owner is null or i.owner = :owner)")
Page<Inventory> findAllByShow (String name, String owner, Pageable pageable);
}
PS: You need to update your Controller and Service layers to accept other parameters such as name, owner etc..

Related

JPA Failing to produce a proper SQL query when a parameter has a composite primary key

Today I came across a weird bug while trying to test a JPA update query and I'm wondering if this a SpringBoot bug.
I have the following entities
An Entry entity
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor(access = AccessLevel.PROTECTED, force = true)
public class Entry {
#Id
private String id;
#ManyToOne(targetEntity = User.class)
#JoinColumn(referencedColumnName = "username")
#NotNull
private final User username;
#Enumerated(EnumType.STRING)
#NotNull
private Type type;
#ManyToOne(targetEntity = Category.class)
#JoinColumns({#JoinColumn(referencedColumnName = "name"),#JoinColumn(referencedColumnName = "type"),#JoinColumn(referencedColumnName = "username")})
#NotNull
private Category category;
#Size(max = 45)
#NotBlank
private String description;
#NotNull
private Double amount;
#NotNull
private final Date createdAt;
private Timestamp lastUpdate;
#NotNull
private Boolean isDeleted;
public enum Type{
Income,Expense
}
}
A Category entity with a composite key
#Entity
#NoArgsConstructor(access = AccessLevel.PROTECTED, force = true)
#Setter
#Getter
#EqualsAndHashCode(of = {"id"})
#ToString(of = {"id"})
public class Category {
#EmbeddedId
private CategoryId id;
private final Timestamp createdAt = Timestamp.from(Instant.now());
#ManyToOne(targetEntity = User.class)
#JoinColumn(referencedColumnName = "username")
private final User user;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "category")
private List<Entry> entries;
public Category(String name, Type type, User user){
this.id = new CategoryId(name,type,user.getUsername());
this.user = user;
}
}
A CategoryID that is the embeddable composite key of the Category entity
#Data
#Embeddable
#AllArgsConstructor
#NoArgsConstructor(access = AccessLevel.PROTECTED)
#EqualsAndHashCode(of = {"name","type","username"})
public class CategoryId implements Serializable {
private String name;
#Enumerated(EnumType.STRING)
private Type type;
private String username;
}
The following repository
#Repository
public interface EntryRepository extends JpaRepository<Entry, String> {
Optional<Entry> findEntryById(String id);
#Modifying(clearAutomatically = true, flushAutomatically = true)
#Query(value = "UPDATE Entry e SET e.username = :username, e.type = :type, e.category = :category, e.description = :description, e.amount = :amount, e.createdAt = :date, e.lastUpdate = :lastUpdate, e.isDeleted = :isDeleted WHERE e.id = :id")
void update(#Param("id") String id,
#Param("username") User username,
#Param("type") Entry.Type type,
#Param("category") Category category,
#Param("description") String description,
#Param("amount") Double amount,
#Param("date") Date date,
#Param("lastUpdate") Timestamp lastUpdate,
#Param("isDeleted") Boolean isDeleted);
}
And finally the following Unit Test
#Test
void update() {
//given
User testUser = userRepository.save(new User("testUser#test.com","000000000000000000000000000000000000000000000000000000000000"));
Category testCategory = categoryRepository.save(new Category("Test Category", Entry.Type.Income,testUser));
Entry testEntry = new Entry("testEntry",testUser, Entry.Type.Income,
testCategory, "test",
0.0, new Date(343), from(now()), false);
System.out.println(testCategory);
entryRepositoryUnderTest.save(testEntry);
//when
entryRepositoryUnderTest.update("testEntry",testUser,Expense,testCategory,"testUpdated",1.0,new Date(346), from(now()),true);
Optional<Entry> actual = entryRepositoryUnderTest.findEntryById("testEntry");
System.out.println(actual.get().getCategory());
//then
assertThat(actual.get().getUsername()).isEqualTo(testUser);
assertThat(actual.get().getType()).isEqualTo(Expense);
assertThat(actual.get().getCategory()).isEqualTo(testCategory);
assertThat(actual.get().getDescription()).isEqualTo("testUpdated");
assertThat(actual.get().getAmount()).isEqualTo(1.0);
assertThat(actual.get().getIsDeleted()).isEqualTo(true);
}
When I run the test it fails and I get the following error message:
could not execute update query; SQL [update entry set username_username=?, type=?,category_name=?=category_type=?, description=?, amount=?, created_at=?, last_update=?, is_deleted=? where id=?]; nested exception is org.hibernate.exception.DataException: could not execute update query
As you can see here when SpringBoot is trying to produce a SQL query statement from my #Query parameter it can not properly extract the Category field from the parameters and inject it's composite embeddable key into the SQL statement. It has no problem extracting the User parameter because the User is an entity with an id that is not composite.
Is this a SpringBoot bug or am I missing something?
EDIT:
This is the structure of the database

PSQLException: ERROR: null value in column "person" violates not-null constraint when trying class-based projection

I cannot solve my problem, although following a documentation regarding class-based projection.
I always get the following error message:
PSQLException: ERROR: null value in column "person" violates not-null constraint
This is my entity class
#Entity
#Table(name="incomeoutgo", schema = "public")
public class IncomeOutgo extends AbstractPersistable<Long> {
#NotNull
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name ="id")
private Long id;
#NotNull
#Column(name="dayofweek")
private Date dayofweek;
#NotNull
#Size(min= 2, max= 100)
#Column(name="position")
private String position;
#NotNull
#Size(min = 5, max = 50)
#Column(name ="person")
private String person;
#NotNull
#Size(min= 1)
#Column(name="income")
private double income;
#NotNull
#Size(min= 2)
#Column(name="outgo")
private double outgo;
}
So does my Repository look like:
#Repository
public interface ChooseMonthRepository extends JpaRepository<IncomeOutgo, Date> {
#Query(value = "SELECT dayofweek, person, position, income, outgo FROM IncomeOutgo WHERE dayofweek >= :start_dayofmonth AND dayofweek <= :end_dayofmonth", nativeQuery = true)
List<DateChoiceDTO> findAllByDate(#Param("start_dayofmonth") Date start_dayofmonth, #Param("end_dayofmonth") Date end_dayofmonth);
}
This is my class-based projection
#AllArgsConstructor
#NoArgsConstructor
#Data
public class DateChoiceDTO {
Date dayofweek;
String person;
String position;
double income;
double outgo;
}
The Service class
#RequiredArgsConstructor
#Service
#Transactional(readOnly=true)
public class DateChoiceService {
private final ChooseMonthRepository incomeOutgoDateChoice;
public List<?> getAllForDateChoice(Date start_dayofmonth) {
Date lastDayOfMonth=java.util.Calendar.getInstance().getTime();
return incomeOutgoDateChoice.findAllByDate(start_dayofmonth, lastDayOfMonth);
}
}
And last but not least my Controller
#RequiredArgsConstructor
#Controller
#Validated
#RequestMapping(value = "/")
public class DateChoiceController {
private static final String DATE_CHOICE_VIEW = "DateChoice";
private final DateChoiceService dateChoiceService;
#GetMapping("/")
public String homeInit(Model model) {
return DATE_CHOICE_VIEW;
}
#PostMapping(value = "/")
public String addUser(#ModelAttribute("incomeoutgo") #Valid DateChoiceDTO dateChoice, Model model, #NotNull BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
return DATE_CHOICE_VIEW;
}
List<?> incomeOutgoList = dateChoiceService.getAllForDateChoice(dateChoice.getDayofweek());
model.addAttribute(DATE_CHOICE_VIEW, incomeOutgoList);
return DATE_CHOICE_VIEW;
}
}
I do not understand why the person column suddenly comes into play?
Maybe someone can tell me what I am doing wrong here?
You are getting following exception because the framework is not sure what to do with the tuple.
No converter found capable of converting from type AbstractJpaQuery$TupleConverter$TupleBackedMap to type DateChoiceDTO
You have to use fully qualified name of the class when you are using construction result set mapping in the query like below:
select new a.b.cSomeDto(t.property1, t.property2) from table t
Here is how i have fixed it:
#Query(value = "SELECT new com.example.samplejdbctemplatecall.DateChoiceDTO" +
"(table.dayofweek, table.person, table.position, table.income, table.outgo) " +
"FROM IncomeOutgo table WHERE table.dayofweek >= :start_dayofmonth AND table.dayofweek <= :end_dayofmonth")
List<DateChoiceDTO> findAllByDateSecond(#Param("start_dayofmonth") Date start_dayofmonth, #Param("end_dayofmonth") Date end_dayofmonth);
But as mentioned by Simon, if you have insert query firing from somewhere else you need to fix that first, because this is a complete retrieval operation and the error you are facing is related to data insertion.
Entire working sample(+ interface projection):
#RequestMapping("/test")
#RestController
class IncomeOutgoController {
private final ChooseMonthRepository chooseMonthRepository;
private int days = 0;
#Autowired
IncomeOutgoController(ChooseMonthRepository chooseMonthRepository) {
this.chooseMonthRepository = chooseMonthRepository;
}
#GetMapping("/interface-projection")
public Object interfaceProjection() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, -1);
Date date = calendar.getTime();
calendar = Calendar.getInstance();
return composeResponse("interface-projection", chooseMonthRepository.findAllByDate(date, calendar.getTime()));
}
#GetMapping("/constructor-projection")
public Object constructorProjection() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, -1);
Date date = calendar.getTime();
calendar = Calendar.getInstance();
return composeResponse("constructor-projection", chooseMonthRepository.findAllByDateSecond(date, calendar.getTime()));
}
#GetMapping("/store")
public Object addRandomData() {
String randomUuid = UUID.randomUUID().toString();
chooseMonthRepository.save(new IncomeOutgo(null, Calendar.getInstance().getTime(), "random-position: " + randomUuid,
randomUuid, new Random(5000).nextDouble(), new Random(500).nextDouble()));
return "success";
}
private Map<String, Object> composeResponse(String key, Object value) {
final Map<String, Object> response = new HashMap<>();
response.put(key, value);
return response;
}
}
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "incomeoutgo", schema = "public")
class IncomeOutgo extends AbstractPersistable<Long> {
#NotNull
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#NotNull
#Column(name = "dayofweek")
private Date dayofweek;
#NotNull
#Size(min = 2, max = 100)
#Column(name = "position")
private String position;
#NotNull
#Size(min = 5, max = 50)
#Column(name = "person")
private String person;
#NotNull
#Size(min = 1)
#Column(name = "income")
private double income;
#NotNull
#Size(min = 2)
#Column(name = "outgo")
private double outgo;
}
#Repository
interface ChooseMonthRepository extends JpaRepository<IncomeOutgo, Date> {
#Query(value = "SELECT dayofweek, person, position, income, outgo FROM IncomeOutgo WHERE dayofweek >= :start_dayofmonth AND dayofweek <= :end_dayofmonth", nativeQuery = true)
List<DateChoiceDTOInterface> findAllByDate(#Param("start_dayofmonth") Date start_dayofmonth, #Param("end_dayofmonth") Date end_dayofmonth);
#Query(value = "SELECT new com.example.samplejdbctemplatecall.DateChoiceDTO" +
"(table.dayofweek, table.person, table.position, table.income, table.outgo) " +
"FROM IncomeOutgo table WHERE table.dayofweek >= :start_dayofmonth AND table.dayofweek <= :end_dayofmonth")
List<DateChoiceDTO> findAllByDateSecond(#Param("start_dayofmonth") Date start_dayofmonth, #Param("end_dayofmonth") Date end_dayofmonth);
}
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
class DateChoiceDTO {
Date dayofweek;
String person;
String position;
Double income;
Double outgo;
}
interface DateChoiceDTOInterface {
Date getDayOfWeek();
String getPerson();
String getPosition();
Double getIncome();
Double getOutgo();
}
application.properties
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:postgresql://172.17.0.2:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=mysecretpassword
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=true

Spring Data Jpa One To One mapping with where clause

I have two tables and I need OneToOne mapping with where clause.
select * from person_details inner join address_details
on address_details.pid=person_details.pid AND person_details.exist_flag = 'Y' AND address_details.address_exist_flag = 'Y'
Table 1
public class PersonDetails {
#Id
private String pid;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "exist_flag")
private String existFlag;
#OneToOne(mappedBy = "personDetails", cascade = CascadeType.ALL)
#Where(clause = "addressExistFlag = 'Y'")
private AddressDetails addressDetails;
}
Table 2
#Data
#NoArgsConstructor
#Entity
#Table(name = "address_details")
public class AddressDetails {
#Id
private String pid;
private String street;
#Column(name = "address_exist_flag")
private String addressExistFlag;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "pid", insertable = false, updatable = false)
private PersonDetails personDetails;
}
I need data to be fetched if both addressExistFlag = 'Y' and existFlag = 'Y'.
With current scenario If I am trying to fetch data via spring batch read repository as below, only existFlag = 'Y' is considered. Is it because of incorrect mapping or the way I have used in spring batch
ReadRepository looks like below
public interface PersonDetailsRepository extends JpaRepository<PersonDetails, String> {
Page<PersonDetails> findByExistFlag(String existFlag, Pageable pageable);
}
Spring batch read repository looks like below
#Bean
RepositoryItemReader<PersonDetails> personDetailsItemReader() {
Map<String, Sort.Direction> sort = new HashMap<>();
sort.put("ExistFlag", Sort.Direction.ASC);
return new RepositoryItemReaderBuilder<PersonDetails>()
.repository(personDetailsRepository)
.methodName("findByExistFlag")
.arguments("Y")
.sorts(sort)
.name("personDetailsItemReader")
.build();
}
You are only querying for existsFlag.
You have to add the other Flag too:
public interface PersonDetailsRepository extends JpaRepository<PersonDetails, String> {
Page<PersonDetails> findByExistFlagAndAddressDetailsAddressExistFlag(
String existFlag, String addressExistFlag, Pageable pageable);
}
#Bean
RepositoryItemReader<PersonDetails> personDetailsItemReader() {
Map<String, Sort.Direction> sort = new HashMap<>();
sort.put("ExistFlag", Sort.Direction.ASC);
return new RepositoryItemReaderBuilder<PersonDetails>()
.repository(personDetailsRepository)
.methodName("findByExistFlagAndAddressDetailsAddressExistFlag")
.arguments("Y", "Y")
.sorts(sort)
.name("personDetailsItemReader")
.build();
}

Return type of JPA Repository 'getOne(id)' Method

I have the following Spring boot service for an object of type Report -
#Service
public class ReportService {
#Autowired
private ReportRepository reportRepository;
#Autowired
private UserRepository userRepository;
/*get all reports */
public List<Report> getAllReports(){
return reportRepository.findAll();
}
/*get a single report */
public Report getReport(Long id){
return reportRepository.getOne(id);
}
//other similar methods....
}
The problem arises while retrieving a single Report. If a report ID is send which doesn't exist, the following error is generated...
DefaultHandlerExceptionResolver : Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException: Could not
write JSON: Unable to find com.interact.restapis.model.Report with id 16;
nested exception is com.fasterxml.jackson.databind.JsonMappingException:
Unable to find com.interact.restapis.model.Report with id 16 (through
reference chain:
com.interact.restapis.model.Report_$$_jvst83c_1["fromUserId"])
Below is the code for my Report Controller
#RestController
public class ReportController {
#Autowired
private ReportService reportService;
//Get all reports
#GetMapping("/interactions")
public List<Report> getAllReports() {
return reportService.getAllReports();
}
//Get single report
#GetMapping("/interactions/{id}")
public ResponseEntity<Report> getReport(#PathVariable Long id) {
if(reportService.getReport(id) == null)
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
return new ResponseEntity<>(reportService.getReport(id), HttpStatus.OK);
}
#PostMapping("/interactions")
public ResponseEntity<Report> addReport(#RequestBody Report report) {
Report report1 = reportService.addReport(report);
if(report1 == null)
return new ResponseEntity<>(report, HttpStatus.NOT_FOUND);
return new ResponseEntity<>(report1, HttpStatus.OK);
}
//Other request methods...
}
Below is the code for my Report Model class -
#Entity
#Table (name = "report")
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Report {
#Id
#Column (name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "from_user_id")
private Long fromUserId;
#Column(name = "to_user_id")
private Long toUserId;
#Column(name = "to_user_email")
private String toUserEmail;
#Column(name = "from_user_email")
private String fromUserEmail;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "dd-MM-yyyy hh:mm:ss")
#CreatedDate
private Date createdAt;
#Column(nullable = false)
private String observation;
#Column(nullable = false)
private String context;
private String recommendation;
#Column(nullable = false)
private String eventName;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "dd-MM-yyyy hh:mm:ss")
#Column(nullable = false)
private Date eventDate;
private boolean isAnonymous;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "dd-MM-yyyy hh:mm:ss")
private Date acknowledgementDate;
#OneToMany(cascade = CascadeType.ALL, targetEntity = Action.class)
#JoinColumn(name = "report_id")
private List<Action> actionList;
#Value("${some.key:0}")
private int rating; //Range 0 to 4
private int type;
/*
Getter and setter methods...
*/
}
I want to know if reportRepository.getOne(Long id) returns null so that I can actually check if a particular report doesn't exist in the database. If not, how else can I implement the above?
The JpaRepository.getOne with throw EntityNotFoundException if it couldn't find a record with the given id.
You can use CrudRepository.findById (JpaRepository is a subclass of CrudRepository) which will return an Optional<Report> which can be empty if there are no record for the given id. You can use Optional.isPresent() to check whether it a Report is available or not and take actions accordingly.
Create a method in your ReportRepository.
It will return Report by matched id else return null.
public Optional<Report> findById(Long id);
Note: findById(Long id); should match with the property name in your Report entity.
I am assuming your Report entity is as follows:
public class Entity{
private Long id;
...
}

Spring Data Rest with Jpa relations

Followed this question but did not work
Have two entities Account and UserTransaction
Account.java
#Entity
#Access(AccessType.FIELD)
public class Account {
#Id
private Integer accountNumber;
private String holderName;
private String mobileNumber;
private Double balanceInformation;
public Account(Integer accountNumber, String holderName, String mobileNumber, Double balanceInformation) {
this.accountNumber = accountNumber;
this.holderName = holderName;
this.mobileNumber = mobileNumber;
this.balanceInformation = balanceInformation;
}
}
UserTransaction.java
#Entity
#Access(AccessType.FIELD)
#Table(name = "user_transaction")
public class Transaction {
#Id
private Long transactionId;
#ManyToOne
#JoinColumn(name = "accountNumber")
private Account accountNumber;
private Double transactionAmount;
#Column(nullable = false, columnDefinition = "TINYINT", length = 1)
private Boolean transactionStatus;
private String statusMessage;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
private Date timestamp;
public Transaction(Long transactionId, Account account,
Double transactionAmount,
Boolean transactionStatus,
String statusMessage) {
this.transactionId = transactionId;
this.accountNumber = account;
this.transactionAmount = transactionAmount;
this.transactionStatus = transactionStatus;
this.statusMessage = statusMessage;
}
}
and My TransactionRepository is as follows
#RepositoryRestResource(collectionResourceRel = "transactions", path = "transactions")
public interface JpaTransactionRepository extends JpaRepository<Transaction, Long>, TransactionRepository {
#Query(value = "select t from Transaction t where t.accountNumber.accountNumber = :accountNumber")
Iterable<Transaction> findByAccountNumber(#Param("accountNumber") Integer accountNumber);
}
I have constructed a json as specified in the stackoverflow post at the top
{
"transactionId" : "3213435454342",
"transactionAmount" : 5.99,
"transactionStatus" : true,
"statusMessage" : null,
"timestamp" : "2017-03-09T05:11:41.000+0000",
"accountNumber" : "http://localhost:8080/accounts/90188977"
}
when I try to execute POST with the above json I get
Caused by: java.sql.SQLIntegrityConstraintViolationException: Column 'account_number' cannot be null
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:533)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:513)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:115)
at com.mysql.cj.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:1983)
How do I save an entity that has relationships with Spring data rest????
The problem is that with #JoinColumn(name = "accountNumber") you would hard-code the column name in database as accountNumber. Normally the naming-strategy would add embedded underscores instead of having mixed case column names.
So it should work if you change the line to #JoinColumn(name = "account_number").

Resources