« Back

Custom Finder for Portal Entities in a Plugin

Company Blogs June 22, 2012 By David Truong Staff

Sometimes you need to write a custom finder for a table that belongs to core. In my case it was JournalArticle.  My client wanted to avoid using the ext-plugin as much as possible so I had to try to figure out a way to do it within a portlet plugin.

I tried to use dynamic queries as a solution but it turned out to be inadequate because I was unable to group by (I wanted to get the latest articles with a certain structureId).

I needed a custom finder but for awhile I thought this was impossible because you needed to load the Impl of a model during the query which is inaccessible since it is part of portal-impl.  But my experimentation with dynamic queries was not in vain because I figured... if dynamic queries can figure out a way to load the impl class I could probably do the same.

So here is the class I wrote.

It consists of two basic methods:

public static Class getImplClass(Class clazz, ClassLoader classLoader) {
    if (!clazz.getName().endsWith("Impl")) {
        String implClassName = clazz.getPackage().getName() + ".impl." + 
            clazz.getSimpleName() + "Impl";

       	clazz = _classMap.get(implClassName);

       	if (clazz == null) {    
            try {
               			if (classLoader == null) {   
                    Thread currentThread = Thread.currentThread();

                    classLoader = currentThread.getContextClassLoader(); 

                clazz = classLoader.loadClass(implClassName); 
               _classMap.put(implClassName, clazz); 
            catch (Exception e) {
                _log.error("Unable find model " + implClassName, e);
    return clazz;
public static Session openPortalSession() throws ORMException {
    return sessionFactory.openSession();	

private static Log _log = LogFactoryUtil.getLog(CustomFinderHelperUtil.class);

private static Map> _classMap = new HashMap>();
private static SessionFactory sessionFactory =

So basically in my customFinder instead of doing

session = openSession();

I did

session = CustomFinderHelperUtil.openPortalSession();

and instead of doing

q.addEntity("JournalArticle",  JournalArticleImpl.class));

I did

q.addEntity("JournalArticle", CustomFinderHelperUtil.getImplClass(
                JournalArticle.class, true));

(I created a extra method that took a boolean to use the portalClassLoader, you can load it using PortalClassLoaderUtil.getPortalClassLoader())

Hopefully this helps some you guys out.


Threaded Replies Author Date
very cool, now it all makes sense. Wilson Man June 22, 2012 1:10 PM
May be the SQLQuery(Impl) could be extended so... Sampsa Sohlman June 23, 2012 3:24 PM
NIce! 다니엘 Daniel Bastos June 28, 2012 7:42 AM
FYI You are using _classMap in a non ... Jelmer Kuperus July 9, 2012 2:55 AM
Nice Post... Jay Patel July 10, 2012 7:41 AM
Hey jelmer, Good points. I will update my... David Truong July 10, 2012 12:59 PM
Hey Sampsa, That would make things too easy... David Truong July 10, 2012 1:01 PM
It is a bit challenging to add a new action... Muhammed Shakir October 7, 2012 3:09 AM
Great! i asked to me the same question "If... Harvey Tamayo November 29, 2016 4:10 PM

very cool, now it all makes sense.
Posted on 6/22/12 1:10 PM.
May be the SQLQuery(Impl) could be extended so that if there is entity's interface as parameter then, it would find the implementation automatically.

Anyway, good post.
Posted on 6/23/12 3:24 PM.
Posted on 6/28/12 7:42 AM.

You are using _classMap in a non threadsafe way

Also by holding on to the impl class references in a map you are effectively preventing the webapp classloader from being garbage collected. (not a problem if you just use it to load classes from the ROOT webapp, since it's not hotdeployable, but it is if you use this same trick do load classes from another standalone portlet) You'll be blowing up your permgen space
Posted on 7/9/12 2:55 AM.
Nice Post...
Posted on 7/10/12 7:41 AM.
Hey jelmer,

Good points. I will update my code so that if the classLoader is not ROOT it won't put it in the map. You should consider filing a jira issue also because this code is a copy of what is from DynamicFactoryUtil

Thanks for your comments guys
Posted on 7/10/12 12:59 PM in reply to Jay Patel.
Hey Sampsa,

That would make things too easy for you guys then! Haha JK. Good suggestion. It is even more valid because the look up is already being done for dynamic queries. Very little code would have to be written for this improvement.
Posted on 7/10/12 1:01 PM in reply to David Truong.
It is a bit challenging to add a new action with a custom jsp and ensuring that the jsp is wrapped into the theme properly. I have got the solution and it works like a charm. You can find the solution here : http://www.liferayaddict.com/home/-/blogs/new-action-in-hook-in-liferay-6-1
Posted on 10/7/12 3:09 AM in reply to David Truong.
Great! i asked to me the same question "If DynamicQueryFactoryUtil.forClass can, me too. Right?" thanks.
For now i have other issue, i try to do a CustomSQL Query where IS SELECT * customTable INNER JOIN JournalArticle. For now i don't find other solution that modifying portlet-hbm adding the portal table configuration from portal-hbm. Like is suggested in http://www.liferaysavvy.com/2013/02/getting-data-from-multiple-tables-in.html. But if you are interested and you find other solution, that will be great. Regards from Colombia.
Posted on 11/29/16 4:10 PM.