0

In my Java/Spring application I am trying to iterate through all items found in the SQL Database Table called License, and send an email if the licence expiration date is 30 days away from today, but I am having issues iterating through.

The issue is accessing the expiration column. What should I be doing to access the expiration date of each license in the database, because clearly the way I am doing it is not accurate. I might be getting confused because you need to get all the items from the table through the repository but then for each item you use the model to get access the Expiration date.

Is there a better way to iterate through the list of items in a repository and access specific columns? Or can someone easily help me fix the code I have so far?

List<License> licenses=licenseRepository.findAll();
for(Object lic:licenses){

    if (lic.expiration.minusDays(30) == LocalDate.now()) {
        try {
            emailService.sendSimpleMessage(mail, licenseModel);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Stacie
  • 306
  • 7
  • 26
  • You can create custom SQL query which will find all licenses with expiration equals 30 days away. If you're using Spring Boot Data you can use @Query annotation in your repository interface. – jker Jan 12 '19 at 00:05
  • Take a look at this post if you are using Spring Data https://stackoverflow.com/questions/39784344/check-date-between-two-other-dates-spring-data-jpa – akuma8 Jan 12 '19 at 00:10
  • Actually with spring data you can create metod in repository with specific name which Will find match rows – jker Jan 12 '19 at 00:13

1 Answers1

0

Repository

better way to iterate through the list of items in a repository and access specific columns

Nope. We cannot help you on that point as you have not shown or explained your repository code.

I can show you proper JDBC 4.2 code to retrieve a date-only value from a database column of a type akin to the SQL-standard DATE type.

LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;

Or can someone easily help me fix the code I have so far?

Yes, I can help.

  • You are using incorrect syntax.
  • You are ignoring crucial issue of time zone.

Use isEqual method, not ==

The == operator on Java tests either:

  • If two references both point to the same object, to the same location in memory.
    (Generally speaking, this is very rarely needed in most apps. So generally do not use == with objects.)
  • If two primitives (int, boolean, etc.) have equivalent values.

So the effect is dramatically different between those two. One compares the values of the data you care about (in primitives). The other compares the memory location (a number basically) of a pair of references (pointers) without regard to the data you care about (in objects).

When comparing the value of two objects, call a method. For LocalDate that would be isEqual. You can also compare temporally with isBefore & isAfter.

So your code:

if ( lic.expiration.minusDays( 30 ) == LocalDate.now() ) { … }

…should be…

if ( lic.expiration.minusDays( 30 ).isEqual( LocalDate.now() ) ) { … }

I would break that down in my own code.

LocalDate today = LocalDate.now() ;
LocalDate thirtyDaysBeforeExpiration = lic.expiration.minusDays( 30 ) ;
if ( thirtyDaysBeforeExpiration.isEqual( today ) ) { … }

Time zone

A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.

If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.

Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

So my version of your code would actually be:

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( z ) ;
LocalDate thirtyDaysBeforeExpiration = lic.expiration.minusDays( 30 ) ;
if ( then.isEqual( today ) ) { … }

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154