Grails request parameter type conversion - grails

In my Grails app, I need to bind a request parameter to a Date field of a command object. In order to perform the String-to-Date conversion, one needs to register an appropriate PropertyEditor in grails-app\conf\spring\resources.groovy
I've added the following bean definiton:
import org.springframework.beans.propertyeditors.CustomDateEditor
import java.text.SimpleDateFormat
beans = {
paramDateEditor(CustomDateEditor, new SimpleDateFormat("dd/MM/yy"), true) {}
}
But I'm still getting an error:
java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "04/01/99"]
I think there's probably just something wrong with the way I've defined the bean, but I've no idea what?

The piece you are missing is registering of the new property editor. The following worked for me when I upgraded to Grails 1.1 and had to bind dates in the MM/dd/yyyy format.
grails-app/config/spring/resources.groovy:
beans = {
customPropertyEditorRegistrar(util.CustomPropertyEditorRegistrar)
}
src/groovy/util/CustomPropertyEditorRegistrar.groovy:
package util
import java.util.Date
import java.text.SimpleDateFormat
import org.springframework.beans.propertyeditors.CustomDateEditor
import org.springframework.beans.PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistry
public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("dd/MM/yy"), true));
}
}

Related

Cannot import package in unit tests for a Jenkins Shared Library

I'm attempting to create unit tests for a JenkinsShared library using Gradle in order to run the test tasks.
I've followed this tutorial which upon conclusion one has a working test suite for a shared library for functions within the vars folder (with the unit tests in src/test/groovy/*Test.groovy).
However, in our internal shared jenkins library we followed a more object oriented style and isolated functionality into a package of classes in the format: src/org/company/*.groovy.
The problem arises when attempting to import said package into a unit test class. In the tutorial, the functions are imported using the loadScript method this method fails when loading a class which is dependent on another file.
Take the class:
package tests
import org.junit.*
import com.lesfurets.jenkins.unit.*
import static groovy.test.GroovyAssert.*
import org.company.UtilFactory
class UtilFactoryTest extends BasePipelineTest {
#Test
void testCall() {
def util = UtilFactory.getUtil("hello")
assertEquals true, true
}
}
src/org/company/UtilFactory.groovy
package org.company
class UtilFactory implements Serializable {
static Util instance
static Util getUtil(script=null) {
if (!(UtilFactory.instance)) {
if (!script) {
// Throws an exception if on the first call to getUtil the
// script parameter is null.
throw new ScriptUndefinedException("script parameter null on initial call to getUtil")
}
UtilFactory.instance = new Util(script)
}
return UtilFactory.instance
}
}
class ScriptUndefinedException extends Exception {
// Parameterless Constructor
public ScriptUndefinedException() {}
// Constructor that accepts a message
public ScriptUndefinedException(String message)
{
super(message);
}
}
Which gives me the exception:
jenkins-utilities/src/test/groovy/UtilFactoryTest.groovy: 7:
unable to resolve class org.company.UtilFactory
# line 7, column 1.
import org.company.UtilFactory
This may be more of a Gradle issue than a JenkinsShared Library. I've just spent a good portion of my day trying to figure out exactly what I'm doing wrong to no avail.
I would really appreciate any help to guide me in the right direction.
This library may be helpful getting your shared libraries to work in the unit test https://github.com/stchar/pipeline-sharedlib-testharness

New assignment to collection-type class field absent from flow program with Rascal, unlike to local variables

Consider the following Java code:
import java.util.LinkedList;
import java.util.List;
class Library {
List<String> loans = new LinkedList<>();
public List<String> searchUser(String name) {
List<String> usersFound = new LinkedList<>();
return loans;
}
}
and the following Rascal module:
module Mwe
import lang::java::flow::JavaToObjectFlow;
import lang::java::jdt::m3::AST;
import IO;
void m() {
ast = createAstFromEclipseFile(|project://test/src/test.java|, true);
fp = createOFG({ast});
print(fp);
}
The resulting flow program will be:
flowProgram({
attribute(|java+field:///Library/loans|),
method(|java+method:///Library/searchUser(java.lang.String)|,[|java+parameter:///Library/searchUser(java.lang.String)/scope(name)/scope(0)/name|]),
constructor(|java+constructor:///Library/Library()|,[])
},{
assign(|java+method:///Library/searchUser(java.lang.String)/return|,|id:///|,|java+field:///Library/loans|),
newAssign(|java+variable:///Library/searchUser(java.lang.String)/usersFound|,|java+class:///java/util/LinkedList|,|java+constructor:///java/util/LinkedList/LinkedList()|,[])
})
So, there is a new assignment of LinkedList to usersFound, but nothing comparable for loans. Why would that happen? Is that the intended behaviour?
Just checked the implementation, the field initializers are not included in the getStatements function (see lang::java::flow::JavaToObjectFlow on line 169). Similarly the static initializers of a class are ignored.
The best way forward would be to either report it as a bug, or fix it and turn it into a pull-request. (pull request is the quickest way to getting it fixed on unstable)
As a possible, yet work intensive workaround you rewrite the AST to put the field initializers inside all existing constructors (or add a constructor if there is none).

Struts2 NotSerializableException occurs with ExecuteAndWaitInterceptor

We are running Struts 2.5.14.1 and working on externalizing Tomcat session state. This requires Serializable sessions. However, our Action with the ExecuteAndWait interceptor fails. Since our original code was quite complex I wrote a simpler one below which demonstrates the exact same behavior.
The simple action is shown here:
package com.sentrylink.web.actions;
import java.util.concurrent.TimeUnit;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.InterceptorRefs;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import com.opensymphony.xwork2.ActionSupport;
#SuppressWarnings("serial")
#Results({
#Result(name="wait", location="/"),
#Result(name=ActionSupport.SUCCESS, location="/WEB-INF/content/messagePage.jsp"),
})
#InterceptorRefs({
#InterceptorRef("webStack"),
#InterceptorRef("execAndWait")
})
public class TestExecuteAndWait extends ActionSupport {
public String execute() throws Exception {
TimeUnit.SECONDS.sleep(10);
return SUCCESS;
}
}
Running this gives
WARNING: Cannot serialize session attribute __execWaittest-execute-and-wait for session 74CDB9F8D00BBC697030AFC6978E94F6
java.io.NotSerializableException: com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector
It appears that Struts is pulling in an unwanted item for serialization. It may be related to the bug described here, although the fix put in for that bug appears to be present in 2.5.14.1 (not surprisingly, since that fix was in 2013).
I suspect this is a bug in the framework, but before I go ahead and file a report, and figure out a workaround for myself, I thought I would see if anyone had a solution or had ever gotten ExecuteAndWait to work with serialized sessions.

access configuration/property files from src/groovy

I have a file under src/groovy and I have some properties that are in my Config.groovy and in external property file too. Normally if one want access properties its possible to use grailsApplication .configuration.property.name expression. I want to be able to access all those properties from this file that is under src/groovy directory. What I've tried so far
import grails.util.Holders
class ForkedTomcatCustomizer {
def application
void customize(Tomcat tomcat) {
println Holders.grailsApplication.config.property.name
}
}
gave me NPE saying that grailsAppliction is null
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class ForkedTomcatCustomizer {
def application
void customize(Tomcat tomcat) {
def ctx = SCH.servletContext.getAttribute(GA.APPLICATION_CONTEXT)
def grailsAppliction = ctx.grailsApplication.getObject()
println grailsAppliction.config.property.name
}
}
the same - NPE because grailsAppliction is null
Is it possible to handle this situation somehow? Thank you!
Use the below and see if it works
println Holders.config.property.name
You don't need grailsApplication when using Holders.
The examples below are probably a little more complex than what you need, but they show how to get a configuration property at build time. I use them to merge two configuration files, but you might not need to do that.
This method returns a config property when called here at the CompileEnd event.
You could define a similar method in your app's _Events.groovy file that calls your own configuration holder class.
import org.codehaus.groovy.grails.commons.ConfigurationHolder;
class KeyAndSecret{
public static String consumerKey = ConfigurationHolder.config.consumerKey;
public static String consumerSecret = ConfigurationHolder.config.consumerSecret;
}
Try like this

Depedency inject request parameter with CDI and JSF2

When using CDI and JSF2 How can a HTTP request parameter be injected into a bean?
HINT: before reading any further have a look at http://showcase.omnifaces.org/cdi/Param.
Do it yourself is probably obsolete seeing how omnifaces is a de facto standard today. I would probably not have written this if omnifaces had this at the time
CDI does not solve specialized problems like injecting a request parameter. That's supposed to be solved by extensions.
This is already provided by solder. http://docs.jboss.org/seam/3/solder/latest/reference/en-US/html/injectablerefs.html
It will probably be included in Deltaspike 0.4-incubating or similar as well.
That said the code required is rather simple to implement yourself. Example below:
Annotation to use for the injection point (For example private String myParam;)
import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER })
public #interface RequestParam {
#Nonbinding
public String value() default "";
}
Now we have the annotation but we can't just ask the container to dependency inject a #RequestParam - we obviously need an implementation.
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
public class RequestParamProducer implements Serializable {
private static final long serialVersionUID = -4260202951977249652L;
#Inject
FacesContext facesContext;
// Producer for #RequestParam
#Produces
#RequestParam
String getRequestParameter(InjectionPoint ip) {
String name = ip.getAnnotated().getAnnotation(RequestParam.class)
.value();
if ("".equals(name))
name = ip.getMember().getName();
return facesContext.getExternalContext().getRequestParameterMap()
.get(name);
}
}
So how does it work? Well quite simply it first checks if you did specify what parameter you wanted as in #Requestparam("longAndTerribleFieldNameBestToSpecify");
If you didn't it will use the fieldName. So if you annoted a setter called setMyInstance it will look for a parameter called setMyInstance.
The normal use case would be to have a String variable that is named exactly like the parameter you want.
Note that we inject FacesContext, that must also be produced. A FacesContext producer could look like this:
class FacesContextProducer {
#Produces #RequestScoped FacesContext getFacesContext() {
return FacesContext.getCurrentInstance();
}
}
End usage:
#Inject
#RequestParam
private String session_secret;
Note that this will not work for Servlet or similar as it requires access to FacesContext. In those cases one need to wrap the injection with for example a bean that is #RequesScoped. You inject that bean instead.

Resources