Using Spring Specification with Date - java

How can I use Spring Specification with Date field? I have no problem with 'normal' fields like Strings. But when I have Date, I have a problem and can't find a solution to solve it.
Here is my TaskEntity.class:
#Entity
#Table(name = "TASKS")
public class TaskEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String description;
#ManyToOne
private StatusEntity status;
private Date expiryDate;
// ....
}
And here is my TaskSpecification.class:
public class TaskSpecification implements Specification<TaskEntity> {
private static final Logger LOGGER = Logger.getLogger(TaskSpecification.class.getName());
private List<SearchCriteria> searchCriteriaList;
public TaskSpecification() {
this.searchCriteriaList = new ArrayList<>();
}
public void add(SearchCriteria criteria) {
searchCriteriaList.add(criteria);
}
#Override
public Predicate toPredicate(Root<TaskEntity> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
LOGGER.info("toPredicate()");
List<Predicate> predicates = new ArrayList<>();
for (SearchCriteria criteria : searchCriteriaList) {
if (criteria.getValue() instanceof Date) {
// WHAT TO DO HERE?
} else {
predicates.add(
builder.equal(
root.get(criteria.getKey()),
criteria.getValue().toString())
);
}
}
LOGGER.info("toPredicate(...)");
return builder.and(predicates.toArray(new Predicate[0]));
}
}

Ihe same problem I faced a month ago but this solution solved my issue.
public static Date startDate(Date date) {
try {
DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd");
String strDate = df2.format(date) + "T00:00:00";
LocalDateTime localDate = LocalDateTime.parse(strDate);
Instant instant = localDate.atZone(ZoneId.systemDefault()).toInstant();
date = Date.from(instant);
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
return date;
}
Create a function and call where you use the date.
like that
values.add(EntitiesSpecification.startDate(fr.getValues().get(0)));

you can get the date value and add the date format in entity like MM-DD-YYYY. Could you please try this way?

Related

How to deserialize a String to a Date with Morphia

I have a Mongo collection with objects of this format:
{
id: 1,
date: "2020-08-06T12:00:00Z",
...
}
I have Java code that needs to read from this collection but never writes to it. The process that writes to this collection is not owned by me so I can't necessarily change the format of that date string. I initially tried to model my Java Morphia object like this:
#Entity public class MyDocument {
#Id
private Integer id;
private Date date;
...
}
This did not work because Morphia didn't know how to deserialize that date format into a Date object. The solution that I came up with was treating the date as a String on the POJO and then having a getDate() method that did the actual deserialization. I am wondering, is there a better way for me to do this? I know if you're using Jackson you can annotate certain fields with #JsonDeserialize and pass a deserializer so I was wondering if there was something similar for Morphia.
My solution (which feels suboptimal to me):
#Entity public class MyDocument {
#Id
private Integer id;
private String date;
...
private Date getDate() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
try {
return dateFormat.parse(date);
} catch (Exception ex) {
return null;
}
}
}
You can go ahead and create a simple converter extending the TypeConverter like so:
public class DateConverter extends TypeConverter {
private static final String FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private final SimpleDateFormat simpleDateFormat;
public DateConverter() {
super(Date.class);
this.simpleDateFormat = new SimpleDateFormat(FORMAT);
}
#Override
public Object decode(Class<?> targetClass, Object fromDBObject, MappedField optionalExtraInfo) {
try {
return simpleDateFormat.parse(((String) fromDBObject));
} catch (ParseException e) {
return null;
}
}
}
The go ahead and register your formatter for your document entity like so:
#Entity("Documents")
#Converters(DateConverter.class)
public class Document {
#Id
private Integer id;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
private Date date;
public Date getDate() { return date; }
public void setDate(Date date) { this.date = date; }
#Override
public String toString() {
return "Document{" +
"id=" + id +
", date=" + date +
'}';
}
}
This will effectively tell Morphia to decode the database incoming values via parsing the string with the desired pattern, resulting directly into a concrete Date object without any additional conversion logic.

Getting null value for days calculated / added current date plus the user entered value

Getting null value for days calculated / added current date plus the user entered value
We are calculating a column value based on the user entered value ie
Number of days entered by the User plus the current date.
private Date setdaysAttendanceApprovedWithAdditionalDays(int daysAttendanceApproved2) {
Date currentDate = new Date();
Calendar c = Calendar.getInstance();
c.setTime(currentDate);
c.add(Calendar.DATE, daysAttendanceApproved2);
Date currentDatePlusUserInput = c.getTime();
return currentDatePlusUserInput;
}
Desired Output
If a user enters the value of 10
then
8 May 2020 Plus 10
the Output would be 18-May-2020
in the set NewDate
Issue
the setNewdate setdaysAttendanceApprovedWithAdditionalDays is the being set to null
<h:form>
<p:panel id="panel" header="New User">
<h:panelGrid columns="3" cellpadding="5">
<p:outputLabel for="Additional Days" value="Additionaldays:" />
<p:inputText id="additionaldays" value="#{saveMB.attendanceApprovalEntity.daysAttendanceApproved}">
</p:inputText>
</h:panelGrid>
<p:commandButton value="Save" actionListener="#{saveMB.approveAttendance}" />
</p:panel>
</h:form>
saveMB.java
#ManagedBean(name = "saveMB")
#ViewScoped
public class saveMB implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(saveMB.class);
private Integer daysAttendanceApproved;
public Integer getdaysAttendanceApproved() {
return daysAttendanceApproved;
}
public void setdaysAttendanceApproved(Integer daysAttendanceApproved) {
this.daysAttendanceApproved = daysAttendanceApproved;
}
private Date newdate;
public Date getNewdate() {
return newdate;
}
public void setNewdate(Date newdate) {
this.newdate = newdate;
}
private AttendanceFlow attendanceApprovalEntity;
public AttendanceFlow getattendanceApprovalEntity() {
return attendanceApprovalEntity;
}
public void setattendanceApprovalEntity(AttendanceFlow attendanceApprovalEntity) {
this.attendanceApprovalEntity = attendanceApprovalEntity;
}
#PostConstruct
public void init() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
Map<String, String> params = externalContext.getRequestParameterMap();
}
private Date setdaysAttendanceApprovedWithAdditionalDays(int daysAttendanceApproved2) {
Date currentDate = new Date();
Calendar c = Calendar.getInstance();
c.setTime(currentDate);
c.add(Calendar.DATE, daysAttendanceApproved2);
Date currentDatePlusUserInput = c.getTime();
return currentDatePlusUserInput;
}
public void approveAttendance(AjaxBehaviorEvent event) {
FacesContext facesContext = FacesContext.getCurrentInstance();
try {
this.attendanceApprovalEntity.setNewdate(setdaysAttendanceApprovedWithAdditionalDays(this.attendanceApprovalEntity.getdaysAttendanceApproved()));
} catch (Exception e) {}
}
}
AttendanceFlow.java
#Entity
#Table(name = "ATTENDANCE_FLOW")
#NamedQuery(name = "AttendanceFlow.findAll", query = "SELECT h FROM AttendanceFlow h")
public class AttendanceFlow implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "ATTENDANCE_FLOW_ID_GENERATOR", sequenceName = "ATTENDANCE_FLOW_ID_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ATTENDANCE_FLOW_ID_GENERATOR")
#Column(name = "ATTENDANCE_FLOW_ID")
private Integer AttendanceFlowId;
#Column(name = "DAYS_ATTENDANCE_APPROVED")
private Integer daysAttendanceApproved;
#Column(name = "NEW_DATE")
#Temporal(TemporalType.DATE)
private Date newdate;
public Date getNewdate() {
return newdate;
}
public void setNewdate(Date newdate) {
this.newdate = newdate;
}
public Integer getAttendanceFlowId() {
return AttendanceFlowId;
}
public void setAttendanceFlowId(Integer AttendanceFlowId) {
this.AttendanceFlowId = AttendanceFlowId;
}
public Integer getdaysAttendanceApproved() {
return daysAttendanceApproved;
}
public void setdaysAttendanceApproved(Integer daysAttendanceApproved) {
this.daysAttendanceApproved = daysAttendanceApproved;
}
}
While Debugging I can find the value of
this.attendanceApprovalEntity.getdaysAttendanceApproved
ie user entered value something like 10 , but I could not proceed afterthat
LocalDate::plusDays
Use LocalDate instead of outdated Date and Calendar. Check this for more details.
Do it as follows:
private LocalDate setDaysAttendanceApprovedWithAdditionalDays(int daysAttendanceApproved) {
LocalDate date = LocalDate.now();
return date.plusDays(daysAttendanceApproved);
}
A quick demo:
import java.time.LocalDate;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(setDaysAttendanceApprovedWithAdditionalDays(10));
}
static LocalDate setDaysAttendanceApprovedWithAdditionalDays(int daysAttendanceApproved) {
LocalDate date = LocalDate.now();
return date.plusDays(daysAttendanceApproved);
}
}
Output:
2020-05-18
JPA and java.time
Remove #Temporal annotation from the attribute. Also, note that if you are using JPA 2.1 or earlier, you need to write a converter as shown here. If you are are using JPA 2.2 or later, you do not need any converter.
Use the GregorianCalendar class instead. Today's date can be obtained with date=new GregorianCalendar() and the number entered by the user can be added with date.add(Calendar.DAY_OF_MONTH,number).

Hot to add a list of parameters of another object in jpa Criteria

I have a class Director
public class Director {
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="transacao_id")
private Company company;
private Date registrationDate;
...
}
I have a class Company
public class Company {
private Long id;
private String cnpj;
private String description;
...
}
I need to add another filter in predicates...
I need to fetch a list from Director, filtering through a list of cnpj using jpa predicates, for example:
private Predicate[] criarRestricoes(FilterDTO filter, CriteriaBuilder builder, Root<Director> root) {
List<Predicate> predicates = new ArrayList<>();
Date today = new Date();
if (filter.getRegistrationDate() != null) {
predicates.add(builder.between(root.get("registrationDate").as(Date.class), today, filter.dateParam));
}
if (!StringUtils.isEmpty(filter.getCnpj())) {
predicates.add(builder.equal(???????????, ???????????????);
}
return predicates.toArray(new Predicate[predicates.size()]);
}
builder.equal(root.join("company").get("cnpj"), filter.getCnpj());

JPA AttributeConverter comparison?

I'm looking for an easy way to query a database column of type string in format YYYYMMDD. This could be done with a native query like:
select * from TPRODUCT where to_date(ENDOFPRODUCTION, 'YYYYMMDD') > CURRENT_DATE;
But is there a way to achieve this comparison with an AttributeConverter
#NamedQuery(name = "product.filterByEOP", query =
"select p from Product p where p.eop > :currentDate")
Well, it turns out you can. In case anyone else is looking into this, after checking the reference I ended up with:
public class DateConverter implements AttributeConverter<Date, String> {
private final String DATE_FORMAT = "YYYYMMDD";
#Override
public String convertToDatabaseColumn(Date date) {
return new SimpleDateFormat(DATE_FORMAT).format(date);
}
#Override
public Date convertToEntityAttribute(String dateString) {
Date converted = null;
try {
converted = new SimpleDateFormat(DATE_FORMAT).parse(dateString);
} catch (ParseException ex) {
}
return converted;
}
}
which you can then use on an entity attribute:
#Column(name = "ENDOFPRODUCTION")
#Convert(converter = DateConverter.class)
private Date eop;
and use the query:
final TypedQuery<Product> query = this.entityManager.createNamedQuery("product.filterByEOP", Product.class);
query.setParameter("currentDate", new Date());
List<Product> models = query.getResultList();
Why you don't convert your String to a date and use this last like it is :
String myDate = "20170607";
DateFormat format = new SimpleDateFormat("YYYYMMDD");
Date newDate = format.parse(myDate);
Now you can use :
query.setParameter("currentDate", newDate);

mysql timestamp displaying in seconds - how to display in java

The timestamp '2015-06-15 13:01:48' which is stored in MySQL database is coming as 1434369708000 in my rest api response. How to handle so that the response also has the same format. I'm using Java, Hibernate, Restful WS with MySQL.
Entity:
private Date CreatedDateTime;
#Column(name = "created_Date_Time", columnDefinition = "TIMESTAMP")
public Date getCreatedDateTime() {
return createdDateTime;
}
public void setCreatedDateTime(Date createdDateTime) {
this.createdDateTime= createdDateTime;
}
JSON View:
#JsonView({MessageView.class})
public Date getCreatedDateTime() {
if (device != null) {
return device.getCreatedDateTime();
}
return null;
}
public void setCreatedDateTime(Date CurrentServerUTC) {
if (device != null) {
this.device.getCreatedDateTime(CurrentServerUTC);
}
}
http://fasterxml.github.io/jackson-annotations/javadoc/2.0.0/com/fasterxml/jackson/annotation/JsonFormat.html
On Entity try annotating CreatedDateTime with:
#JsonFormat(pattern = "yyyy-MM-dd kk:mm:ss")
private Date CreatedDateTime;
Double check the pattern though, I'm not %100 sure it's correct. It's the same as Java SimpleDatePattern string.
PS: non-static field names start with lowercase letter in Java as a convention.
I wrote a simple test to showcase this annotation:
public class JacksonDateTest {
#Test
public void test() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectMapper om = new ObjectMapper();
om.writeValue(baos, new Sth());
baos.write("\n Sth2 \n".getBytes());
om.writeValue(baos, new Sth2());
System.out.println(baos.toString());
baos.close();
}
public class Sth {
#JsonFormat(pattern = "yyyy-MM-dd kk:mm:ss")
Date creationDate = new Date();
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
}
public class Sth2 {
Date creationDate = new Date();
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
}
}
It works. Sth is serialized as:
{"creationDate":"2015-06-16 16:09:06"}
while Sth2 is serialized as:
{"creationDate":1434470946137}
There must be something else going wrong in your code.

Categories