I have this next class:
#Service
public class BusinessService {
#Autowired
private RedisService redisService;
private void count() {
String redisKey = "MyKey";
AtomicInteger counter = null;
if (!redisService.isExist(redisKey))
counter = new AtomicInteger(0);
else
counter = redisService.get(redisKey, AtomicInteger.class);
try {
counter.incrementAndGet();
redisService.set(redisKey, counter, false);
logger.info(String.format("Counter incremented by one. Current counter = %s", counter.get()));
} catch (JsonProcessingException e) {
logger.severe(String.format("Failed to increment counter."));
}
}
// Remaining code
}
and this this my RedisService.java class
#Service
public class RedisService {
private Logger logger = LoggerFactory.getLogger(RedisService.class);
#Autowired
private RedisConfig redisConfig;
#PostConstruct
public void postConstruct() {
try {
String redisURL = redisConfig.getUrl();
logger.info("Connecting to Redis at " + redisURL);
syncCommands = RedisClient.create(redisURL).connect().sync();
} catch (Exception e) {
logger.error("Exception connecting to Redis: " + e.getMessage(), e);
}
}
public boolean isExist(String redisKey) {
return syncCommands.exists(new String[] { redisKey }) == 1 ? true : false;
}
public <T extends Serializable> void set(String key, T object, boolean convertObjectToJson) throws JsonProcessingException {
if (convertObjectToJson)
syncCommands.set(key, writeValueAsString(object));
else
syncCommands.set(key, String.valueOf(object));
}
// Remaining code
}
and this is my test class
#Mock
private RedisService redisService;
#Spy
#InjectMocks
BusinessService businessService = new BusinessService();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void myTest() throws Exception {
for (int i = 0; i < 50; i++)
Whitebox.invokeMethod(businessService, "count");
// Remaining code
}
my problem is the counter always equals to one in logs when running tests
Counter incremented by one. Current counter = 1(printed 50 times)
and it should print:
Counter incremented by one. Current counter = 1
Counter incremented by one. Current counter = 2
...
...
Counter incremented by one. Current counter = 50
this means the Redis mock always passed as a new instance to BusinessService in each method call inside each loop, so how I can force this behavior to become only one instance used always for Redis inside the test method ??
Note: Above code is just a sample to explain my problem, but it's not a complete code.
Your conclusion that a new RedisService is somehow created in each iteration is wrong.
The problem is that it is a mock object for which you haven’t set any behaviours, so it responds with default values for each method call (null for objects, false for bools, 0 for ints etc).
You need to use Mockito.when to set behaviour on your mocks.
There is some additional complexity caused by the fact that:
you run the loop multiple times, and behaviour of the mocks differ between first and subsequent iterations
you create cached object in method under test. I used doAnswer to capture it.
You need to use doAnswer().when() instead of when().thenAnswer as set method returns void
and finally, atomicInt variable is modified from within the lambda. I made it a field of the class.
As the atomicInt is modified each time, I again used thenAnswer instead of thenReturn for get method.
class BusinessServiceTest {
#Mock
private RedisService redisService;
#InjectMocks
BusinessService businessService = new BusinessService();
AtomicInteger atomicInt = null;
#BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void myTest() throws Exception {
// given
Mockito.when(redisService.isExist("MyKey"))
.thenReturn(false)
.thenReturn(true);
Mockito.doAnswer((Answer<Void>) invocation -> {
atomicInt = invocation.getArgument(1);
return null;
}).when(redisService).set(eq("MyKey"), any(AtomicInteger.class), eq(false));
Mockito.when(redisService.get("MyKey", AtomicInteger.class))
.thenAnswer(invocation -> atomicInt);
// when
for (int i = 0; i < 50; i++) {
Whitebox.invokeMethod(businessService, "count");
}
// Remaining code
}
}
Having said that, I still find your code questionable.
You store AtomicInteger in Redis cache (by serializing it to String). This class is designed to be used by multiple threads in a process, and the threads using it the same counter need to share the same instance. By serializing it and deserializing on get, you are getting multiple instances of the (conceptually) same counter, which, to my eyes, looks like a bug.
smaller issue: You shouldn't normally test private methods
2 small ones: there is no need to instantiate the field annotated with #InjectMocks. You don't need #Spy as well.
I'm would like to use MOXy to marshal / unmarshal object from existing classes.
I would like to know if there is a mean to generate XML binding files (cause I don't want to use annotations) from my classes.
Or do we have to do it all with our little hands :) ?
By default JAXB/MOXy doesn't require any metadata to be specified (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html). You only need to specify the metadata where you want to override the default behaviour.
I'm guessing your real question is what is the easiest way to create the MOXy external mapping document. I do the following with Eclipse, there are probably similar steps for your favourite IDE:
Get the XML Schema for MOXy's mapping document
<EclipseLink_Home>/xsds/eclipselink_oxm_2_5.xsd
Register the XML Schema with your IDE
Eclipse | Preferences | XML | XML Catalog | Add
Create and XML document in the IDE and specify the following as the root element.
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"/>
Use the auto-complete functionality offered by your IDE to construct the XML document.
Another option is to generate jaxb classes and from those read the bindings (annotations) producing an external mapping (after which you can remove the annotations). PoC code:
public class MoxyBindingGenerator {
private static final String PACKAGE = "com.company.binding.jaxbclasses";
private static ObjectFactory xmlBindingsFactory = new ObjectFactory();
public static void main(String[] args) throws Exception {
Collection<TypeInfo> typeInfos = readAnnotations();
XmlBindings xmlBindings = xmlBindingsFactory.createXmlBindings();
xmlBindings.setPackageName(PACKAGE);
JavaTypes javaTypes = xmlBindingsFactory.createXmlBindingsJavaTypes();
xmlBindings.setJavaTypes(javaTypes);
List<JavaType> javaTypesList = javaTypes.getJavaType();
XmlEnums xmlEnums = xmlBindingsFactory.createXmlBindingsXmlEnums();
xmlBindings.setXmlEnums(xmlEnums);
List<XmlEnum> xmlEnumsList = xmlEnums.getXmlEnum();
typeInfos.stream().forEach(typeInfo -> {
if (!typeInfo.isEnumerationType()) {
fillJavaTypes(javaTypesList, typeInfo);
}
else {
fillEnumTypes(xmlEnumsList, typeInfo);
}
});
saveToFile(xmlBindings);
}
private static Collection<TypeInfo> readAnnotations() throws JAXBException, Exception {
JAXBContext jaxbContext = (JAXBContext) javax.xml.bind.JAXBContext.newInstance(PACKAGE);
Object contextState = getPrivateField(jaxbContext, "contextState");
Generator generator = (Generator) getPrivateField(contextState, "generator");
AnnotationsProcessor annotationsProcessor = generator.getAnnotationsProcessor();
Collection<TypeInfo> typeInfos = annotationsProcessor.getTypeInfo().values();
return typeInfos;
}
private static void fillEnumTypes(List<XmlEnum> xmlEnumsList, TypeInfo typeInfo) {
EnumTypeInfo et = (EnumTypeInfo) typeInfo;
XmlEnum xmlEnum = xmlBindingsFactory.createXmlEnum();
xmlEnum.setJavaEnum(et.getJavaClassName());
List<String> xmlEnumNames = et.getFieldNames();
List<Object> xmlEnumValues = et.getXmlEnumValues();
for (int i = 0; i < xmlEnumNames.size(); i++) {
String xmlEnumName = xmlEnumNames.get(i);
Object xmlEnumObject = xmlEnumValues.get(i);
XmlEnumValue xmlEnumValue = xmlBindingsFactory.createXmlEnumValue();
xmlEnumValue.setJavaEnumValue(xmlEnumName);
xmlEnumValue.setValue(xmlEnumObject.toString());
xmlEnum.getXmlEnumValue().add(xmlEnumValue);
}
xmlEnumsList.add(xmlEnum);
}
private static void fillJavaTypes(List<JavaType> javaTypesList, TypeInfo typeInfo) {
JavaType javaType = xmlBindingsFactory.createJavaType();
javaType.setName(typeInfo.getJavaClassName());
fillXmlType(javaType, typeInfo);
if (typeInfo.getXmlRootElement() != null) {
XmlRootElement xmlRootElement = typeInfo.getXmlRootElement();
xmlRootElement.setNamespace(null);
javaType.setXmlRootElement(xmlRootElement);
}
JavaAttributes javaAttributes = xmlBindingsFactory.createJavaTypeJavaAttributes();
javaType.setJavaAttributes(javaAttributes);
List<JAXBElement<? extends JavaAttribute>> javaAttributeList = javaAttributes.getJavaAttribute();
typeInfo.getNonTransientPropertiesInPropOrder().stream().forEach(field -> {
fillFields(javaAttributeList, field);
});
javaTypesList.add(javaType);
}
private static void fillFields(List<JAXBElement<? extends JavaAttribute>> javaAttributeList, Property field) {
if (field.getXmlElements() != null && field.getXmlElements().getXmlElement().size() > 0) {
XmlElements xmlElements = xmlBindingsFactory.createXmlElements();
xmlElements.setJavaAttribute(field.getPropertyName());
List<XmlElement> elements = field.getXmlElements().getXmlElement();
elements.stream().forEach(e -> {
e.setDefaultValue(null);
e.setNamespace(null);
xmlElements.getXmlElement().add(e);
});
JAXBElement<XmlElements> value = xmlBindingsFactory.createXmlElements(xmlElements);
javaAttributeList.add(value);
}
else if (!field.isAttribute()) {
XmlElement value = xmlBindingsFactory.createXmlElement();
value.setJavaAttribute(field.getPropertyName());
value.setName(field.getSchemaName().getLocalPart());
if (field.isNillable())
value.setNillable(field.isNillable());
if (field.isRequired())
value.setRequired(field.isRequired());
javaAttributeList.add(xmlBindingsFactory.createXmlElement(value));
}
else {
XmlAttribute value = xmlBindingsFactory.createXmlAttribute();
value.setJavaAttribute(field.getPropertyName());
value.setName(field.getSchemaName().getLocalPart());
javaAttributeList.add(xmlBindingsFactory.createXmlAttribute(value));
}
}
private static void saveToFile(XmlBindings xmlBindings)
throws JAXBException, PropertyException, FileNotFoundException, IOException {
JAXBContext xmlModelJaxbContext =
(JAXBContext) javax.xml.bind.JAXBContext.newInstance("org.eclipse.persistence.jaxb.xmlmodel");
JAXBMarshaller marshaller = xmlModelJaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
FileOutputStream fos = new FileOutputStream(new File(System.getProperty("user.home"), "binding-imspoor-oxm.xml"));
marshaller.marshal(xmlBindings, fos);
fos.close();
}
private static void fillXmlType(JavaType javaType, TypeInfo typeInfo) {
XmlType orgXmlType = typeInfo.getXmlType();
if (orgXmlType != null) {
boolean add = false;
XmlType xmlType = xmlBindingsFactory.createXmlType();
if (!StringUtils.isEmpty(orgXmlType.getName())) {
xmlType.setName(orgXmlType.getName());
add = true;
}
if (orgXmlType.getPropOrder() != null && orgXmlType.getPropOrder().size() > 1) {
xmlType.getPropOrder().addAll(orgXmlType.getPropOrder());
add = true;
}
if (add)
javaType.setXmlType(xmlType);
}
}
private static Object getPrivateField(Object obj, String fieldName) throws Exception {
Field declaredField = obj.getClass().getDeclaredField(fieldName);
declaredField.setAccessible(true);
return declaredField.get(obj);
}
}
I have
public class ExtendedBeanELResolver extends BeanELResolver {
private static final Pattern regExpDn = Pattern.compile("PLMN-PLMN/\\w+.\\d+(.*)");
#Override
public Object getValue(ELContext context, Object base, Object property)
try {
// remake DIST.NAME appearance
if (property.equals("dn") && base instanceof Alarm && ((Alarm) base).getCustomer().getNameEng().equalsIgnoreCase("mts")) {
String dn = null;
try {
dn = ((Alarm) base).getDn();
Matcher mtch = regExpDn.matcher(dn);
mtch.find();
((Alarm) base).setDn(mtch.group(1));
} catch (Throwable e) {
// logger.error("error in dn - " + dn);
} finally {
return super.getValue(context, base, property);
}
}
}
for change some visible values in object depending on some conditions. I do not want to change value if this called from jsf <ui:param name="fullDistName" value="#{alarm.dn}" />
How i can get id of component from which this EL called?
sorry for my english.
You can get the current JSF component by programmatically evaluating #{component} or by invoking UIComponent#getCurrentComponent().
UIComponent component = UIComponent.getCurrentComponent(FacesContext.getCurrentInstance();
// ...
Please note that this tight-couples your EL resolver to JSF.
The source code:
public class ReportGenerator implements Serializable {
private static final long serialVersionUID = -3995091296520157208L;
#Inject
private ReportCacheSession reportCacheSession;
#Inject
private UserSessionBean userSessionBean;
#Inject
private Instance<ReportBuilder> reportBuilderInstance;
public static final int BUILD_ERROR = 0;
public static final int BUILD_OK = 1;
public static final int BUILD_NOPAGES = 2;
private ReportBuilder reportBuilder = null;
private FileData build(String jasperName, Map<String, Object> params, String extension, boolean guardarCache, boolean inline) {
FileData fd = null;
reportBuilder = reportBuilderInstance.get();
if (reportBuilder != null) {
reportBuilder.jasperName = jasperName;
reportBuilder.emailName = SevUtils.getEmailName(userSessionBean.getUserInfo().getEmail());
reportBuilder.sessionId = JSFUtils.getSessionId();
reportBuilder.params = params;
reportBuilder.extension = extension;
//reportBuilder.config(jasperName, SevUtils.getEmailName(userSessionBean.getUserInfo().getEmail()), JSFUtils.getSessionId(), params, extension);
reportBuilder.start();
try {
reportBuilder.join();
} catch (InterruptedException ex) {
Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
fd = reportBuilder.getFileData();
}
if (fd != null && fd.getState() == BUILD_OK) {
fd.setInline(inline);
if (guardarCache) {
reportCacheSession.addReport(fd);
}
}
return fd;
}
}
reportBuilder.start(); is a new Thread to generate the report(s), the problem is when the line reportCacheSession.addReport(fd); is called CDI create a new instance each time, but ReportCacheSession is a session bean annotated with javax.inject.Named and javax.enterprise.context.SessionScoped.
I don't know why this happens, but my solution is add a new line, like this:
FileData fd = null;
reportCacheSession.toString(); //NEW LINE
reportBuilder = reportBuilderInstance.get();
reportCacheSession.toString(); create the instance of ReportCacheSession before my thread is called and all works OK...
How the new thread affects to CDI? Why CDI created a new instance of my session bean when I called the thread before?
UPDATE 08/15/12:
Ok, I have changed my code to use the EJB annotation #Asynchronous, in this case I have problem when I'm generating a large PDF report (the XLS report works without problem), the file's size is incomplete(less bytes) and when I try to open it this appear in blank... Maybe a problem/bug with JRExporter#exportReport method...
LAST UPDATE:
Ok, the report generation was my mistake... the question is which alternative is best to use EJB Asynchronous or JMS? Thanks to all, each comment have led me to find a good solution...
I need to use function with argument in a EL expression (with JSF) like this:
<h:outputText value="#{object.test(10)}" ></h:outputText>
But it doesn't work.
I read on the web that it's impossible to do this with JSF. I use facelet with JSF.
Someone knows how to do that ?
Thanks.
You could provide the method as a custom facelet function in your own taglib. The method must be static, so if you are trying to call a method on a specific bean, you would have to pass the bean, and the parameters to your static facelet function. In your case, it would be something like
<h:outputText value="#{my:doStuff(object,10)}" ></h:outputText>
and your facelet function would be
public static String doStuff( MyType o, int param )
{
return o.test( param );
}
Then, using the information in the facelets docbook you would define your function in your taglib.xml file.
It's not the prettiest solution, especially if you plan on doing this a lot, but I believe the next version of the EL (in java EE 6) will allow for using parameters in some cases.
Edit: Some info about parameterized method calls in the next version of el can be found on Ryan Lubke's Blog
I find a sad solution but it's working. I overload a map like this:
new AbstractMap<Integer, String>()
{
#Override
public Set<Entry<Integer, String>> entrySet()
{
return null;
}
#Override
public String get(final Object arg0)
{
Integer keywordDb = (Integer)arg0;
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
HashMap<String, String> params = new HashMap<String, String>();
params.put("keywordDb", keywordDb.toString());
params.put("month", new Integer(cal.get(Calendar.MONTH) + 1).toString());
params.put("year", new Integer(cal.get(Calendar.YEAR)).toString());
DataAnalyzeManager manager = new DataAnalyzeManager();
manager.setEm(modelPosition.getEm());
DataAnalyze data = manager.findDataByParams(params, modelPosition.getSite(), false, DataAnalyzeManager.VISITBYMONTHBYKEYWORD);
if (data != null)
return data.getDataInt().toString();
return "0";
}
};
Thereby, I can do that in my JSF:
#{homePositionController.visitByMonth[keyword.keyword.keywordDb]}
And my function is executed.
You may have to have <%# page isELIgnored ="false" %>
at the top of your pages. Read more here. The default is to ignore el expressions. What version of the JSP spec are you using with JSF? If you are using JSF 2 with JSP < 2.1 you are going to run into problems.
Also, what version of el are you using? You can't pass method params with older versions.
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>2.1.2-b05</version>
</dependency>
There is couple ways about doing that, you could use JBoss EL expression implementation they support method calls with parameters check out Seam, or use similar approach as #digitaljoel suggested.
This is what I created for that purpose, you can call static and static methods, not a great solution but it does the job.
<c:if test="#{t:call(null, '#Util.SecurityUtility', 'isPanelWorkbookEnabledForUser','')}">
Hello Panel
</c:if>
#Util is just an alias to com.mycomp.util where
Example 2
<c:if test="#{item != null and t:call(item, 'java.lang.String', 'indexOf', t:params(t:param('flash-alert',''))) == 0}">
#{t:call(session, 'org.apache.catalina.session.StandardSessionFacade', 'removeAttribute', t:params(t:param(item,'')))}
</c:if>
Syxtax
java.lang.Object call(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object[])
Where Object is object we want to invoke method on, String is the method name, Object[] are parameters to pass.
t:call, t:params, t:param are function defined in project-taglib.xml as so
<function>
<function-name>call</function-name>
<function-class>util.Functions</function-class>
<function-signature>java.lang.Object call(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object[])</function-signature>
</function>
<function>
<function-name>param</function-name>
<function-class>.util.Functions</function-class>
<function-signature>java.lang.String param(java.lang.Object, java.lang.String)</function-signature>
</function>
<function>
<function-name>params</function-name>
<function-class>util.Functions</function-class>
<function-signature>java.lang.Object[] params(java.lang.String)</function-signature>
</function>
Here is the implementation
package mycompany.web.util;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import javax.el.MethodNotFoundException;
public class Functions {
private static HashMap<String, String> alliasMap;
static{
alliasMap=new HashMap<String, String>();
alliasMap.put("#DateUtil", "com.americanbanksystems.compliance.util.DateUtil");
//Match anything following the dot(.)
alliasMap.put("#Util.*", "com.americanbanksystems.compliance.util");
alliasMap.put("#Application.*", "com.americanbanksystems.compliance.application");
}
public static String param(Object obj, String cls) {
//make sure that passed in object is not null
if(obj==null){
obj="";
}
ByteArrayOutputStream baut=new ByteArrayOutputStream();
XMLEncoder encoder=new XMLEncoder( baut );
//Bug in the JDK
//http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=c993c9a3160fd7de44075a2a1fa?bug_id=6525396
if(obj instanceof java.sql.Timestamp){
Date o = new Date(((java.sql.Timestamp)obj).getTime());
obj=o;
}
//Checking if this is possible
if(String.class.isAssignableFrom(obj.getClass())){
//removed trailing +" " because it was causing indexOf return invalid value
//Unknown side effects
obj=FacesUtil.get(obj.toString());
}
encoder.writeObject( obj );
encoder.close();
return new String(baut.toByteArray());
}
private static Object decode(String str){
ByteArrayInputStream bais=new ByteArrayInputStream(str.getBytes());
XMLDecoder decoder=new XMLDecoder(bais);
return decoder.readObject();
}
public static Object[] params(String str){
// (?<=</java>)\s*(?=<?)
String[] obj=str.split("(?<=</java>)\\s*(?=<?)");
Object[] results=new Object[obj.length];
for(int i=0;i<obj.length;i++){
results[i]=decode(obj[i]);
}
return results;
}
#SuppressWarnings("unchecked")
public static Object call(Object owningObject, String qualifiedClassname, String methodName, java.lang.Object... methodArguments) {
if (null == methodName || methodName.equals("")) {
throw new IllegalArgumentException("Method name can't be null or empty");
}
if (null == methodArguments) {
methodArguments = new Object[0];
}
//Check for aliases
if(qualifiedClassname.indexOf("#")>-1){
String subpackage=qualifiedClassname;
String originalClass=qualifiedClassname;
//Split at the dot
boolean isPackageAllias=false;
String[] sp=subpackage.split("\\.");
if(sp.length>1){
subpackage=sp[0]+".*";
isPackageAllias=true;
}
if(alliasMap.containsKey(subpackage)){
String value = alliasMap.get(subpackage);
if(isPackageAllias){
qualifiedClassname=subpackage.replace(sp[0], value);
qualifiedClassname=qualifiedClassname.replace(".*", originalClass.replace(sp[0],""));
}else{
qualifiedClassname=value;
}
}else{
throw new IllegalArgumentException("Allias name '"+qualifiedClassname+"' not found");
}
}
Class clazz;
try {
clazz = Class.forName(qualifiedClassname);
//Find method by methodName,Argument Types
Class[] argumentTypes=new Class[methodArguments.length];
for(int i=0;i<methodArguments.length;i++){
argumentTypes[i]=methodArguments[i].getClass();
//Check if the passed in method argument is a string and if its represented as unicode char
//if it is then convert it into a char and reassign to the original parameter
//example 1: \u0022 == "
//example 2: \u0027 == '
// Reason for this functionality is that we can't pass " and ' from within t:call method
if (argumentTypes[i] == String.class && methodArguments[i].toString().indexOf("\\u") > -1) {
String arg = methodArguments[i].toString();
arg = arg.substring(2, arg.length());
try {
int outchar = Integer.parseInt(arg, 16);
if (Character.isDefined(outchar)) {
methodArguments[i] = String.valueOf((char) outchar);
}
} catch (NumberFormatException nfe) {
// Suppress error and continue assuming this is a regular string
}
}
}
Method methodToInvoke = null;
try{
methodToInvoke = clazz.getMethod(methodName, argumentTypes);
}catch(NoSuchMethodException nsm){//Find by method name/ argument count
for (Method method : clazz.getMethods()) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == methodArguments.length) {
if (null == owningObject) {
owningObject = clazz.newInstance();
}
methodToInvoke=method;
break;
}
}
}
if(methodToInvoke!=null){
return methodToInvoke.invoke(owningObject, methodArguments);
}else{
throw new InstantiationException("method not found :" + methodName);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] arg) {
// StringBuffer buff=new StringBuffer();
// buff.append("Gregs init");
// Functions.call(java.lang.Class<T>, T, java.lang.String, java.lang.String, java.lang.Object...)
/*
* Functions.call(StringBuffer.class, buff, "java.lang.StringBuffer","append"," Init ");
* Functions.call(StringBuffer.class, buff, "java.lang.StringBuffer","append"," greg ");
* System.out.println("output="+ buff);
*/
//#{t:call(null, ".util.DateUtil", "normalizeDate", t:parametize(editRiskActionPlan.riskActionPlan.completionDate,",","java.lang.Object"))}
// c(call(null, "util.DateUtil", "normalizeDate", new Date()));
// #{t:parametize(editRiskActionPlan.riskActionPlan.completionDate,",","java.lang.Object")}
//parametize((new Date()).toString(),",","java.lang.Object");
Date a=new Date();
Date b=new Date();
String rawString=param((Date)b, Date.class.toString() );
//System.out.println(rawString);
//Replaced=#{t:call("Gregs ' car", 'java.lang.String', 'replace', t:params( parameter ))}
String paramA=param("\\u0027","");
String paramB=param("\\u0022","");
String params=paramA+paramB;
String in="I need to ' have a replaced single quote with double";
String out=(String)call(in, "java.lang.String", "replace", params(params));
System.out.println(out);
/*
Object[] obj=params(rawString);
for(Object o:obj){
System.out.println(o);
}
//c(call(null, "#DateUtil", "normalizeDate", obj));
*/
}
}
I hope this helps, btw this was copied/pasted from my project so not sure if I missed anything.