« Back

Tricks of Velocity class loading

Company Blogs September 16, 2010 By Ray Augé Staff

Recently I was asked to solve a WCM dynamic Template problem which involved listing articles using the business logic of the template.

One of the first problems I encountered was of course doing a search for the Articles via the JournalArticleLocalService which, in the case of the searchs which return List<JournalArticle>, require an OrderByComparator. Since there is no way to directly instantiate classes in Velocity I wondered how I was going to handle this issue.

Luckily my colleague Thiago was working with a community member (Sabrina Schürhaus Locks) who had already solved the problem in a rather interesting and simple way:

 

#set ($obc = $portal.getClass().forName("com.liferay.portlet.journal.util.comparator.ArticleDisplayDateComparator").newInstance())

 

It's so simple I feel silly that I never thought of this myself.

Kudos Sabrina!

Threaded Replies Author Date
I ran into this issue as well and found this... Amos Fong September 16, 2010 10:38 AM
Ah, but you can my friend! #set ($obcClass =... Ray Augé September 16, 2010 11:53 AM
Note, this is complicated by the fact that it's... Ray Augé September 16, 2010 11:56 AM
wow cool, velocity java magic! thanks for the... Amos Fong September 16, 2010 12:21 PM
Neat trick! I'll have to remember that one. Gregory Amerson September 16, 2010 1:45 PM
I posted something similar to the forums a... Jelmer Kuperus September 27, 2010 9:30 AM
Until recently (I just did a svn update of the... Ian White October 19, 2011 9:28 PM
Hey Ian, I tried this with the same old test... Ray Augé October 20, 2011 8:47 PM
hello ray, how to get value from a field which... Arya Nugroho October 28, 2011 1:29 PM
Hey Arya, Can you clarify a little? I'm not... Ray Augé November 3, 2011 6:24 AM
Hello! I also tried Ray's test-velotool-hook... oscar caro puerto March 6, 2012 3:40 AM
Hi, I am facing on problem with the Caroussel... Mehdi Khan November 9, 2012 4:13 AM
I don't think that relates to the post. If so,... Ray Augé November 9, 2012 4:49 AM
Hello! I've tried velocity class loading in... Matej Dolanc January 16, 2014 2:20 PM
We added some security around classloading. You... Ray Augé January 16, 2014 2:43 PM
Thank you very much... Matej Dolanc January 16, 2014 2:55 PM
Hi Ray, Somehow this is not working in 6.1+... Nasir Hussain May 2, 2015 9:21 AM
My bad... got it working, wrong constructor... Nasir Hussain May 2, 2015 12:09 PM
Any idea how to create the obc to be driven by... Dave Weitzel June 29, 2015 7:47 AM

I ran into this issue as well and found this same solution. However, you can't pass any parameters so you can't do ascending obc's.
Posted on 9/16/10 10:38 AM.
Ah, but you can my friend!


#set ($obcClass = $portal.getClass().forName("com.liferay.portlet.journal.util.comparator.ArticleD­isplayDateComparator"))
#set ($booleanType = $portal.getClass().forName('java.lang.Boolean'))
#set ($obcConstructor = $obcClass.getConstructor($booleanType.getField('TYPE').staticValue))

#set ($obc = $obcConstructor.newInstance(true))
Posted on 9/16/10 11:53 AM in reply to Amos Fong.
Note, this is complicated by the fact that it's a constructor having primitive args, on top of which you can't directly reference static fields in velocity, so getting the primitive type of a class required more reflection tricks. But this example demonstrates all of that!
Posted on 9/16/10 11:56 AM in reply to Ray Augé.
wow cool, velocity java magic! thanks for the lesson
Posted on 9/16/10 12:21 PM in reply to Ray Augé.
Neat trick! I'll have to remember that one.
Posted on 9/16/10 1:45 PM.
I posted something similar to the forums a while back that was even hackier (due to the difficulty of getting to int.class)

http://www.liferay.com/community/forums/-/message_boards/message/55148­92

these are pretty dirty tricks tho
Posted on 9/27/10 9:30 AM.
Until recently (I just did a svn update of the portal trunk) the velocity hook approach was working well, whereby you simply defined your java interface + impl pair in an applicationContext.xml file. See Ray's test-velotool-hook sample.

Alas, with the latest trunk code, your beans are not able to be loaded. Fingers crossed this is just a bug and not a decision to stop supporting velocity hooks.
Posted on 10/19/11 9:28 PM in reply to jelmer kuperus.
Hey Ian,

I tried this with the same old test velo hook:

#set ($myTool = $utilLocator.findUtil('test-velotool-hook','com.mytool.MyTool'))

$myTool
<br />
$myTool.operationOne()
<br/>
$myTool.operationTwo($text.data)

and got back:
com.mytool.MyToolImpl@5741bf0e
Hello out there!
Hello Ray!

Is it still not working?
Posted on 10/20/11 8:47 PM in reply to Ian White.
hello ray, how to get value from a field which is characterized by a specific tags on the article?

thanks
Posted on 10/28/11 1:29 PM in reply to Ray Augé.
Hey Arya,

Can you clarify a little? I'm not exactly sure what you mean!
Posted on 11/3/11 6:24 AM in reply to Arya Nugroho.
Hello!
I also tried Ray's test-velotool-hook sample in liferay 6.0.6 and is working fine, but I recently downloaded liferay-portal-6.1.0-ce-ga1 bundled with tomcat, deployed the hook, and tested from a velocity template, but in this version I'm getting:
NoSuchBeanDefinitionException: No bean named 'com.mytool.MyTool' is defined
Posted on 3/6/12 3:40 AM.
Hi, I am facing on problem with the Caroussel ,(1)when i refresh the page Caroussel loading slowly some time its take more than 5 minutes to load the message Caroussel.
(2).Sometimes when I log on, the caroussel is just blank. It takes around 2 - 5 minutes till the caroussel loads on the page.
And its happening only on Ineternet Explorer(IE)
Posted on 11/9/12 4:13 AM.
I don't think that relates to the post. If so, can you explain how?
Posted on 11/9/12 4:49 AM in reply to Mehdi Khan.
Hello!

I've tried velocity class loading in LIferay 6.2 (liferay-portal-6.2.0-ce-ga1) and it doesn't work for me. It works fine in LIferay 6.1.

Example:
#set ($obc = $portal.getClass().forName("com.liferay.portlet.journal.util.comparator.ArticleD­isplayDateComparator").newInstance())
$obc

I get the following warning message ( LIferay 6.2):

21:44:52,996 WARN [RuntimePageImpl-3][velocity:145] Cannot retrieve method forName from object of class java.lang.Class due to security restrictions.
21:44:52,997 DEBUG [RuntimePageImpl-3][velocity:155] RHS of #set statement is null. Context will not be modified. 10157#10197#11456[line 1, column 1]

Does anyone know where could be the issue?

Thanks
Matej
Posted on 1/16/14 2:20 PM.
We added some security around classloading. You can adjust the settings to your usage. http://docs.liferay.com/portal/6.2/propertiesdoc/portal.properties.html#Velocity­%20Engine
Posted on 1/16/14 2:43 PM in reply to Matej Dolanc.
Thank you very much...
Posted on 1/16/14 2:55 PM in reply to Ray Augé.
Hi Ray,

Somehow this is not working in 6.1+ Java 6 for this particular class

#set ($inetAddressClass = $portal.getClass().forName("javax.mail.internet.InternetAddress"))
#set ($stringType = $portal.getClass().forName('java.lang.String'))
#set ($inetAddressConstructor = $inetAddressClass.getConstructor($stringType.getField('TYPE').staticValue))
#set ($toAddress = $inetAddressConstructor.newInstance("abc@gmail.com"))
$toAddress, $inetAddressConstructor, $inetAddressClass

here the $toAddress is not working other variables are fine
Posted on 5/2/15 9:21 AM.
My bad... got it working, wrong constructor invokation

#set ($inetAddressConstructor = $inetAddressClass.getConstructor($stringType))
Posted on 5/2/15 12:09 PM in reply to Nasir Hussain.
Any idea how to create the obc to be driven by a custom Date field in the structure of the articles?
Seems expensive to get alist here, create another list wioth data from the xml content and then resort that list and then get more data for each article when listing the now correctly sorted list
Posted on 6/29/15 7:47 AM.