Ask Questions and Find Answers
Important:
Ask is now read-only. You can review any existing questions and answers, but not add anything new.
But - don't panic! While ask is no more, we've replaced it with discuss - the new Liferay Discussion Forum! Read more here here or just visit the site here:
discuss.liferay.com
RE: Make Custom Entity Asset
Hey everyone ! i m there again to ask your help ^^ I m tryin to make my customs entities as Assets. I followed this https://portal.liferay.dev/docs/7-0/tutorials/-/knowledge_base/t/adding-updating-and-deleting-assets-for-custom-entities to add a line in the AssetEntry table. This is working fine.I rode about a render for my Custom Entity but i saw that it's rendering the title and description if u don't do any render, and this is enough. I found it here at the third line :https://portal.liferay.dev/docs/7-0/tutorials/-/knowledge_base/t/rendering-an-asset
My problem is that the line is added in asset but it's not displaying and not searcheable, what did i do wrong ?
My problem is that the line is added in asset but it's not displaying and not searcheable, what did i do wrong ?
Hi,
You need to index custom entity and make it available for search portlet by implementing opensearch
Please refer below .
https://liferay.dev/forums/-/message_boards/message/84418151
1. Indexing Custom Entity Refer
https://portal.liferay.dev/docs/7-0/tutorials/-/knowledge_base/t/creating-a-guestbook-indexer
2. For making custom enitity available in search portlet you need to implement opensearch
https://github.com/liferay/liferay-portal/blob/7.0.x/modules/apps/web-experience/journal/journal-service/src/main/java/com/liferay/journal/search/JournalOpenSearchImpl.java
You need to index custom entity and make it available for search portlet by implementing opensearch
Please refer below .
https://liferay.dev/forums/-/message_boards/message/84418151
1. Indexing Custom Entity Refer
https://portal.liferay.dev/docs/7-0/tutorials/-/knowledge_base/t/creating-a-guestbook-indexer
2. For making custom enitity available in search portlet you need to implement opensearch
https://github.com/liferay/liferay-portal/blob/7.0.x/modules/apps/web-experience/journal/journal-service/src/main/java/com/liferay/journal/search/JournalOpenSearchImpl.java
Hey Mohammed, Just a small correction. You don't need to implement the OpenSearch interface to make your entity searchable with the Liferay search -- all you have to do is make sure that your search configuration includes the model for your custom entity. If you have implemented the indexer, then they will be found, and if you have implemented the Asset Renderer, then they will be rendered as part of the out of the box functionality. Open Search is for something else altogether. Implementing this interface allows you to use a global search bar (read: browser) and set the scope of the search to the current site -- so you search the "Liferay site" but using your browser in place of the search portlet. Normally you have to actually make configuration changes to your browser to enable this behaviour. Outside of this correction, I would agree with everything else you've said here -- custom indexer, custom renderer and I would also add several methods to my service definition (MyCustomEntityLocalServiceImpl) that you can use to invoke searches.
I followed the second link creating the same but it didn't work ... I don't understand because when i create one it appear in the database in asset table, it's also indexing properly and searchable throw ElasticSearch but not in the liferay search portlet.
I can also select my entity in asset publisher portlet configuration, but they don't appear in the portlet .. I have no error
I can also select my entity in asset publisher portlet configuration, but they don't appear in the portlet .. I have no error
Okay after fex days of deep torture, i finally succed to make my asset searchable by adding this in my indexer :
document.add(new Field(Field.GROUP_ID,Long.toString(ENTITY.getGroupId())));
document.add(new Field(Field.SCOPE_GROUP_ID,Long.toString(ENTITY.getGroupId())));
document.add(new Field(Field.STATUS,Long.toString(0L)));
But my torture is not finish, now in he search result i have 0 result displaying but i can see 4 documents and 1 of my entity in the type tab on the left. I don't undertand, i tried to edit the getJspPath() method and i added a full_content.jsp file in my service builder Meta-in/ressources/asset/entityName folder. Nothing changed. If my result contain one of my custom asset the rendering dont work ... Helppppppp
document.add(new Field(Field.GROUP_ID,Long.toString(ENTITY.getGroupId())));
document.add(new Field(Field.SCOPE_GROUP_ID,Long.toString(ENTITY.getGroupId())));
document.add(new Field(Field.STATUS,Long.toString(0L)));
But my torture is not finish, now in he search result i have 0 result displaying but i can see 4 documents and 1 of my entity in the type tab on the left. I don't undertand, i tried to edit the getJspPath() method and i added a full_content.jsp file in my service builder Meta-in/ressources/asset/entityName folder. Nothing changed. If my result contain one of my custom asset the rendering dont work ... Helppppppp
Check whether your asset renderer is getting called by adding log in your gettitle() or getjsppath () or any exception your getting while rendering your custom asset
Also check have u added Field.CLASS_NAME_ID,and Field.CLASS_NAME_ID to your document.add();
That's my biggest problem ... I don't have any logs even if i put some in the fonctions. The only logs appearing is when i deploy in the assetrendererfactory in the constructor method. I also don't have any error warning or exception. What do you mean by Field.CLASS_NAME_ID ?
You can refer Journal Indexer and see are you missing soemthing
https://github.com/liferay/liferay-portal/blob/7.1.x/modules/apps/journal/journal-service/src/main/java/com/liferay/journal/internal/search/JournalArticleIndexer.java
https://github.com/liferay/liferay-portal/blob/7.1.x/modules/apps/journal/journal-service/src/main/java/com/liferay/journal/internal/search/JournalArticleIndexer.java
Let's shed a little light for you on CLASS_NAME and CLASS_NAME_ID and CLASS_PK. This is an important pattern in Liferay to understand as you work with the product because it is used extensively, and once you get a handle on it, it allows you to start wiring in a lot of the out of the box features into your custom features.
First things first, since you have a service builder project and you have generated some custom entities, go to your database and do a SELECT * on the ClassName_ table.
You'll find many familiar references in here, along with the custom stuff that you have added. So basically, when you use Service Builder to generate your entity and deploy your module, one of the many things that happens is you get an entry in this table. So what is it used for?
Truthfully, I have always struggled to explain this -- I understand it, just finding the right words seems to be a challenge. The best way I have come up with to date is that the ClassName, ClassNameId and ClassPK are ways to "genericize" references. The AssetEntry is a great example, but there are many more -- Ratings, Subscriptions, etc. The challenge is, how do you data model something like a Rating (which is generic) but then associate it to something specific, like a Message Board Post vs. a Blog Post. Well, in Liferay, we do this with the ClassName, ClassNameId, ClassPK stuff.I'm just going to make numbers up here to illustrate the point. Let's say in your ClassName_ table you have the following.
Where the first two rows are of course out of the box entries, and the last one is a reference to your custom entity. Let's assume that you have a Player table with the following --
Now, if you use the Liferay pattern then that means you can identify John Snow, as
... so in your code you can identify the model and the specific data record by combining the class name and the PK from the player table. So, if you wrote a portlet that rendered player details for example, and then you added the option to be able to "rate a player" you don't have to write all that plumbing to manage ratings yourself. You can use Liferay's Ratings API and services to record ratings for Player, John Snow, in the Ratings tables and then you can use the Ratings taglibs to render them in your portlet. AND! like I mentioned above, this pattern can repeat itself for other features like comments, subscriptions, asset entries etc. So it's a way to genericize meta data about your entity but store it in a central table so that you don't end up with a Ratings_Blogs table and a Ratings_Journal_Article table and a Ratings_Player table etc.
Make sense?
First things first, since you have a service builder project and you have generated some custom entities, go to your database and do a SELECT * on the ClassName_ table.
You'll find many familiar references in here, along with the custom stuff that you have added. So basically, when you use Service Builder to generate your entity and deploy your module, one of the many things that happens is you get an entry in this table. So what is it used for?
Truthfully, I have always struggled to explain this -- I understand it, just finding the right words seems to be a challenge. The best way I have come up with to date is that the ClassName, ClassNameId and ClassPK are ways to "genericize" references. The AssetEntry is a great example, but there are many more -- Ratings, Subscriptions, etc. The challenge is, how do you data model something like a Rating (which is generic) but then associate it to something specific, like a Message Board Post vs. a Blog Post. Well, in Liferay, we do this with the ClassName, ClassNameId, ClassPK stuff.I'm just going to make numbers up here to illustrate the point. Let's say in your ClassName_ table you have the following.
Class Name Class Name Id
com.liferay...JournalArticle 21005
com.liferay...BlogEntry 22004
com.abc...Player 24500
Where the first two rows are of course out of the box entries, and the last one is a reference to your custom entity. Let's assume that you have a Player table with the following --
Player ID Name Position Age Retired
21345 John Snow CF 22 False
98432 Chris Jade RD 20 False
Now, if you use the Liferay pattern then that means you can identify John Snow, as
className=com.abc...Player
classNameId=24500classPK=21345
... so in your code you can identify the model and the specific data record by combining the class name and the PK from the player table. So, if you wrote a portlet that rendered player details for example, and then you added the option to be able to "rate a player" you don't have to write all that plumbing to manage ratings yourself. You can use Liferay's Ratings API and services to record ratings for Player, John Snow, in the Ratings tables and then you can use the Ratings taglibs to render them in your portlet. AND! like I mentioned above, this pattern can repeat itself for other features like comments, subscriptions, asset entries etc. So it's a way to genericize meta data about your entity but store it in a central table so that you don't end up with a Ratings_Blogs table and a Ratings_Journal_Article table and a Ratings_Player table etc.
Make sense?
Sorry for the very late answer but i ve been making my brain over work on that problem ... ;)
So yes it definitly make sense ! but i guess that's not what i meaned in my question (My english is surely bad i m French
), i have the entity in asset Entry and my search portlet is finding it. Let me explain you :
Let's take an Ads entity. I create my ad throx my portlet, my elasticsearc hindex it correctly and the assetEntity Table is updated. Until there everything look fine. But when i instanciate an AssetPublisher portlet, i can't see my entity, so i decided to filter in the configuration. I seletco only my custom Ads entity (yes it appear in the configuration).I got a "No values found" in the AssetPublisher Portlet.
You wil lsay, "Your entity is just not indexed correctly or not seted up as an asset follow the docs" wich would be totaly correct. But there it start to get weird. If i write the name of my Ads i just created in the global search, i will see Ads (1) in the Typpe select on the right, and other normal searchable Stuffs, but still thet "No Values found" in the result.
I have no error, i have setted up a render and rendereFactory for my both entities. I also created a JSP, i trieds to follow the old 6.2 tutorial too with the EntityAsset working with my custo mentity asset. Nothing is working ! To be honest i can't find any clue of where is the rerror coming from ...
So yes it definitly make sense ! but i guess that's not what i meaned in my question (My english is surely bad i m French

Let's take an Ads entity. I create my ad throx my portlet, my elasticsearc hindex it correctly and the assetEntity Table is updated. Until there everything look fine. But when i instanciate an AssetPublisher portlet, i can't see my entity, so i decided to filter in the configuration. I seletco only my custom Ads entity (yes it appear in the configuration).I got a "No values found" in the AssetPublisher Portlet.
You wil lsay, "Your entity is just not indexed correctly or not seted up as an asset follow the docs" wich would be totaly correct. But there it start to get weird. If i write the name of my Ads i just created in the global search, i will see Ads (1) in the Typpe select on the right, and other normal searchable Stuffs, but still thet "No Values found" in the result.
I have no error, i have setted up a render and rendereFactory for my both entities. I also created a JSP, i trieds to follow the old 6.2 tutorial too with the EntityAsset working with my custo mentity asset. Nothing is working ! To be honest i can't find any clue of where is the rerror coming from ...
Hi Dorian,
I speak French, so you could try to explain it in French if you think that will help. I will warn you though that I don't get to use my French very much these days so my replies might be a little bit like your English. Maybe you can write to me in French and I can write to you in English haha
Ok -- it certainly sounds like everything you have is correct. I mean, the AssetFactory, the Renderer and the fact that you have a facet in your search rights showing up with a count for your type means that if much be found. You're referencing the 7.0 Documentation .. so I just want to clarify something. You are dusing a Liferay 7.0 installation, but can you clarify specifically which version?
The next thing I would try would be to remove the search portlet from the equation and try with a custom query. If you create a new MVC Portlet, then in the render method you can try to use something like this --
Or something close to that -- I'm going a bit from memory here. If you then set a breakpoint after the last line above, then you you can inspect the Hits and the SearchContext objects to understand what is being passed to elastic. Just make sure, in your portlet class, to inject a service for the Portal .. or change the references above (_portal) to use PortalUtil instead.
I speak French, so you could try to explain it in French if you think that will help. I will warn you though that I don't get to use my French very much these days so my replies might be a little bit like your English. Maybe you can write to me in French and I can write to you in English haha

Ok -- it certainly sounds like everything you have is correct. I mean, the AssetFactory, the Renderer and the fact that you have a facet in your search rights showing up with a count for your type means that if much be found. You're referencing the 7.0 Documentation .. so I just want to clarify something. You are dusing a Liferay 7.0 installation, but can you clarify specifically which version?
The next thing I would try would be to remove the search portlet from the equation and try with a custom query. If you create a new MVC Portlet, then in the render method you can try to use something like this --
long companyId = _portal.getCompanyId(portletRequest);
long groupId = _portal.getScopeGroupId(portletRequest);
// build the basic object
HttpServletRequest request = _portal.getHttpServletRequest(portletRequest);
HttpServletRequest originalRequest = _portal.getOriginalServletRequest(request);
SearchContext searchContext = SearchContextFactory.getInstance(request);
searchContext.setEntryClassNames(new String[]{Ads.class.getName()});
searchContext.setStart(0);
searchContext.setEnd(10);
Indexer indexer = IndexerRegistryUtil.nullSafeIndexer(Ads.class.getName());
Hits hits = indexer.search(searchContext);
Or something close to that -- I'm going a bit from memory here. If you then set a breakpoint after the last line above, then you you can inspect the Hits and the SearchContext objects to understand what is being passed to elastic. Just make sure, in your portlet class, to inject a service for the Portal .. or change the references above (_portal) to use PortalUtil instead.
@Reference
private Portal _portal;
.. also, are you able to share the code for your indexer class with us?
Hey thanks for your answer !
I m running on Liferay CE 7.1.1-ga2, using a Service Builder and React portlets. I will try what you said, I add my indexer as attachment.
I m running on Liferay CE 7.1.1-ga2, using a Service Builder and React portlets. I will try what you said, I add my indexer as attachment.
Attachments:
Great -- and just one more clarification. Starting in 7.1, there were actually two different search portlet options. There was the "legacy one" for lack of a better name which, whne added to a page, was one portlet that had the results, the facets, etc. There is also a "new set of search portlets" that allows you to add individual facets, results, search bar, etc.
I am assuming you are using the new one, but just wanted to double check. Is my assumption correct?
EDIT: Another question. You mentioned that you created the Asset Renderer for this custom entity as well right? When you add an AssetPublisher widget to a page and configure it to show your custom asset, do the entries show up?
I am assuming you are using the new one, but just wanted to double check. Is my assumption correct?
EDIT: Another question. You mentioned that you created the Asset Renderer for this custom entity as well right? When you add an AssetPublisher widget to a page and configure it to show your custom asset, do the entries show up?
I m using the default one, i will show u a screenshot of what i get
Attachments:
Ok, yeah, that is the new one. That's good to know -- makes testing a little more relevant (since I can make sure to try with the same one haha).
What about the asset publisher? Does it render your custom items? I ask because I have seen occasion in the past where the search was actually returning items (hence the facet count you are seeing) BUT, the Asset Renderer was not working and so the result was not rendering.
What about the asset publisher? Does it render your custom items? I ask because I have seen occasion in the past where the search was actually returning items (hence the facet count you are seeing) BUT, the Asset Renderer was not working and so the result was not rendering.
In the asset Publisher I can select the PetitesAnnonces entity, but i can't see any item in the portlet. Attachments again ^^ On the assetPublisher portlet you can see the portlet on the right with two entities, and the asset on the left.
Attachments:
Ok, in that case I would focus my attention on the asset renderer. Two questions.
1. Are there any errors in the log? (I do recall having this issue and I think it was silently gobbled up, but I can't say for sure)
2. If you set a breakpoint in your asset renderer.. does it hit?
1. Are there any errors in the log? (I do recall having this issue and I think it was silently gobbled up, but I can't say for sure)
2. If you set a breakpoint in your asset renderer.. does it hit?
I think that's where it's coming from. I will send u my two renderer class. Unfortunatly i have no error ! on the asset publisher portlet and on the search portlet no error. The renderer breakpoints don't hit either, the constructor only hit when i start my serveur.
Alright, progress! 
I wish I could remember what I did to solve this problem when I had it, but it was about a year and a half ago and I can barely remember what I had for dinner last night, sooooo. I'm going to check with a former coworker of mine shortly to see if she remembers what it was. In the mean time can you do the usual stuff of checking to make sure you factory service is resolved and active in the Gogo shell?
scr:info agiir.bd.serviceBuilder.assets.PetitesAnnoncesAssetRendererFactory
.. it's probably fine, but just to eliminate another possibility. And one more thing to try while you are waiting for me to ask my former co-worker, can you change the getJspPath method implementation in the asset renderer class to use
public String getJspPath(HttpServletRequest request, String template)
{
return "/asset/summary.jsp";
}
which I believe will use the "summary.jsp" from the asset renderer portlet that Liferay ships with.

I wish I could remember what I did to solve this problem when I had it, but it was about a year and a half ago and I can barely remember what I had for dinner last night, sooooo. I'm going to check with a former coworker of mine shortly to see if she remembers what it was. In the mean time can you do the usual stuff of checking to make sure you factory service is resolved and active in the Gogo shell?
scr:info agiir.bd.serviceBuilder.assets.PetitesAnnoncesAssetRendererFactory
.. it's probably fine, but just to eliminate another possibility. And one more thing to try while you are waiting for me to ask my former co-worker, can you change the getJspPath method implementation in the asset renderer class to use
public String getJspPath(HttpServletRequest request, String template)
{
return "/asset/summary.jsp";
}
which I believe will use the "summary.jsp" from the asset renderer portlet that Liferay ships with.
Well i tried what you said me and ... Still the same stuff ^^ It's terribly frustrating, when i do scr:info i got my AssetRendererFactory detected as active and working fine. I trie to do some fix i found on other topic in that forum but it's having no effects !
Hey Dorian,
I get it -- and we have all been there I'm sure, and not just with Liferay of course. I am sure that we can find an answer and I am equally sure that when we do find the answer it will be an "OMG! Are you kidding me?!" moment
Ok, last resort, if you are willing to package up the code in a zip and share it with me, then I am happy to build and deploy on my side to troubleshoot a little more effectively. If you don't really want to attach the source here to the message thread (which I understand) maybe you can ping me on slack and we can troubleshoot there -- and report back here when we find the answer.
I get it -- and we have all been there I'm sure, and not just with Liferay of course. I am sure that we can find an answer and I am equally sure that when we do find the answer it will be an "OMG! Are you kidding me?!" moment

Ok, last resort, if you are willing to package up the code in a zip and share it with me, then I am happy to build and deploy on my side to troubleshoot a little more effectively. If you don't really want to attach the source here to the message thread (which I understand) maybe you can ping me on slack and we can troubleshoot there -- and report back here when we find the answer.
Sorry for the late answer. We finally used the indexer directly in the jsp without using Assets. We had to finish it fast ^^ Thanks for your help anyway !
EW. .. just kidding
. I get it, sometimes you have to do what you have to do to get it done and keep the wolves at bay. With that said, if you have a have a technical debt backlog item for this and want to continue to troubleshoot to figure out what the missing piece was, so that one day you can swap out the temporary fix for the better solution, I'm happy to continue to troubleshoot it with you.

Copyright © 2025 Liferay, Inc
• Privacy Policy
Powered by Liferay™