JPA AttributeConverter comparison? - java

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);

Related

Using Spring Specification with Date

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?

How to stop the String from being interpreted as DateTime in Payara?

Good day everyone! I have a get method in rest and the result is stored in something like this:
#XmlRootElement(name = "FooDTO")
public class Foo {
#XmlElement(nillable = true)
private String approvedDate;
private static final DateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat(
"dd.MM.yyyy");
public Date getApprovedDate() {
try {
return StringUtils.isBlank(approvedDate) ? null
: DEFAULT_DATE_FORMAT.parse(approvedDate);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
public void setApprovedDate(Date approvedDate) {
this.approvedDate = approvedDate == null ? "" : DEFAULT_DATE_FORMAT
.format(approvedDate);
}
}
It works in Glassfish server and I get approvedDate as a String in dd.MM.yyyy format. However, in Payara, the String is getting formatted to yyyy-MM-ddTHH:mm:ssZ[Timezone]. How do I adjust this so that the String doesn't get "interpreted" as DateTime? Thanks!
As I see you have a field approvedDate that is private so the the process marshal/unmarshal accesses this field through the get/set, in this case it's returning as Date type on the getApprovedDate method.
Try:
#XmlRootElement(name = "FooDTO")
public class Foo {
#XmlElement(nillable = true)
private String approvedDate;
private static final DateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy");
public String getApprovedDate() {
return approvedDate;
}
public void setApprovedDate(Date approvedDate) {
this.approvedDate = approvedDate == null ? "" : DEFAULT_DATE_FORMAT
.format(approvedDate);
}
}

#Type annotation in Hibernate is not Working. I am using #SQLInsert

I have a model class in hibernate with a field with Calendar type. The corresponding DB column is of timestampwithtimezone(6). I am using custom #SQLInsert. The class looks like below-
#Entity
#SQLInsert("insert into EMPLOYEE (STARTDATETIME) values (TO_TIMESTAMP_TZ(?,'DD- MM-YY HH.MI.SS PM TZHTZM '))" )
#Table(
name = "EMPLOYEE",
)
public class Employee {
#Column(
name = "STARTDATETIME",
nullable = false
)
#Type(type = "com.myPackage.TimeStampTypeImpl")
private Calendar startDateTime;
public Calendar getStartDateTime() {
return this.startDateTime;
}
public void setStartDateTime(Calendar startDateTime) {
this.startDateTime = startDateTime;
}
}
In the class TimeStampTypeImpl which is implementing Usertype is doing the necessary conversion of Calendar to suitable string which is supposed to be given in the input parameter of the insert query, in nullSafeSet method.
But the problem I am getting is- it seems that the the custome class TimestampImpl is not working- the nullSafeSet method is not getting called. So the insert query is failing.
The libraries I am using is-
hibernate-commons-annotations-4.0.1.Final-redhat-2.jar
hibernate-core-4.2.7.SP1-redhat-3.jar
hibernate-jpa-2.0-api-1.0.1.Final-redhat-2.jar
Code in TimeStampTypeImpl :
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
Calendar cal = (Calendar) value;
log.debug("TIMESTAMPIMPL2");
tring dateTime = getOracleFormattedTimeWithZone(cal);
log.debug("TIMESTAMPIMPL3");
st.setString(index, dateTime);
}
private static String getOracleFormattedTimeWithZone(Calendar timeWithZone) {
String dateFormat = "dd-MM-yy hh.mm.ss a Z";
DateFormat df = new SimpleDateFormat(dateFormat);
String dateTime = df.format(timeWithZone.getTime());
System.out.println("()()()()()()()()()"+dateTime);
return dateTime;
}

Using dates in Criteria Query where clause

I have an entity with a java.util.Date field stored as a TemporalType.DATE. When passing a java.util.Date with hours, minutes or seconds to the where clause of a criteria query I can't seem to get a match from the database.
The setup is an embedded H2-database in Spring with Hibernate. I've tried using PostgreSQL instead of H2 and it works. I've also tried to set H2 in PostgreSQL-mode, but it doesn't change anything.
Given the entity
#Entity
public class SomeEntity {
#Id
private int id;
#Temporal(TemporalType.DATE)
private java.util.Date aDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getDate() {
return aDate;
}
public void setDate(Date aDate) {
this.aDate = aDate;
}
}
The following query only returns a match if the hours, minutes and seconds of the parameter have been set to 0.
public List<SomeEntity> someQueryOnDate(Date date) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SomeEntity> query = cb.createQuery(SomeEntity.class);
Root<SomeEntity> root = query.from(SomeEntity.class);
Predicate dateEquals = cb.equal(root.get(SomeEntity_.date), date);
query.where(dateEquals);
// This list is always empty if the date in the predicate has a time part
return em.createQuery(query).getResultList();
}
A full example follows. The test fails on the last assertion, where I query the database using a Date with hours, minutes and seconds set.
#Test
public void testDateEquals() throws ParseException {
Date dateWithoutTime = new SimpleDateFormat("yyyy-MM-dd").parse("2014-07-03");
Date dateWithTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-07-03 09:45:01");
createEntity(dateWithoutTime);
List<SomeEntity> entitiesMatchingDateWithTime = listAllEntitiesWithDate(dateWithTime);
List<SomeEntity> entitiesMatchingDateWithoutTime = listAllEntitiesWithDate(dateWithoutTime);
Assert.assertFalse("No entities matched the date without time", entitiesMatchingDateWithoutTime.isEmpty());
Assert.assertFalse("No entities matched the date with time" , entitiesMatchingDateWithTime.isEmpty());
}
private void createEntity(Date d) {
SomeEntity entity = new SomeEntity();
entity.setDate(d);
em.persist(entity);
// For good measure
em.flush();
em.clear();
}
private List<SomeEntity> listAllEntitiesWithDate(Date date) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SomeEntity> query = cb.createQuery(SomeEntity.class);
Root<SomeEntity> root = query.from(SomeEntity.class);
Predicate dateEquals = cb.equal(root.get(SomeEntity_.date), date);
query.where(dateEquals);
return em.createQuery(query).getResultList();
}
Maybe the solution is provided here:
Hibernate Criteria for Dates
You can use Restrictions to compare dates.

Hibernate. Optimizing sqlRestriction

How can I optimize the following without sqlRestriction:
public List<SomeEntity> getEntityByYearMonthAndDay(Calendar cal) {
Criteria criteria = helper.createCriteria();
criteria.add(sqlRestriction("(DATE(date_column) = ?)", cal.getTime(), org.hibernate.type.StandardBasicTypes.DATE));
return criteria.list();
}
SomeEntity looks like:
#Entity
#Table(name="some_table")
public class SomeEntity extends Identifiable {
#Column(name = "date_column")
private Calendar dateColumn;
//Getters and setters
}
In the DB I have such representation:
date_column => datetime (YYYY-MM-DD HH:mm:ss).
It's obvious that logic compares only date truncating time values.
Yeah, guys :)
So if you want not to use built-in MySQL DATE(...) function and use only JPA:
public List<SomeEntity> getEntityByYearMonthAndDay(Calendar cal) {
Criteria criteria = helper.createCriteria();
Calendar leftBorder = Calendar.getInstance();
leftBorder.setTime(cal.getTime());
Calendar rightBorder = Calendar.getInstance();
rightBorder.setTime(cal.getTime());
rightBorder.add(Calendar.DATE, 1);
Conjunction dateConjunction = Restrictions.conjunction();
dateConjunction.add(Restrictions.eq("dateColumn", leftBorder));
dateConjunction.add(Restrictions.lt("dateColumn", rightBorder));
criteria.add(dateConjunction);
return criteria.list();
}

Categories