DB field empty problems in Spring Boot - spring-boot

I have a method in Spring Boot that collects various database dates from the logged in employee.
private boolean isActiveThisMonth(EmployeeView emp,LocalDate date){
return (emp.getHiringDate().withDayOfMonth(1).minusDays(1).isBefore(date.withDayOfMonth(1)) && (emp.getLeavingDate()==null ||
emp.getLeavingDate().plusMonths(1).withDayOfMonth(1).isAfter(date.with(lastDayOfMonth()))));
}
Currently if the hiringDate field is empty in the database, it returns an error. How can I add an exception so that if the field arrives without an error? Or if it is better to put a date, for example the current day and thus not an error?

A couple of ways to prevent this.
1.
You could handle the null value inside isActiveThisMonth like this
private boolean isActiveThisMonth(EmployeeView emp,LocalDate date){
LocalDate hiringDate = emp.getHiringDate() != null ? emp.getHiringDate() : LocalDate.now();
return (hiringDate.withDayOfMonth(1).minusDays(1).isBefore(date.withDayOfMonth(1)) && (emp.getLeavingDate()==null ||
emp.getLeavingDate().plusMonths(1).withDayOfMonth(1).isAfter(date.with(lastDayOfMonth()))));
}
You could make sure the value is set in the Entity when the Employee is created.
#Column(name = "hire_date", columnDefinition = "DATE DEFAULT CURRENT_DATE")
private jDate startDate;

Related

Java Date field not shown properly in postman

Any help or hint would be greatly appreciated it!!
I am using Spring Boot 2.56
The date and time show properly for field "transactionDate" field when debugging the code in intellij.
2023-01-15 23:35:05.0
enter image description here
Code:
public List < TransactionEntity > findByFromAccountIdOrToAccountId(Long accountId) {
AccountEntity account = accountRepository.findByAccountId(accountId);
if (account == null) {
throw new AccountException("account cannot be found in account table accountId:" + accountId);
}
List < TransactionEntity > list = transactionRepository.findByFromAccountOrToAccount(account, account);
return list;
}
TransactionEntity.java
private Timestamp transactionDate;
For the transactionDate field I used import java.sql.Timestamp;
In postman it is showing: "transactionDate": 1673843714000,
How can I show the proper date and time in postman result such as "2023-01-15 23:35:05.0".
"transactionDate": 1673843714000
This is how Timestamp looks like. If you want to show like you mention use LocalDateTime instead.
private LocalDateTime transactionDate;
Or convert
transactionDate.toLocalDateTime().toLocalDate()

InvalidPathException while sorting with org.springframework.data.domain.Pageable

I am trying to sort my table's content on the backend side, so I am sending org.springframework.data.domain.Pageable object to controller. It arrives correctly, but at the repository I am getting org.hibernate.hql.internal.ast.InvalidPathException. Somehow the field name I would use for sorting gets an org. package name infront of the filed name.
The Pageable object logged in the controller:
Page request [number: 0, size 10, sort: referenzNumber: DESC]
Exception in repository:
Invalid path: 'org.referenzNumber'","logger_name":"org.hibernate.hql.internal.ast.ErrorTracker","thread_name":"http-nio-8080-exec-2","level":"ERROR","level_value":40000,"stack_trace":"org.hibernate.hql.internal.ast.InvalidPathException: Invalid path: 'org.referenzNumber'\n\tat org.hibernate.hql.internal.ast.util.LiteralProcessor.lookupConstant(LiteralProcessor.java:111)
My controller endpoint:
#GetMapping(value = "/get-orders", params = { "page", "size" }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<PagedModel<KryptoOrder>> getOrders(
#ApiParam(name = "searchrequest", required = true) #Validated final OrderSearchRequest orderSearchRequest,
#PageableDefault(size = 500) final Pageable pageable, final BindingResult bindingResult,
final PagedResourcesAssembler<OrderVo> pagedResourcesAssembler) {
if (bindingResult.hasErrors()) {
return ResponseEntity.badRequest().build();
}
PagedModel<Order> orderPage = PagedModel.empty();
try {
var orderVoPage = orderPort.processOrderSearch(resourceMapper.toOrderSearchRequestVo(orderSearchRequest), pageable);
orderPage = pagedResourcesAssembler.toModel(orderVoPage, orderAssembler);
} catch (MissingRequiredField m) {
log.warn(RESPONSE_MISSING_REQUIRED_FIELD, m);
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok(orderPage);
}
the repository:
#Repository
public interface OrderRepository extends JpaRepository<Order, UUID> {
static final String SEARCH_ORDER = "SELECT o" //
+ " FROM Order o " //
+ " WHERE (cast(:partnerernumber as org.hibernate.type.IntegerType) is null or o.tradeBasis.account.retailpartner.partnerbank.partnerernumber = :partnerernumber)"
+ " and (cast(:accountnumber as org.hibernate.type.BigDecimalType) is null or o.tradeBasis.account.accountnumber = :accountnumber)"
+ " and (cast(:orderReference as org.hibernate.type.LongType) is null or o.tradeBasis.referenceNumber = :orderReference)"
+ " and (cast(:orderReferenceExtern as org.hibernate.type.StringType) is null or o.tradeBasis.kundenreferenceExternesFrontend = :orderReferenceExtern)"
+ " and (cast(:dateFrom as org.hibernate.type.DateType) is null or o.tradeBasis.timestamp > :dateFrom) "
+ " and (cast(:dateTo as org.hibernate.type.DateType) is null or o.tradeBasis.timestamp < :dateTo) ";
#Query(SEARCH_ORDER)
Page<Order> searchOrder(#Param("partnerernumber") Integer partnerernumber,
#Param("accountnumber") BigDecimal accountnumber, #Param("orderReference") Long orderReference,
#Param("orderReferenceExtern") String orderReferenceExtern, #Param("dateFrom") LocalDateTime dateFrom,
#Param("dateTo") LocalDateTime dateTo, Pageable pageable);
}
Update:
I removed the parameters from the sql query, and put them back one by one to see where it goes sideways. It seems as soon as the dates are involved the wierd "org." appears too.
Update 2:
If I change cast(:dateTo as org.hibernate.type.DateType) to cast(:dateFrom as date) then it appends the filed name with date. instead of org..
Thanks in advance for the help
My guess is, Spring Data is confused by the query you are using and can't properly append the order by clause to it. I would recommend you to use a Specification instead for your various filters. That will not only improve the performance of your queries because the database can better optimize queries, but will also make use of the JPA Criteria API behind the scenes, which requires no work from Spring Data to apply an order by specification.
Since your entity Order is named as the order by clause of HQL/SQL, my guess is that Spring Data tries to do something stupid with the string to determine the alias of the root entity.

Dealing with nullable UUID in a controller - SpringBoot and Postgres

I have an entity that includes a nullable UUID (but it is not an ID), as follows:
#Column(nullable = true)
var myField: UUID? = null
I also have a dto converter as follows:
myField = entity.myField.let { it }
I can correctly store a null value for the UUID field, but when inspecting the GET response from my controller whenever I pass a null value for such field the body does not contain the myField at all. What is the reason for that? How does SpringBoot deal with null value for UUID.
Thanks

Spring Mongodb query for Employee first and last name and dob using range criteria

I have some data on employees which stores typical information like first and last name and dob, etc... The business case I have been given requires me to pull a record for an employee based on a criteria of first name, last name and dob.
At first I thought this would be easy, but after doing a search in db, I found the dob records have differing timestamps (which doesn't make sense). Without getting into the internal company issues of addressing this, I need my query to look at a dob with a start of day and end of day range.
My sample code below demonstrates my latest effort to solve this issue but have not been able to match results with what i see in the db. This code is using Spring Mongodb Query and mongoDbTemplate for constructing the queries. I could really use some help in figuring this one out.
I have to set a date range to ensure I get the employee for that day but can't figure out how to construct the query correctly.
sample method:
#Slf4j
#Repository
public class EmployeeDao {
private static final int START_OF_DAY = 0;
private static final int END_OF_DAY = 1;
#Getter private MongoTemplate mongoTemplate;
#Autowired
public void setMongoTemplate(MongoTemplate mongoTemplate) {
DB db = mongoTemplate.getDb();
mongoTemplate = new MongoTemplate(db.getMongo(), "EmployeeDB");
this.mongoTemplate = mongoTemplate;
}
public List<Employee> findEmployeeByNameIdDobRange(String lName, String fName, Date dob){
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String startFmt = df.format(convertTo(dob, START_OF_DAY));
String endFmt = df.format(convertTo(dob, END_OF_DAY));
Query q = new Query();
q.addCriteria(Criteria.where("employee.firstName").regex(fName, "i")
.and("employee.lastName").regex(lName, "i")
.andOperator(
Criteria.where("employee.dob").gte(startFmt).lte(endFmt)
)
);
return return getMongoTemplate().find(q, Employee.class);
}
private Date convertTo(Date dt, int startOrEnd){
Calendar cal = Calendar.getInstance();
cal.setTime(dt);
switch (startOrEnd) {
case END_OF_DAY:
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 999);
break;
case START_OF_DAY:
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 1);
cal.set(Calendar.SECOND, 1);
cal.set(Calendar.MILLISECOND, 1);
break;
default:
throw new IllegalArgumentException("starOrEnd paramter does not equal 0 for beggining or 1 for end of day");
}
log.info(cal.toString());
return cal.getTime();
}
I appreciate any suggestions that can be made. Thanks!

JPA/Hibernate generating wrong SQL in Spring Roo finder method

I'm developing a Spring web application whose persistence layer consists in Spring Roo generated JPA entities, with Hibernate as persistence provider and MySql as underlying DB.
Among my entities I have a class Detection with a tstamp java.util.Date field generated in Roo as follows:
entity jpa --class ~.data.Detection
...
field date --fieldName tstamp --type java.util.Date
...
finder add findDetectionsByTstampBetween
(the finder method was of course chosen after executing finder list)
In my controller code, at a point I invoke:
List<Detection> detections = Detection.findDetectionsByTstampBetween(from, to).getResultList();
Where from and to are two valid java.util.Date(s). When testing sample data though (after ensuring that for a given choice of from, to the returned list shouldn't be empty), I got an empty list and investigated the reasons.
I found in tomcat logs that Hibernate was generating the following SQL:
Hibernate: select detection0_.id as id1_3_, ...etc..., detection0_.tstamp as tstamp4_3_ from detection detection0_ where detection0_.tstamp>=?
I would expect the where clause should contain a trailing "AND detection0_.tstamp<=?", checking the other date range limit. I took a look at the generated Detection.findDetectionsByTstampBetween(Date minTstamp, Date maxTstamp) method in Detection_Roo_Finder.aj and actually the "AND" is present in the invocation to createQuery.
public static TypedQuery<Detection> Detection.findDetectionsByTstampBetween(Date minTstamp, Date maxTstamp) {
if (minTstamp == null) throw new IllegalArgumentException("The minTstamp argument is required");
if (maxTstamp == null) throw new IllegalArgumentException("The maxTstamp argument is required");
EntityManager em = Detection.entityManager();
TypedQuery<Detection> q = em.createQuery("SELECT o FROM Detection AS o WHERE o.tstamp BETWEEN :minTstamp AND :maxTstamp", Detection.class);
q.setParameter("minTstamp", minTstamp);
q.setParameter("maxTstamp", maxTstamp);
return q;
}
Any idea what could cause the problem?
I've finally found the solution to the riddle and, as it turned out, the issue had nothing to do with JPA.
The problem was that the call to the persistence layer was inserted inside a Rest service controller with the following mapping:
#ResponseBody
#RequestMapping(value="/detections", method=RequestMethod.GET, params="from, to" )
public Object getDetectionsInRange(
#RequestParam(required=true) #DateTimeFormat(pattern="yyyy-MM-dd HH:mm") final Date from,
#RequestParam(required=true) #DateTimeFormat(pattern="yyyy-MM-dd HH:mm") final Date to
)
{
...
List<Detection> detections = Detection.findDetectionsByTstampBetween(from, to).getResultList();
...
}
The error was in the definition of the params= argument in #RequestMapping, the correct format being as follows:
#RequestMapping(value="/detections", method=RequestMethod.GET, params={"from", "to"} )
This error caused another version of the controller method for /detections. In this second version I called a different finder method, which appeared to generate the wrong SQL in Hibernate.
#ResponseBody
#RequestMapping(value="/detections", method=RequestMethod.GET )
public Object getDetections(
#RequestParam(required=false, defaultValue="0") int days,
#RequestParam(required=false, defaultValue="0") int hours,
#RequestParam(required=false, defaultValue="0") int minutes
)
{
...
List<Detection> detections = Detection.findDetectionsByTstampGreaterThanEquals( ... ).getResultList();
...
}

Resources