Freemarker date assignment to seemingly Valid Date Fails - java

I'm running into a weird problem that doesn't seem to happen all the time, but when it does, it looks like this:
Error: on line 60, column 31 in foo/bar.ftl
Expecting a date here, found: 2011-12-29 04:37AM
The problematic instruction:
----------
==> assignment: createDate=project.createdTime?datetime("yyyy-MM-dd hh:mma") [on line 60, column 9 in foo/bar.ftl]
----------
Java backtrace for programmers:
----------
freemarker.template.TemplateModelException: Error: on line 60, column 31 in foo/bar.ftl
Expecting a date here, found: 2011-12-29 04:37AM
at freemarker.core.BuiltIn$dateBI$DateParser.parse(BuiltIn.java:334)
at freemarker.core.BuiltIn$dateBI$DateParser.get(BuiltIn.java:305)
at freemarker.core.BuiltIn$dateBI$DateParser.exec(BuiltIn.java:316)
at freemarker.core.MethodCall._getAsTemplateModel(MethodCall.java:93)
at freemarker.core.Expression.getAsTemplateModel(Expression.java:89)
at freemarker.core.Assignment.accept(Assignment.java:90)
at freemarker.core.Environment.visit(Environment.java:210)
at freemarker.core.MixedContent.accept(MixedContent.java:92)
at freemarker.core.Environment.visit(Environment.java:210)
at freemarker.core.Environment.process(Environment.java:190)
at freemarker.template.Template.process(Template.java:237)
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.processTemplate(FreeMarkerView.java:366)
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.doRender(FreeMarkerView.java:283)
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.renderMergedTemplateModel(FreeMarkerView.java:233)
at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:167)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
...
The line in bar.ftl where it's failing looks like this:
<#assign createDate = project.createdTime?datetime("yyyy-MM-dd hh:mma")>
The getter in the Project.java code looks like this:
private Date createdTime;
...
public String getCreatedTime() {
SimpleDateFormat sm = new SimpleDateFormat("yyyy-MM-dd hh:mma");
return createdTime == null ? null : sm.format(createdTime);
}
So to me, it looks like everything is getting returned correctly, and that the code is setup correctly. I'm using FreeMarker 2.3.16 and Spring MVC. It seems to work most of the time, but fails sometimes...
Ideas?

The error message means that, internally, DateFormat.parse has thrown java.text.ParseException. Since the string given in the exception message should be parsed OK with that pattern (and I hope your example is exact and real), and since it happens only sometimes, it stinks like a concurrency (multi-threading) issue around the date-format cache. If you could construct a standalone test that demonstrates this, that would make finding it quicker (I'm in charge of maintaining FM, pretty much). Quickly looking at the source code nothing jumps at me... the syncs are there.
Edit: Another possible reason is that sometimes the FreeMarker "locale" setting is not English. The "AM"/"PM" postfix is different for non-English, and so it causes this error.

Your code looks valid, I've no idea why it fails - especially "sometimes".
One thing that strikes me as odd, however, is that you're converting your date to string first (inside getCreatedTime()) only to parse it back within FreeMarker template. Why not pass it as date to begin with? Something like:
// Project.java
public Date getCreatedTime() {
return this.createdTime;
}
// bar.ftl
<#assign createDate = project.createdTime?datetime>

Related

MongoDB, common part of 2 Querys

I got document that looks like this
#Document(collection="myDocument")
public class MyDocument {
#Id
private String id;
private List<Dates> dates;
}
public class Dates{
private String key;
private DateTime value;
}
And OtherDocument is container for DateTime values from various sources, I can't simply make fields like DateTime birthdate; inside MyDocument because I don't know what key will be, they are just some dates that describe MyDocument. Now, I need to create search engine for those values, for example, someone want's to find all MyDocuments with dates that contains:
key : "Birthdate" greater than
value : "1990-01-01 00:00:00 +00:00"
and key : "Mather's birthday" less than
value: "1975-01-01 00:00:00 +00:00"
So, Criteria (using MongoTemplate here) first may look like this
Criteria criteria = Criteria.where("myDocument.dates.value")
.exists(true)
.gt(DateTimeUtil.valueOf("1990-01-01 00:00:00 +00:00")) //just converting String to DateTime here
.and("myDocument.dates.name")
.exists(true)
.all("Birthday"));
And second one:
Criteria criteria = Criteria.where("myDocument.dates.value")
.exists(true)
.lt(DateTimeUtil.valueOf("1975-01-01 00:00:00 +00:00"))
.and("myDocument.dates.name")
.exists(true)
.all("Mather's birthday"));
The problem is, I can't put those both Criteria in one Query, it will cause error. The only soultion I found till now is to make 2 separate Query in that case and then find common part by using
resultA.retainAll(resultB)
But the point is, I don't want to, this database will store a lot of data and those requests will be very frequent. I need this to work fast, and combining 2 lists in pure Java will be slow as hell with that amount of data. Any ideas how to deal with that?
edit#
here is the error thrown when I try to combine 2 Criteria like this in one Query
caught: (java.lang.RuntimeException), msg(json can't serialize type :
class org.joda.time.DateTime) java.lang.RuntimeException: json can't
serialize type : class org.joda.time.DateTime
You can use below code. $and the query together and use $elemMatch to match the dates fields on multiple condition.
Something like
Criteria criteria1 = Criteria.where("dates").
elemMatch(
Criteria.where("value").exists(true).gt(DateTimeUtil.valueOf("1990-01-01 00:00:00 +00:00"))
.and("name").exists(true).all("Birthday")
);
Criteria criteria2 = Criteria.where("dates").
elemMatch(
Criteria.where("value").exists(true).lt(DateTimeUtil.valueOf("1975-01-01 00:00:00 +00:00"))
.and("name").exists(true).all("Mather's birthday")
);
Criteria criteria = new Criteria().andOperator(criteria1, criteria2);
Note: You may still have the problem with joda time conversion.

Spring #RequestParam vs #ModelArribute when getting a java.util.Date

I have a situation where the following code correctly gets the Date, without the time:
#RequestMapping(value="/pdf", method={RequestMethod.GET,RequestMethod.POST})
public void printPdf(#RequestParam("printDateTime") Date printDateTime .... more) {
printDateTime; // contains date, but NOT the time
...more code here...
}
However, when I use modelAttribute, it will correctly get the date AND the time from the client.
#RequestMapping(value="/pdf", method={RequestMethod.GET,RequestMethod.POST})
public void printPdf(#ModelAttribute WorkerSearchParamsDto searchParamsDto .... more) {
searchParamsDto.getPrintDateTime(); // Returns correct date with client time...
...more code here...
}
I am a little confused about why that would be the case and what I could do to resolve this. There are reasons we would like to not use modelAttribute for the print date, be we can work around it. Any ideas would be helpful.
To be clear, we WANT the time, not just the Date
We are running Spring 3.2.4.RELEASE

HIBERNATE : Don't want to save milliseconds

I got a little problem and I didn't find a suitable solution on the net because my question is a bit tricky for search engine.
There's a lot of topics about hibernate saving milliseconds. But my problem is something else.
In fact, I got a database, which save my date like this :
2014-03-20 10:58:09
I used Hibernate to get back my date, and display it on a web page. But Hibernate retrieve more than that : it also retrieve a 0 milliseconds, like this :
2014-03-20 10:58:09.0
Many people seems to have problem with this, but in my case, I DON'T WANT this information, I want Hibernate to retrieve the date without this .0 !
Thanks for your help !
EDIT AND SOLUTION :
Ok so I made it by using a little hack.
In my specific object using by Hibernate, I had this method :
public Date getModificationDate() {
return modificationDate;
}
I just simply create an other method :
private static final SimpleDateFormat FMT = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
public String getModificationDateLabel() {
if (modificationDate != null) {
return FMT.format(modificationDate);
}
return null;
}
So, when I display in my webpage (I use Velocity Template), I just run through my list of object an display the label :
#foreach( $object in $objects)
$!{object.modificationDateLabel}
#end
The SimpleDateFormat allow me to remove the .0, and by creating a new method, I don't disturb the behavior of getting a Date with Hibernate.
Thanks for your time !
I don't see a problem with the date returned as "2014-03-20 10:58:09.0" is equal to "2014-03-20 10:58:09". Can you provide specific scenario where this can result in issue?
Or use SimpleDateFormat("yyyy-MM-dd HH:mm:ss") then parse your date in this format before using the date.

Data Corruption issue running function in Tomcat 5.5 & 6.0

I've been trying to figure out this bug for few days. I have narrowed the issue down to a test case as follows. Again, this is a test case that causes the bug to happen. The function (at this point) is not a practical one, but just trying to figure out the bug.
Server is running:
- Tomcat 6
- OpenJDK 1.6.0_17
- CentOS 5.5
I have a simple Class file with the following method Static Method and Static variable declaration:
public static java.text.SimpleDateFormat displayDateSDF1 = new java.text.SimpleDateFormat("MM/dd/yyyy");
public static java.util.Date getSubDateMini(String inputDate)
{
java.util.Date testObj = null;
try
{
testObj = displayDateSDF1.parse("01/01/2000") ;
}
catch (Exception e)
{
}
return testObj;
}
Testing in Tomcat:
When I run this method, I'd expect to get the same result every time, right? However, if I call this method from a JSP, I get the expected result of a Date object with value 1/1/2000 about 99.9% of the time. However, sometimes I get an unexpected data object passed back with a seemingly random date value.
To test this, I created a JSP with the following code segment in it:
for (int i=0; i<200000;i++)
{
java.util.Date testObjLib = TestDate.getSubDateMini("") ;
if (testObjLib!=null&&!testObjLib.toString().equalsIgnoreCase("Sat Jan 01 00:00:00 PST 2000"))
{
out.print("<br>"+testObjLib+"");
}
}
Some dates that appear are as follows:
Wed Jan 01 00:00:00 PST 1
Fri Aug 01 00:00:00 PDT 2166
In 200,000 runs, I get approximately 50 bad dates which gives an error rate of ~0.025% but again it's random. I've run this loop with 10 iterations and received an error. Sometimes it runs the loop with 200,000 and all dates look good.
Testing in Java:
Running this loop via a console/terminal app in CentOS with the same loop, I have not seen this error happen yet. I increased the loop to 10,000,000 and had no false results as of yet.
I can understand out of memory or some thrown error (which would result in a null value) but not corrupt/inconsistent data. I built up a new server from scratch with Tomcat 6 and also tried Tomcat 5.5 and both have the same results. I have not tried Tomcat 7.
Any suggestions?
SimpleDateFormat is not thread-safe.
This means that when it is accessed from multiple threads, unexpected results can be observed. And tomcat is serving each request from a separate thread, so whenever two requests are made at the same time, the problem would arise.
You have a number of options:
instantiate the SimpleDateFormat on each call of the method (rather than making it static)
if you need the format more than once per thread, use a ThreadLocal to store it.
alternatively use joda-time, where DateTimeFormat is thread-safe.

Problem using JPA with Oracle and grouping by hour

I have a problem using JPA with Oracle and grouping by hour.
Here's the scenario:
I have an entiry named EventData. This entity has a java.util.Date field named startOfPeriod. This field maps in a table field of datatype DATE.
The query I'm using is something like:
select min(ed.startOfPeriod) as eventDate,
(...)
from
Event e inner join e.eventDatas ed
(...)
group by
year(ed.startOfPeriod),
month(ed.startOfPeriod),
day(ed.startOfPeriod),
hour(ed.startOfPeriod)
order by 1
If I remove the group by "hour(ed.startOfPeriod)" it works fine (it doesn't produce any errors but it doesn'to do what I want).
When I insert this group by clause it makes this exception:
Caused by: java.sql.SQLException: ORA-30076: campo de extração inválido para origem de extração
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:745)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:219)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:813)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1049)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:854)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1154)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3370)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3415)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:92)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1812)
at org.hibernate.loader.Loader.doQuery(Loader.java:697)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.doList(Loader.java:2232)
Analysing the error code, it happens when "The extract source does not contain the specified extract field.". But the source of extraction (the startOfPeriod field) is of datatype DATE (which has an hour part).
The same code works like a charm in SQL Server.
Anyone knows what is going on?
Tnhks!
Have you tried TO_CHAR(d, 'HH24') instead? You could also trunc() to hours...
Not quite an answer, but it sounds suspiciously like a driver issue to me (especially as this works fine on SQLServer). What version of the Oracle driver are you using? Have you tried different versions?
I didn't convert all my DATE fields to TIMESTAMP ones.
Instead, I extended the Oracle's dialect to rewrite the hour function.
Like that:
public class Oracle9Dialect extends org.hibernate.dialect.Oracle9Dialect
{
public Oracle9Dialect()
{
super();
registerFunction("hour", new SQLFunctionTemplate(Hibernate.INTEGER, "to_number(to_char(?1, 'hh24'))"));
}
}
Using this dialect (org.hibernate.dialect.Dialect), the hour function will not use the ANSI hour function (extract(hour from <FIELD>)). It will use to_number(to_char(<FIELD>, 'hh24')) instead.
The bad thing is that it always use the custom function (even when it doesn't need to be used, like with a TIMESTAMP field).
This is what I did to solve my problem.

Categories

Resources