Force #GrailsCompileStatic check request as AbstractMultipartHttpServletRequest - grails

I'm trying to apply #GrailsCompileStatic to controller that has an action that retrieves MultipartFiles from request:
request.getFile('foo')
But get the following:
[Static type checking] - Cannot find matching method
javax.servlet.http.HttpServletRequest#getFile(java.lang.String)
Is there any chance to force compiler to verify request against AbstractMultipartHttpServletRequest (that has the getFile(java.lang.String) method) instead of HttpServletRequest?
UPD
This solution works:
MultipartFile multipartFile = ((StandardMultipartHttpServletRequest) request).getFile('myFile')
But has some strange behaviour when trying to test it:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot
cast object
'org.grails.plugins.testing.GrailsMockHttpServletRequest#2bcf856f'
with class 'org.grails.plugins.testing.GrailsMockHttpServletRequest'
to class
'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest'

http://docs.grails.org/2.2.1/api/org/codehaus/groovy/grails/plugins/testing/GrailsMockHttpServletRequest.html
and
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.html
both implements an interface
org.springframework.web.multipart.MultipartHttpServletRequest
so just use this
import org.springframework.web.multipart.MultipartHttpServletRequest
...
MultipartFile multipartFile = ((MultipartHttpServletRequest) request).getFile('myFile')

Related

Jenkins | Use method from an imported java class in a groovy script

I want to be able to use a method from a Jenkins plugin via its java class
Just to point out I'm not a developer or a groovy/java expert - happy to learn!
The java class that my method is part of is com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator
From this I would like to use the method getRepoOwner()
What I've done is set my import and defined a new call to the class:
import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator
def bbSCMNav = new BitbucketSCMNavigator()
When I run this I get the error below:
org.codehaus.groovy.runtime.metaclass.MethodSelectionException: Could not find which method <init>() to invoke from this list:
public com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator#<init>(java.lang.String)
public com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMNavigator#<init>(java.lang.String, java.lang.String, java.lang.String)
I've searched for the error above Could not find which method <init>() to invoke from this list
And I came across this ticket Could not find which method <init>() to invoke from this list on newInstance in groovy closure
Can't say that I entirerly understand the reply if it's helpful to me or not as I say I'm not a developer and groovy and java are relatively new to me but happy to understand if anyone can point me in the right direction with this
The goal of this exercise is to use the method during the run-time of a build to get the output of getRepoOwner() and use that in a variable to construct a URI
This question also seems similar to mine - Calling internal methods of Jenkins plugin (thinBackup)
But I'm not using maven or a pom.xml here
Cheers
Quick Answer
This error Could not find which method < init >() is related to a missing constructor.
Almost all internal jenkins class are ready to use in groovy.
In your case, BitbucketSCMNavigator does not have a default constructor. It have a constructor with one String argument. Check this line
Explanation
I could replicate your error with another internal class org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory:
node {
stage('internal') {
org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory obj =
new org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory();
}
}
hudson.remoting.ProxyException: org.codehaus.groovy.runtime.metaclass.MethodSelectionException: Could not find which method <init>() to invoke from this list:
private org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory#<init>(org.jenkinsci.plugins.workflow.cps.CpsFlowExecution, boolean, java.lang.ClassLoader, java.util.List)
But, reviewing this class CpsFlowExecution I could see that CpsGroovyShellFactory does not have a default constructor. It have a constructor with one argument : CpsGroovyShellFactory(this)
So, If I instance the constructor with one argument, no errors appear.
node {
stage('internal') {
org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory obj =
new org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory(null);
}
}

How to call a JavaScript function named `call` from dart

Is there any way to call a JavaScript function named call() (in a nested object) from Dart or do I have to wait for Dart 2.0 from which the special handling of call() might get removed?
I have a JS Proxy like:
#JS()
class SomethingFancy {
external String call();
}
But as call() can be used to turn an object into a function, it makes it impossible to access the function of the JS object.
If I could, I would change the name of the method in Dart, but that's not supported by package:js:
/// By default the dart name is used. It is not valid to specify a custom
/// [name] for class instance members.
The error I get is:
Uncaught Error: NoSuchMethodError: method not found: 'call$0' (J.getSomethingFancy$1$x(...).call$0 is not a function)
If the function didn't exist, the error would look like this:
Uncaught Error: NoSuchMethodError: method not found: 'callMe' (receiver.callMe is not a function)
Other functions on the same object work just fine.
You can prefix call with JS$:
#JS()
class SomethingFancy {
external String JS$call();
}
JS$ can be used as prefix to allow to access to JS names that conflicts with dart keywords.

Mock CommonsMultipartFile in Grails integration test case

I have a service method which accepts CommonsMultipartFile and uploads it to server
class ExampleService() {
def saveFile(CommonsMultipartFile file) {
// some validation code for file
}
}
tried using both MockMultipartHttpServletRequest and GrailsMockMultipartFile.
In case of MockMultipartHttpServletRequest getting error as:
| org.codehaus.groovy.runtime.typehandling.GroovyCastException:
Cannot cast object 'org.springframework.mock.web.MockMultipartFile#2f39360'
with class 'org.springframework.mock.web.MockMultipartFile' to
class 'org.springframework.web.multipart.commons.CommonsMultipartFile'
Same goes with GrailsMockMultipartFile getting error as:
| org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot
cast object 'org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile#1022f0bd'
with class 'org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile' to
class 'org.springframework.web.multipart.commons.CommonsMultipartFile'
referred this stack overflow question.
How should I mock CommonsMultipartFile and pass it as argument inside my test case ?
Solution
I found solution please check my answer
After going through different stack overflow links and CommonsMultipartFile JDK I come up with this solution
Please let me know if I am using wrong approach #burtbeckwith
File getTestFile(String fileName = "") {
//Code which create file instance
}
// Inside my test case I have created CommonsMultipartFile test file and used it.
DiskFileItemFactory factory = new DiskFileItemFactory()
FileItem fileItem = factory.createItem( "file", "multipart/form-data", false, "logo.png" )
IOUtils.copy(new FileInputStream(getTestFile()), fileItem.getOutputStream())
CommonsMultipartFile testFile = new CommonsMultipartFile(fileItem)
If you change the saveFile(CommonsMultipartFile) method to accept an instance of the interface MultipartFile rather than the specific implementation it will be easier to mock and you should lose no functionality.
saveFile(MultipartFile)

Struts2 annotation with parameter when using json plugin

Simply I want to evaluate a property of my action and use it's value within an annotation.
The following is exactly where I want to use it.
I want to define a excludeProperties parameter at run time.
Consider the following annotation which currently works on the action:
#Result(name = "success", type = "json", params = {"root", "model", "excludeProperties", "myCollection"})
There the actions model has a myCollection collection which I do not want serialized.
However I would like to create an exclusion String (a string will do for now).
If I create a getter setter for exclusion, I would expect the following annotation to work (which does not):
#Result(name = "success", type = "json", params = {"root", "model", "excludeProperties", "${exclusion}"})
Any ideas?
I have created actions similar to this answer which shows resolving a parameter within an annotation. I am using the named variable pattern matcher to extract values from the namespace... but I just can't seem to set this parameter no matter what I do.
Part of the issue was that I was working with entity objects and serializing collections was an issue. With your own custom JSON result type you can do what ever you want. Since created getter setter for jsonModel, I just constructed what I needed there. I don't need to worry about lazy initialization errors because you need to explicitly include collections with flexjson so if you just want the primitives (which I did) then flexjson is perfect.
This very simple result type using flexjson which worked for my needs:
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.util.ValueStack;
import flexjson.JSONSerializer;
import java.io.PrintWriter;
import org.apache.struts2.ServletActionContext;
public class Kjson implements Result {
#Override
public void execute(ActionInvocation invocation) throws Exception {
ServletActionContext.getResponse().setContentType("text/plain");
PrintWriter responseStream = ServletActionContext.getResponse().getWriter();
ValueStack valueStack = invocation.getStack();
Object jsonModel = valueStack.findValue("jsonModel");
//create json and put it into response stream
responseStream.println(new JSONSerializer().exclude("class").serialize(jsonModel));
}
}

How to do safe inserts using GORM for Mongo's low-level API?

I am trying to do a safe insert using GORM for Mongo's low-level API.
I have reproduced the problem in a clean Grails project like follows:
Create a new Grails project
Uninstall the Hibernate plugin
Install the GORM for Mongo plugin
Create a controller with the following action
import com.mongodb.*
class TestController {
def mongo
def index = {
def database = mongo.getDB("ExampleDatabase")
def collection = database.getCollection("ExampleCollection")
def document = new BasicDBObject();
document.put("key", "value")
collection.insert(document, WriteConcern.SAFE)
render ""
}
}
When firing the action, the following exception is thrown:
2011-07-27 12:53:03,161 [http-8080-1] ERROR errors.GrailsExceptionResolver - Exception occurred when processing request: [GET] /WriteConcern.SAFE-test/test/index
Stacktrace follows:
groovy.lang.MissingPropertyException: No such property: value for class: com.mongodb.WriteConcern
at com.gmongo.internal.Patcher$__converAllCharSeqToString_closure2.doCall(Patcher.groovy:81)
at com.gmongo.internal.Patcher._converAllCharSeqToString(Patcher.groovy:80)
at com.gmongo.internal.Patcher$_converAllCharSeqToString.callStatic(Unknown Source)
at com.gmongo.internal.Patcher$_converAllCharSeqToString.callStatic(Unknown Source)
at com.gmongo.internal.Patcher._convert(Patcher.groovy:69)
at com.gmongo.internal.Patcher$_convert.callStatic(Unknown Source)
at com.gmongo.internal.Patcher$__patchInternal_closure1.doCall(Patcher.groovy:31)
at writeconcern.safe.test.TestController$_closure1.doCall(TestController.groovy:17)
at writeconcern.safe.test.TestController$_closure1.doCall(TestController.groovy)
at java.lang.Thread.run(Thread.java:680)
If I change the action to use the Mongo Java API as follows:
def index = {
def database = new Mongo().getDB("ExampleDatabase")
def collection = database.getCollection("ExampleCollection")
def document = new BasicDBObject();
document.put("key", "value")
collection.insert(document, WriteConcern.SAFE)
render ""
}
Now it works and the document is persisted to the Mongo database as expected.
My question is this: Is this a bug with the GMongo wrapper, or then how should safe writes be done using the low level API?
This appears due to the GMongo library and how it patches the DBCollection object to handle passing of Map objects to the insert method and converts them. It assumes that all of the arguments of the insert method are Map objects and will then try to get the value property from the Map.Entry.
Looking at the source of Patcher.groovy from GMongo library you'll see the function _convert() that attempts to do this. It looks like a fork of the Github project with type check on the argument (either to see if it's a WriteConcern or to check if it's actually a Map before passing to the _converAllCharSeqToString) is necessary.
EDIT:
I created a pull request on Github for the appropriate code change, but as with all things Groovy, patching the class can also help. You can "patch" the WriteConcern class in your BootStrap.groovy to have a getValue method and that will allow you to pass the parameter in:
def init = { servletContext ->
com.mongodb.WriteConcern.metaClass.getValue = { null }
}

Resources