FindBy combining 'between' and 'or' - java

I'm already using findAllDateBetween(startD, endD) but I would like to know if I can include another date field to search for. Something like (is not working) findAllDate1BetweenOrDate2Between(startD, endD). The startD and endD are the same for Date1 and Date2. Any ideas?
This is the repository:
public interface Cert10TotalRepository extends JpaRepository<Cert10Total, Integer> {
List<Cert10Total> findByDateGermBetween(Date start, Date end);
}
I would like to add OrDatePurityBetween (Date start, Date end)
Thank you

Yes you can like this:
List<Cert10Total> findByDateGermBetweenOrDatePurityBetween(Date germStart, Date germEnd, Date purityStart, Date purityEnd);
General style is that each conjunction(between and or in your case) is appended with the param that is passed.
But in all the fairness, I think you should use a query instead as it's more readable than a such a lengthy method name and misplace param values for callers

Related

convert xmlGregorianCalendar to Date and reverse

i all, i have a spring boot application. what i want in specific is to convert a class (that have nestet object field) in his corrispective entity. example:
public class example{
String string;
ObjectExample object;
}
public class ObjectExample{
String oneString;
XMLGregorianCalendar date;
}
this 2 object are also marked in another package as entities, but ovviusly in the ObjectExampleEntity i have Date date instead XMLGregorianCalendar, like this with the example
#Entity
public class example{
String string;
ObjectExample object;
}
#Entity
public class ObjectExample{
String oneString;
Date date;
}
because i have a big model and big entity (this above is only an example) with a lot of nested classes , i use dozer to convert from the model to the class.
consider for example that the repository jpa is only created for the father example class.
i want to know how i can with dozer convert from Date (entity) to XMLGregorianCalendar (model) and reverse. the model and the entity,i repeat are equal. the only difference is the type of the date. thanks
I am assuming:
Since your variable is named date it contains a calendar date (without time of day).
You are tied to XMLGregorianCalendar because of a WSDL outside your control, but you can change type on the entity side.
Based on these assumptions I recommend LocalDate on the entity side. It’s part of java.time, the modern Java date and time API, and represents exactly a date without time of day. The Date class that you used is poorly designed, long outdated and not recommended. Also despite the name a Date never represented a date, but a point in time.
There are more options. I am presenting three.
Option 1: transfer individual fields
From XMLGregorianCalendar to LocalDate:
DatatypeFactory xmlFactory = DatatypeFactory.newInstance();
XMLGregorianCalendar wsDate = xmlFactory
.newXMLGregorianCalendarDate(2019, DatatypeConstants.MARCH, 30,
DatatypeConstants.FIELD_UNDEFINED);
// Validate
if ((wsDate.getHour() != 0 && wsDate.getHour() != DatatypeConstants.FIELD_UNDEFINED)
|| (wsDate.getMinute() != 0 && wsDate.getMinute() != DatatypeConstants.FIELD_UNDEFINED)
|| (wsDate.getSecond() != 0 && wsDate.getSecond() != DatatypeConstants.FIELD_UNDEFINED)
|| (wsDate.getMillisecond() != 0 && wsDate.getMillisecond() != DatatypeConstants.FIELD_UNDEFINED)) {
System.out.println("Warning: time of day will be lost in conversion");
}
if (wsDate.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) {
System.out.println("Warning: UTC offset will be lost in conversion");
}
// Convert
LocalDate entityDate = LocalDate.of(wsDate.getYear(), wsDate.getMonth(), wsDate.getDay());
System.out.println(entityDate);
The output is in this case:
2019-03-30
From LocalDate to XMLGregorianCalendar:
LocalDate entityDate = LocalDate.of(2019, Month.MARCH, 31);
XMLGregorianCalendar wsDate = xmlFactory.newXMLGregorianCalendarDate(
entityDate.getYear(),
entityDate.getMonthValue(),
entityDate.getDayOfMonth(),
DatatypeConstants.FIELD_UNDEFINED);
System.out.println(wsDate);
2019-03-31
Advantage of this way: It’s pretty straightforward. Disadvantage: You and your reader need to take care that the fields are mentioned in the right order.
Option 2: convert via strings
// Validate as before
// Convert
LocalDate entityDate = LocalDate.parse(wsDate.toXMLFormat());
Result is as before.
XMLGregorianCalendar wsDate
= xmlFactory.newXMLGregorianCalendar(entityDate.toString());
Advantage: it’s brief, and there’s no surprise that the results are correct. Disadvantage: To me it feels like a waste to format into a string only to parse it back.
Option 3: convert via GregorianCalendar and ZonedDateTime
ZonedDateTime zdt = wsDate.toGregorianCalendar().toZonedDateTime();
// Validate
if (! zdt.toLocalTime().equals(LocalTime.MIN)) {
System.out.println("Warning: time of day will be lost in conversion");
}
if (! zdt.getZone().equals(ZoneId.systemDefault())) {
System.out.println("Warning: UTC offset will be lost in conversion");
}
// Finish conversion
LocalDate entityDate = zdt.toLocalDate();
And the other way:
// It doesn’t matter which time zone we pick
// since we are discarding it after conversion anyway
ZonedDateTime zdt = entityDate.atStartOfDay(ZoneOffset.UTC);
GregorianCalendar gCal = GregorianCalendar.from(zdt);
XMLGregorianCalendar wsDate = xmlFactory.newXMLGregorianCalendar(gCal);
wsDate.setTime(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED,
DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
wsDate.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
The validation I present here is a bit simpler but also not quite so strict. If you want strict validation, you can just use the validation from before.
Advantages: I think it’s the official way; at least it uses the conversion methods offered. What I like is that the conversion itself is direct and brief. Disadvantage: When converting to XMLGregorianCalendar we need to set the unused fields to undefined manually, which makes it wordy.
Conclusion
I have presented three options each with their pros and cons. You may also mix, of course, but using a similar conversion both ways is probably less confusing in the end.

Get all columns within last month with a JPA query?

My current Query counts all tickets sold for each event and lists each event with the most tickets desc. Now the problem is, that I need to also get all tickets within the last month and I simply can not get the needed result from the JPArepo Doc. only.
The current query looks like this:
#Query("select t.event.id, count(t.id) from Ticket t where t.event.seat = True group by t.event.id order by count(id) desc")
I am thinking a where after the "True" and before the grouping needs to be implemented but I just dont know how.
I would be really greatful if someone of you could manage to help me out!
Edit: Forgot to mention that the current event date is simply called "date", so to access it what needs to be done is simply t.event.date.
Change your query to something like this:
#Query("select t.event.id, count(t.id) from Ticket t where t.event.seat = ?1 and t.event.date >= ?2 group by t.event.id order by count(t.id) desc")
List<?> getEventCount(Boolean seatTaken, Date eventDate);
I modified the query to have the seat be a boolean parameter (for reusability if you want to find seats that were not taken) and added in the Date parameter.
Then calculate the date a month back as such:
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, -1);
Date date = cal.getTime();
And finally implement the new method:
List<?> results = repo.getEventCount(true, date);
To create a Service class in spring and put it all together try something like:
#Service
public class TicketService {
#Autowired
private TicketRepository repo;
public List<?> getTicketEventCount() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, -1);
Date date = cal.getTime();
List<?> results = repo.getEventCount(true, date);
return results;
}
}

Store a local year for Date

I am going to store only year value in Database and retrieve it.
This is my domain (POJO)
#Entity
public class Publisher {
public Publisher(..., Date establishDate) {
//assign other variables
this.setEstablishDate(establishDate);
}
#NotNull
private Date establishDate;
...
}
And here is my DTO:
#NotNull
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy")
private Long establish_date;
Here, i am creating a new publisher:
new Publisher(..., new Date(this.establish_date));
I sent a json with value 1370 for establish_date (for post a new publisher) , but in Database it displays as: 1970-01-01 03:30:01
Why?
And when i Get the Publisher, it displays establish_date as 1000 !
What is wrong ?
You are using the wrong constructor. The argument specifies the milliseconds since 1970 - not a year: Date(long) You may use the right constructor: Date(int, int, int)
Note that most of the Date API is deprecated. There are better alternatives like Calendar and DateTime. Since you are only storing the year you could also use plain integer. This will make a lot easier.

using the date type in java

I am trying to get two dates from a SQL query, and compare them. So to compare them, I believe I will need to use the "Date" type. Here is what I am trying, I know I am getting the date from the resultSet incorrectly, but I am not sure how to do it.
Date validDate = new Date(0);
Date currentDate = new Date(0);
// query
if (result.next()) {
validDate = (result.getObject("validDate")!=null)?result.getObject("validDate").toDate():"";
currentDate = (result.getObject("currentDate")!=null)?result.getObject("currentDate").toDate():"";
}
if (currentDate > validDate) {
//do something
}
So again, this was my attempt, but I cant seem to get it to run. Thanks in advance.
EDIT: the query has TO_CHAR(column, 'MM-DD-YYYY') on the two dates that I am getting.
EDIT: Now you've mentioned that your query converts the date to a string, stop doing that. You'll end up reparsing it on the calling side - so why perform two conversions pointlessly? Keep string conversions to the absolute minimum - stay in the most appropriate data type wherever possible.
Original answer
You haven't shown what result is, but you probably want something like ResultSet.getDate() to fetch the date values.
Note that your comparison code won't work either because there's no > for Date - you'd need something like:
if (currentDate.after(validDate))
Or fetch the underlying number of millis:
if (currentDate.getTime() > validDate.getTime())
Additionally:
You can't assign "" to a Date variable - a string isn't a Date.
You can just call ResultSet.getDate() and check whether the returned value is null, rather than calling getObject first and then getDate()
Try currentDate.after(validDate)
To compdare dates I always use the before and after methodes of Date.
Some nasty things can happen when accessing dates via the getObject method. You should try to use the rs.getTimestamp (with timeinfo) or the rs.getDate (without timeinfo) methods.
Also, because of the rather complex hierarchy of Date-objects you should compare Dates only using the date1.compareTo(date2) > 0 method.
if your result object is ResultSet, then
Date validDate = result.getTimestamp("validDate");
Date currentDate= result.getTimestamp("currentDate");
// you can add null checks here too....
// you can also use if (currentDate.getTime() > validDate.getTime()){}
if (currentDate.before(validDate)) {
//some code inhere...
}
There are at least three things wrong with your code:
"" is a String literal, so you cannot use it int your ternary expressions to be assigned to a variable of type Date - use null instead so you don't need a ternary
ResultSet.getObject() returns an Object, which does not have a toDate() method. Instead, simply use ResultSet.getDate()
You cannot compare Date instances using a > operator. You have to use the before() and after() methods of the Date class
Taking all this together, the following code might work:
Date validDate = new Date(0);
Date currentDate = new Date(0);
if (result.next()) {
validDate = result.getDate("validDate");
currentDate = result.getDate("currentDate");
}
if (currentDate.after(validDate)) {
//do something
}
The if clause may have to include some extra logic to deal with null values though. It's better to do that than to leave that to implicit conversions, too.

How to initialize Mock with variable data

I have this method to test :
public static Date getDateSinceUTC(CstOrderBean orderBean) {
int year = orderBean.getDeadLineYear();
int month = orderBean.getDeadLineMonth();
int day = orderBean.getDeadLineDay();
int hour = orderBean.getDeadLineHour();
int minute = orderBean.getDeadLineMinute();
String ap = orderBean.getDeadLineAmPm() == 1 ? "PM" : "AM";
//TODO AM=0, PM=1 comes from html form
SimpleDateFormat df = new SimpleDateFormat("yyyy:MM:dd:hh:mm:aa");
String stringDate = stringifyIntegers(":", year, month, day, hour, minute);
stringDate = stringDate.concat(ap);
Date date;
try {
date = df.parse(stringDate);
} catch (ParseException e) {
throw new Error("Parsing date from html form failed", e);
}
return date;
}
Where CstOrderBean needs to be mocked by Mockito because it is not a POJO (some static initializations etc. - from source code generator). But I need to run the method xxx times, hence set the mocks with many data combinations
I could use TestNG's #DataProvider to do that. But I'm not sure how to do that, I guess that :
when(ob.getDeadLineYear()).thenReturn(1, 2, 3);
....
in loop is a bad idea, isn't it ? Is the correct way of doing this to create xx mocks and initialize them like that ?
Each test should get their own mock that preferably does not have variable data. If you use several different return values from the same mock object then the testing has to be white-box testing as the test is coupled with the number of calls to a mocked method instead of the result of the method under test.
That said, you are able to define a set of return values with calling thenReturn repeatedly or by defining the return values as varargs
when(ob.getDeadLineYear()).thenReturn(someValue, anotherValue, ..., ultimateValue);
This might be cleaner as you should probably control the values that the mock returns anyway.
How you mock depends on what you would like to test. Looping on the deadline year might not do the job you want it to.
One test for seeing if a leap year works might be something like:
when(ob.getDeadLineYear()).thenReturn(2000);
when(ob.getDeadLineMonth()).thenReturn(2);
when(ob.getDeadLineDay()).thenReturn(29);
when(ob.getDeadLineHour()).thenReturn(12);
when(ob.getDeadLineMinute()).thenReturn(0);
when(ob.getDeadDeadLineAmPm()).thenReturn(1);
assertTrue("Got unexpected date", getDateSinceUTC(ob).toString().startsWith("2000-02-29 12:00:00"));
(Warning: above codes was typed in by hand). Mix, match, and repeat for other dates that you need to test to verify that getDateSinceUTC is working. You might want a separate test method to check invalid dates, like 2/30/2012 (and expect a throw). You might want to check invalid times like 23:61. You might want to check valid dates, like your birthdate.
Instead of a loop on the year, please look at "normal" cases, borderline cases, and error cases. This is the better practice for unit testing.

Categories