How to guarantee update field whe other field is updated? - java

I have class
public class Order {
private LocalDateTime creationDate;
private Date creationDateAsDate;
}
The creationDate is an existing field in the Order.
The creationDateAsDate is a new field for some functionality.
I need to set and save this new field in all places where I save the old field.
Unfortunately, I am working with legacy code, and I have 5 places where creationDate field is set.
Now I see 2 solutions:
call creationDateAsDate setter in all places where creationDate setter is called.
call creationDateAsDate setter in the creationDate setter.
I don't like both variants. Can someone answer how to do this? It might be one of my variants, or something else.

I would recommend updating both setters which is no wrong (that's the reason they exist) calling a common private method to avoid infinite recursion.
public void setCreationDate(LocalDateTime creationDate) {
Date creationDateAsDate = Date.from(creationDate.atZone(ZoneId.systemDefault())
.toInstant());
updateDates(creationDate, creationDateAsDate);
}
public void setCreationDateAsDate(Date creationDateAsDate) {
LocalDateTime creationDate = LocalDateTime.ofInstant(
creationDateAsDate.toInstant(),
ZoneId.systemDefault());
updateDates(creationDate, creationDateAsDate);
}
private void updateDates(LocalDateTime creationDate, Date creationDateAsDate) {
this.creationDate = creationDate;
this.creationDateAsDate = creationDateAsDate;
}

Since these are private variables remove one of the variables for example private Date creationDateAsDate and the setter for the vaiable.
Implement getter method as follows.
public Date getCreationDateAsDate(){
// convert the creationDate to date and return.
}
REF: Converting between java.time.LocalDateTime and java.util.Date for converting LocalDateTime to Date

You could add a third method (e.g. setCreationDateAsDateAndcreationDate) and call it whenever you want both to be updated. (as classes should be open for extension, but closed for modification).
Then put both setters in it,
or
you could call the new setter method from setCreationDateAsDate and setCreationDate (where you create the other property within setters, and then call the third setter setCreationDateAsDateAndcreationDate while passing both of dates as arguments to it)

Related

spring boot repository: check if Date exists

In my reservation-entity i have a column "bookingDate" --> example: "2021-05-10 12:00:00".
So in this object the date and starttime of an user-booking gets displayed.
If a user wants to book a timeslot, i want to check first if the selected timeslot is empty. So i want to query the database by date&startTime.
I tried it with https://www.baeldung.com/spring-data-jpa-query-by-date , but it didnt work. I got the errors: "The annotation #Temporal is disallowed for this location" & "#Temporal cant be used for variables"
these are the relevant classes:
Reservation.java
#Entity
public class Reservation {
#Id #GeneratedValue
private int reservationId;
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime bookingDate;
private int court = 1;
private String playerNames;
private int userIdReservation;
//getter and setters
With the method "findByBookingDate()" i want to query the database, if the selected timeslot is empty...
VerificationClass.java
public boolean validateReservation(Reservation r) {
LocalDateTime tempDate = r.getBookingDate();
if(reservationRepository.findByBookingDate(tempDate)){ // todo: + and Court
logger.getLogger().info(this.getClass().getName() + "||Booking Slot is empty -- Reservation created||");
return true;
}
logger.getLogger().info(this.getClass().getName() + "||Booking Slot is full -- Reservation failed||");
return false;
}
ReservationRepository.java
#Repository
#Repository
public interface ReservationRepository extends JpaRepository<Reservation, Integer>{
#Query("Select r from reservation r where r.booking_date = :tempDate")
boolean findByBookingDate(#Param("tempDate") LocalDateTime tempDate);
}
If I run it like this i always get an "org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'backyardcodersSpringReactApplication'" --> so the application does not successfully start up.
Im very thankful for every tip and critique!
cheers!
Not understood completely. this is just a lead maybe not a perfect solution.
You can use java.time.LocalDateTime . and annotation be like #DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME).
And the query should be like. [the query will check all the reservation for that day]
Select
from reservation_table
Where
timeSlot between ‘2021-05-10 00:00:00’ and ‘2021-05-10 23:59:59’
I copied your code in my local file. Instead of
import org.springframework.data.jpa.repository.Temporal;
I used
import javax.persistence.Temporal;
in your Reservation.java file.
Also this is my very first answer on Stackoverflow.
First of all #Temporal have three different arguments and it can be applied to the variable of type date , time and time stamp.
Usage
#Temporal(Temporal type.DATE)
private Date date;
#Temporal(Temporal type.TIMESTAMP) // INSERT BOTH DATE WITH TIME TILL MILLISECONDS
private Calendar date;
Why not just just extract the localdate from your LocalDateTime and pass it on? and extract the hour and pass it on and query 2 different columns with it.
LocalDateTime.toLocalDate()
LocalDateTime.getHour()

PMD reference to a mutable object of an interface

Similar to this question. I have an interface DateRangeModel:
I use this to automatically validate dates in implementers:
public interface DateRangeModel {
#ApiModelProperty(value = "From date. Must be less than to date.")
#Column()
Date getFromDate();
void setFromDate(Date date);
#ApiModelProperty(value = "To date. Must be greater than to date.")
#Column()
Date getToDate();
void setToDate(Date date);
/**
* Checks that if both dates are populated, a valid date range is used.
*
* #return true if the date is a valid range.
*/
#AssertTrue(message = "To date must be greater than or equal to from date.")
#JsonIgnore
default boolean areDatesValid() {
if (getToDate() != null && getFromDate() != null) {
return !getFromDate().after(getToDate());
}
return true;
}
}
I implement it like this:
#EqualsAndHashCode
#Data
#Builder
public class BirthdayParty implements DateRangeModel {
Date fromDate;
Date toDate;
String name;
}
Which compiles and seems to work, but I get that error when running PMD:
Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object.
How can I either accomplish what I want (an interface with to/from date validation) without having to implement the setDate methods in all implementers (which I think would defeat the purpose)?
The problem is that java.util.Date is mutable and you return it in your getters. So someone could do this:
BirthdayParty party = ...;
Date fromDate = party.getFromDate();
...
Date someDate = fromDate;
...
// you might not be aware that this also changes the fromDate in party
someDate.setTime(12345678);
There are four things you can do:
Disable the PMD rule.
Suppress the warning everywhere you use one of these a classes.
Don't use Lombok and copy the dates in your setters and getters instead of just storing/returning the reference to a date.
Use java.time.ZonedDateTime (or LocalDateTime) instead of Date. ZonedDateTime is immutable and should not lead to this warning.
I suggest the fourth option. Not only because it gets rid of the PMD warning but also because the new time API in Java 8 is so much better and easier to use than java.util.Date.

Convert Java POJO to Map without JSON serialization

I'd like to convert a Java POJO into a Map without using JSON serialization for the properties (e.g. that Date's are converted to a long or a ISO8601 String). I just want the fields to be retained as they are.
For example if I have a POJO defined like this:
public class MyPojo {
private Date date;
private String x;
public MyPojo(Date date, String x) {
this.date = date;
this.x = x;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
}
I know I can use Jackson as described in this Stackoverflow question but the result is not what I want. For example if I do:
Map<String, Object> x = new ObjectMapper().convertValue(new MyPojo(new Date(), "x"), new TypeReference<Map<String, Object>>() {});
System.out.println(x);
I get this result:
{date=1528521584984, x=x}
whereas I would simply like a Map retaining the java.util.Date instance without being serialized.
Note that I obviously would like this work for nested Pojo's such as:
public class MyPojo {
private MyOtherPojo otherPojo;
...
}
How can I achieve this?
First off, going from a POJO to a Map seems like a bad idea. But I guess that you have reasons for wanting to do it ...
The simple approach is to just create a HashMap and populate it using a sequence of put calls. That gives you a map that contains the same information as the original POJO, but is not "connected" to is.
If you want the Map to be a view of the original POJO, there are 3rd-party libraries that can be used to do this. For example, org.apache.commons.beanutils has classes for wrapping an POJO that follows the JavaBeans conventions as a DynaBean. You can then adapt that as a Map using DynaBeanMapDecorator.
Mapping nested POJOs to nested maps would require more work. (And it contradicts your requirement that you can get the value of getData() as a Date POJO rather than as a Map!)
Jackson will serialize the Date to a timestamp format by default (number of milliseconds since January 1st, 1970, UTC). #JsonFormat annotation can be used to control the date format on individual classes.
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
private Date date;

Mapping from java.time.MonthDay to java.sql.*

We have a case, where we require only the day and the month and thus would use the java.time.MonthDay (Javadocs) to represent that information.
We are aware that we could create our own JPA object for persistence or just use the java.sql.Date object, but that generally requires an unrequired year information.
Another way is to call the method .atYear(int) (Javadoc) (with a fictitious year) on it and receive a java.time.LocalDate (Javadoc), which can be easily converted to java.sql.Date. But this is prone to missunderstandings in the future (and also persist the year information).
Is there some "elegant"/supposed solution for this case? Or is there a replacement for SQL that supports the whole new date and time API for Persistence.
Another case would be java.time.YearMonth (Javadoc).
Thanks for reading!
Since SQL databases don't have a type compatible with MonthDay, use a VARCHAR columns, and simply use toString() and MonthDay.parse().
Or use a custom DateTimeFormatter, if you don't like the --12-03 format.
The default format will correctly sort, as a string.
here are the code snippets:
// column define:
#Column(name = "date", columnDefinition = "mediumint", nullable = false)
#Convert(converter = MonthDayIntegerAttributeConverter.class)
protected MonthDay date;
// converter define:
public class MonthDayIntegerAttributeConverter implements AttributeConverter<MonthDay, Integer> {
#Override
public Integer convertToDatabaseColumn(MonthDay attribute) {
return (attribute.getMonthValue() * 100) + attribute.getDayOfMonth();
}
#Override
public MonthDay convertToEntityAttribute(Integer dbData) {
int month = dbData / 100;
int day = dbData % 100;
return MonthDay.of(month, day);
}
}

How to persist Joda Date to sql database?

How can I persist a jodatime YearMonth object to a sql database?
#Entity
public class MyEntity {
private YearMonth date; //how to persist?
//some more properties
}
I want later to be able to pick all entities by a specific month.
The better question is how do you intend to use the data in the database? Generally you want to store dates in databases using data types supported by the target database as opposed to strings or composite integers. That would allow you to use the built in database date/time functions and validations as opposed to needing to implement that logic in your application.
You can certainly add methods to your entity to convert to/from jodatime values to your entity for the parts of your application that need it.
You need a javax.persistence.Converter for this (see How to convert java.util.Date to Java8 java.time.YearMonth):
#Entity
public class MyEntity {
#Convert(converter = YearMonthConverter.class)
private YearMonth date; //how to persist?
//some more properties
}
The following is an example converter for Java8 java.time.YearMonth to java.utilDate. You need to change java.time.YearMonth to org.joda.time.YearMonth and use the appropriate methods to convert to/from the desired type:
(imports omitted):
#Converter(autoApply = true)
public class YearMonthConverter implements AttributeConverter<YearMonth, Date> {
#Override
public Date convertToDatabaseColumn(YearMonth attribute) {
// uses default zone since in the end only dates are needed
return attribute == null ? null : Date.from(attribute.atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
}
#Override
public YearMonth convertToEntityAttribute(Date dbData) {
// TODO: check if Date -> YearMonth can't be done in a better way
if (dbData == null) return null;
Calendar calendar = Calendar.getInstance();
calendar.setTime(dbData);
return YearMonth.of(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1);
}
}

Categories

Resources