Reflection is the way of examining/modifying runtime the
behaviour of the class at run time.
Reflection make the possibility of inspect the classes,
methods, fields, interfaces without knowing the class names at compile time. We
can also instantiate the class and invoke methods at run time.
Generally application development we can create object
for class that is available in current class path or server class path means
class should be available in the classes directory of your web application or
it should be in web application lib directory or it should be in sever lib directory
then only we can create object and then invoke methods.
Generally In the server we may have deployed different
application and each application is different context and the classes or jar available
in each context not shareable to each other until we place these jar files in
the server lib directory.
Each web application related jar file we cannot place
in server lib directory because until jar file common to all application then it’s
good to place in server lib.
Some time we may have minimal need to invoke the methods
of the class and the class not available in the current application class
loader and it might be available in the other application context.
We
have two ways
We
need make the jar file available to the required application class path or class
loader.
We
can use Reflection API to achieve the requirement.
We
need make the jar file available to the required application class path or class
loader
We just take other application jar file and place into
current application lib directory so that we can instantiate object and invoke methods
but this not recommended for minimal usage and when we change some
implementation in the class again we need update the jar file and place into
the current application lib directory.
Reflection
API
JAVA Reflection API is good way to instantiate and
invoke the methods even though class not available in the current class loader
or current class path.
Liferay
Class Loaders
Liferay we have different class loader.
Liferay
Global Class Loader
Portal
Class Loader.
Portlet
Class Loader
Liferay
Global Class Loader
Liferay Global Class Loader will load the all jar
files and make the classes available to entire Liferay portal and we can use
these classes anywhere like portal development and plugins development.
Generally these jars available in tomacat/lib/ext
path and the important jar is portal-service.jar.
All these classes will be loaded by Liferay Global Class Loader.
Portal
Class Loader
Portal Class loader load all Liferay implementation
classes and these classes available in the portal development and all jars
available in the ROOT/WEB-INF/lib will
be loaded by Portal Class Loader.
Portlet
Class Loader
In Liferay development each plugin portlet have its
own class loader that is portlet class loader and these class loader make the
available to within the portlet and these jars available in PortletName/WEB-INF/lib
In Liferay Portlet development we may have following
scenarios when we develop Liferay Plugins Portlet Development.
Using
the classes in the Liferay Global Lib
Using
Classes in the Portal Class loader
Using
classes which are in other plugin Class Loader.
Using
the classes in the Liferay Global Lib
In the Liferay development we cannot get any issues to
use classes in global class loader and we can instantiate the object and invoke
the methods.
Using
Classes in the Portal Class loader
Portal class loader classes not available to plugin
portlet so in this case we have use reflection API
Using classes which are in other plugin Class Loader.
One plugin portlet classes are not available to other
plugin portlet so we need reflection API.
Note:
When we develop hook plugin, EXT plugins then all
class loaders are available so we don’t get any issues.
Sharing
Service Layer between to Plugin Portlets
Liferay have given way to share service layer between
to plugin portlet so we don’t have any issues in the calling services between
two plugin contexts.
In the dynamic query API we have provision to load
portal class loader classes which are related to service layer using Porta
Class loader and also we have portlet class loader.
If
the scenario which not belongs to above then we will use Reflection API in Liferay
call other class methods which are in different class loaders.
Reflection
API using Portal Level classes
Liferay have implemented the Reflection API and we use
the following util classes to invoke methods which are in different class
loaders
ClassResolverUtil
PortalClassInvoker
PortletClassInvoker
|
Step:
1
We need to create method and here we will specify the
required class, required method to invoke and it parameters types.
If objects then we will use as follows to parameters
types in the reflection
Object
|
Declared
in Reflection Method Key
|
String
|
String.class
|
Long
|
Long.class
|
Student
|
Student.class
|
User
|
User.class
|
Primitive
Types
|
Declared
in Reflection Method Key
|
int
|
Integer.TYPE
|
long
|
Long.TYPE
|
Primitive
array Types
|
Declared
in Reflection Method Key
|
new
long[]{ }
|
long[].class
|
new
int[]{ }
|
int[].class
|
Example
to create method key for portal level class
MethodKey
liveUsersDeleteGroup =
newMethodKey(ClassResolverUtil.resolveByPortalClassLoader(
"com.liferay.portal.liveusers.LiveUsers"),
"deleteGroup",
new Class[] { Long.TYPE, Long.TYPE });
|
MethodKey
leaveGroup = new MethodKey(
ClassResolverUtil
.resolveByPortalClassLoader("com.liferay.portal.liveusers.LiveUsers"),
"leaveGroup",
new Class[] { Long.TYPE, Long.TYPE, long[].class });
|
Method Key need three Parameters i.e. Class
Name with class loader type, Method Name and Type of the parameters as Object
Array
Step:
2
Now we need to invoke the method with passing required
parameter values. We will use invoke method on PortalClassInvoker and it will take method key object and parameter
values as object array. Make sure the order of parameters that we declared in
the MethodKey object creation.
Syntax:
Class:
PortalClassInvoker
Method:
public
static Object invoke(boolean newInstance, MethodKey methodKey, Object...
arguments)
|
Example
Usage
PortalClassInvoker.invoke(true,
liveUsersDeleteGroup, new Object[] {
themeDisplay.getCompanyId(),
deleteGroupId });
|
PortalClassInvoker.invoke(true,
leaveGroup, new Object[] {
themeDisplay.getCompanyId(),
groupId, removeUserIdsLong });
|
If the Original method return some values then we will
get it as Object when we invoke through the Reflection call.
Note:
Parameter types
and order we need to make sure.
Complete
Example:
<%
long
companyId=themeDisplay.getCompanyId();
String
portalLevelClassName="com.liferay.portal.liveusers.LiveUsers";
String
requiredPortalLevelMthodName="getSessionUsers";
Class[]
parameterTypePortalArray={Long.TYPE};
Object[]
valuesPortalArray={companyId};
MethodKey
getSessionUsers = new
MethodKey(ClassResolverUtil.resolveByPortalClassLoader(portalLevelClassName),
requiredPortalLevelMthodName,parameterTypePortalArray);
Object
sessionUsersObject=PortalClassInvoker.invoke(true,getSessionUsers,valuesPortalArray);
out.println("sessionUsersObject:<br/>"+userObject);
%>
|
Reflection
API using Portlet Level classes
Assume we have Plugin PortletA and Plugin
PortletB we want invoke some methods which are in PortletA from PortletB
Portlet Context: PortletA-portlet
Finding
Portlet Context.
Portlet Id: PortletA_WAR_PortletAportlet
Finding
Porttet Id
Go portlet Maximized window state from portlet
configuration
Find
Portlet id from requested URL
We
have implemented some Util class and methods in Plugin PortletA as follows
package
com.meera.portleta.util;
import
com.liferay.portal.kernel.exception.PortalException;
import
com.liferay.portal.kernel.exception.SystemException;
import
com.liferay.portal.model.User;
import
com.liferay.portal.service.UserLocalServiceUtil;
public class
PortletAUtil {
public static
User getUser(long userId) throws
PortalException, SystemException {
return
UserLocalServiceUtil.getUser(userId);
}
public static
String getMessage(String message){
return "Hi
Meera syas" +message;
}
}
|
Now we will invoke PortletA method from PortletB
Step:
1
Create MethodKey Object
MethodKey
getUser = new
MethodKey(ClassResolverUtil.resolveByPortletClassLoader(className,portletContext),
requiredMthodName,parameterTypeArray);
|
Step:
2
Invoke
method using PortletClassInvoker
Syntax
Class:
PortletClassInvoker
Method:
public
static Object invoke(boolean newInstance, String portletId, MethodKey
methodKey,Object... arguments)
|
Example
Code in PortletB JSP page.
<h4>1:PortletB
invoking method which is in Portlet A class Loader Using Reflection</h4>
<%
long
userId=themeDisplay.getUserId();
String
className="com.meera.portleta.util.PortletAUtil";
String
portletContext="PortletA-portlet";
String
requiredMthodName="getUser";
Class[]
parameterTypeArray={Long.TYPE};
Object[]
valuesArray={userId};
String
portletId="PortletA_WAR_PortletAportlet";
MethodKey
getUser = new
MethodKey(ClassResolverUtil.resolveByPortletClassLoader(className,portletContext),
requiredMthodName,parameterTypeArray);
Object
userObject=PortletClassInvoker.invoke(true,portletId,getUser,valuesArray);
out.println("userObject:<br/>"+userObject);
%>
|
Note:
In the above example we implemented method in the PortletA
plugin context and we are invoking in PortletB JSP page.
Complete
Code Example Calling Methods from Portal and Portlet Level class loader classes.
View.jsp
in PortletB
<%@page import="com.liferay.portal.kernel.util.PortalClassInvoker"%>
<%@page import="com.liferay.portal.kernel.util.PortletClassInvoker"%>
<%@page import="com.liferay.portal.kernel.util.ClassResolverUtil"%>
<%@page import="com.liferay.portal.kernel.util.MethodKey"%>
<%@page import="java.util.Map"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0"
prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui"
prefix="aui" %>
<%@taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %>
<%@taglib uri="http://liferay.com/tld/security" prefix="liferay-security" %>
<%@taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<%@taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%@taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
<portlet:defineObjects />
<liferay-theme:defineObjects
/>
<h4>1:PortletB
invoking method which is in Portlet A class Loader Using Reflection</h4>
<%
long
userId=themeDisplay.getUserId();
String
className="com.meera.portleta.util.PortletAUtil";
String
portletContext="PortletA-portlet";
String
requiredMthodName="getUser";
Class[]
parameterTypeArray={Long.TYPE};
Object[]
valuesArray={userId};
String
portletId="PortletA_WAR_PortletAportlet";
MethodKey
getUser =
new
MethodKey(ClassResolverUtil.resolveByPortletClassLoader(className,portletContext),
requiredMthodName,parameterTypeArray);
Object
userObject=PortletClassInvoker.invoke(true,portletId,getUser,valuesArray);
out.println("userObject:<br/>"+userObject);
%>
<h4>2:PortletB
invoking method which is in Portal class Loader Using Reflection</h4>
<%
long
companyId=themeDisplay.getCompanyId();
String
portalLevelClassName="com.liferay.portal.liveusers.LiveUsers";
String
requiredPortalLevelMthodName="getSessionUsers";
Class[]
parameterTypePortalArray={Long.TYPE};
Object[]
valuesPortalArray={companyId};
MethodKey
getSessionUsers =
new MethodKey(ClassResolverUtil.resolveByPortalClassLoader(portalLevelClassName),
requiredPortalLevelMthodName,parameterTypePortalArray);
Object sessionUsersObject=PortalClassInvoker.invoke(true,getSessionUsers,valuesPortalArray);
out.println("sessionUsersObject:<br/>"+userObject);
%>
|
Download
Liferay Reflection Example
Usage
of Portlets
Download Liferay Reflection Example from above link you
can find war files and source code you can directly place war files in portlet
deploy directory then it will be deployed.
Now drag and drop PortletB in the page then you can
see sample output.
Note:
Portlet have developed in Liferay 6.2 CE GA4
so based on your version you can build it from source that I have given.
PortletB
View shows Example out put
Author